, SoulboundData> implements InternalStat, ItemRestriction {
public Soulbound() {
super("SOULBOUND", Material.ENDER_EYE, "灵魂绑定", new String[0], new String[0]);
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SoulboundLevel.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SoulboundLevel.java
index 7da13a76..63c9644c 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SoulboundLevel.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SoulboundLevel.java
@@ -3,15 +3,14 @@
import io.lumine.mythic.lib.api.item.ItemTag;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.api.util.NumericStatFormula;
+import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
-/**
- * Soulbound level for consumables.
- */
+@HasCategory(cat = "soulbound")
public class SoulboundLevel extends DoubleStat {
public SoulboundLevel() {
super("SOULBOUND_LEVEL", Material.ENDER_EYE, "灵魂绑定等级", new String[]{"灵魂绑定等级决定了玩家在尝试使", "用灵魂绑定物品时会受到多少伤害", "\n它还决定了打破绑定的难度."}, new String[]{"consumable"});
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/StepHeight.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/StepHeight.java
index dcbedb96..38f82bfe 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/StepHeight.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/StepHeight.java
@@ -1,13 +1,17 @@
package net.Indyuce.mmoitems.stat;
+import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
-import net.Indyuce.mmoitems.util.VersionDependant;
+import net.Indyuce.mmoitems.stat.annotation.VersionDependant;
import org.bukkit.Material;
+@HasCategory(cat = "vanilla_attribute")
@VersionDependant(version = {1, 20, 5})
public class StepHeight extends DoubleStat {
public StepHeight() {
- super("STEP_HEIGHT", Material.GOLDEN_BOOTS,
- "坡度", new String[]{"行走或冲刺时,不需要跳跃就可以越过","的额外方块数。默认值是0.6,即仅高于一个半砖。"});
+ super("STEP_HEIGHT",
+ Material.STONE_SLAB,
+ "Step Height",
+ "决定生物无需跳跃即可越过的最大方块高度。默认值为0.6,合法范围是0到10。");
}
}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SubmergedMiningSpeed.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SubmergedMiningSpeed.java
new file mode 100644
index 00000000..d7b8fdb8
--- /dev/null
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SubmergedMiningSpeed.java
@@ -0,0 +1,22 @@
+package net.Indyuce.mmoitems.stat;
+
+import net.Indyuce.mmoitems.stat.annotation.HasCategory;
+import net.Indyuce.mmoitems.stat.annotation.VersionDependant;
+import net.Indyuce.mmoitems.stat.type.DoubleStat;
+import org.bukkit.Material;
+
+@HasCategory(cat = "vanilla_attribute")
+@VersionDependant(version = {1, 21})
+public class SubmergedMiningSpeed extends DoubleStat {
+ public SubmergedMiningSpeed() {
+ super("SUBMERGED_MINING_SPEED",
+ Material.WATER_BUCKET,
+ "液体中挖掘速度",
+ "被液体淹没时的挖掘速度系数。系数为1表示淹没时的挖掘速度与在陆地上一样快,系数为0表示淹没时无法挖掘。请注意,这仅代表淹没因素,其他因素(如未接触地面)也会影响。默认值为0.2,最小值为0,最大值为20。");
+ }
+
+ @Override
+ public double multiplyWhenDisplaying() {
+ return 100;
+ }
+}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SuccessRate.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SuccessRate.java
index f08b410d..8786c7f3 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SuccessRate.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SuccessRate.java
@@ -7,7 +7,7 @@
public class SuccessRate extends DoubleStat implements GemStoneStat {
- /*
+ /**
* in a different class because Success Rate is meant to be a proper stat
*/
public SuccessRate() {
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SweepingDamageRatio.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SweepingDamageRatio.java
new file mode 100644
index 00000000..c127dded
--- /dev/null
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/SweepingDamageRatio.java
@@ -0,0 +1,22 @@
+package net.Indyuce.mmoitems.stat;
+
+import net.Indyuce.mmoitems.stat.annotation.HasCategory;
+import net.Indyuce.mmoitems.stat.annotation.VersionDependant;
+import net.Indyuce.mmoitems.stat.type.DoubleStat;
+import org.bukkit.Material;
+
+@HasCategory(cat = "vanilla_attribute")
+@VersionDependant(version = {1, 21})
+public class SweepingDamageRatio extends DoubleStat {
+ public SweepingDamageRatio() {
+ super("SWEEPING_DAMAGE_RATIO",
+ Material.LIGHT_GRAY_DYE,
+ "横扫伤害比例",
+ "在横扫攻击中,基础攻击伤害有多少会传递到次要目标。这是对横扫攻击基础伤害1的额外加成。值为0表示没有基础攻击伤害传递(横扫伤害为1),值为1表示所有基础攻击伤害都传递。默认值和最小值为0,最大值为1。");
+ }
+
+ @Override
+ public double multiplyWhenDisplaying() {
+ return 100;
+ }
+}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/TrimMaterialStat.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/TrimMaterialStat.java
index f8ab9696..d45f0be0 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/TrimMaterialStat.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/TrimMaterialStat.java
@@ -6,7 +6,7 @@
import net.Indyuce.mmoitems.stat.type.ChooseStat;
import net.Indyuce.mmoitems.stat.type.GemStoneStat;
import net.Indyuce.mmoitems.util.StatChoice;
-import net.Indyuce.mmoitems.util.VersionDependant;
+import net.Indyuce.mmoitems.stat.annotation.VersionDependant;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
@@ -29,7 +29,13 @@ public TrimMaterialStat() {
if (!isEnabled()) return;
for (TrimMaterial mat : Registry.TRIM_MATERIAL)
- addChoices(new StatChoice(mat.getKey().getKey()));
+ addChoices(new StatChoice(mat.getKey().toString()));
+ }
+
+ @Nullable
+ @Override
+ public StatChoice getChoice(String id) {
+ return super.getChoice(TrimPatternStat.fixNamespacedKey(id).toString());
}
@Override
@@ -49,6 +55,6 @@ public void whenLoaded(@NotNull ReadMMOItem mmoitem) {
if (!(mmoitem.getNBT().getItem().getItemMeta() instanceof ArmorMeta)) return;
final ArmorMeta meta = (ArmorMeta) mmoitem.getNBT().getItem().getItemMeta();
if (!meta.hasTrim()) return;
- mmoitem.setData(this, new StringData(meta.getTrim().getMaterial().getKey().getKey()));
+ mmoitem.setData(this, new StringData(meta.getTrim().getMaterial().getKey().toString()));
}
}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/TrimPatternStat.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/TrimPatternStat.java
index 8fc0e095..02cfb6a0 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/TrimPatternStat.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/TrimPatternStat.java
@@ -6,7 +6,7 @@
import net.Indyuce.mmoitems.stat.type.ChooseStat;
import net.Indyuce.mmoitems.stat.type.GemStoneStat;
import net.Indyuce.mmoitems.util.StatChoice;
-import net.Indyuce.mmoitems.util.VersionDependant;
+import net.Indyuce.mmoitems.stat.annotation.VersionDependant;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
@@ -29,14 +29,25 @@ public TrimPatternStat() {
if (!isEnabled()) return;
for (TrimPattern mat : Registry.TRIM_PATTERN)
- addChoices(new StatChoice(mat.getKey().getKey()));
+ addChoices(new StatChoice(mat.getKey().toString()));
+ }
+
+ public static NamespacedKey fixNamespacedKey(String str) {
+ if (!str.contains(":")) return NamespacedKey.minecraft(str);
+ return NamespacedKey.fromString(str);
+ }
+
+ @Nullable
+ @Override
+ public StatChoice getChoice(String id) {
+ return super.getChoice(fixNamespacedKey(id).toString());
}
@Override
public void whenApplied(@NotNull ItemStackBuilder item, @NotNull StringData data) {
if (!(item.getMeta() instanceof ArmorMeta)) return;
- @Nullable TrimPattern pattern = Registry.TRIM_PATTERN.get(NamespacedKey.minecraft(data.toString().toLowerCase()));
+ @Nullable TrimPattern pattern = Registry.TRIM_PATTERN.get(fixNamespacedKey(data.toString()));
if (pattern == null) return;
final ArmorMeta meta = (ArmorMeta) item.getMeta();
@@ -49,6 +60,6 @@ public void whenLoaded(@NotNull ReadMMOItem mmoitem) {
if (!(mmoitem.getNBT().getItem().getItemMeta() instanceof ArmorMeta)) return;
final ArmorMeta meta = (ArmorMeta) mmoitem.getNBT().getItem().getItemMeta();
if (!meta.hasTrim()) return;
- mmoitem.setData(this, new StringData(meta.getTrim().getPattern().getKey().getKey()));
+ mmoitem.setData(this, new StringData(meta.getTrim().getPattern().getKey().toString()));
}
}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/WaterMovementEfficiency.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/WaterMovementEfficiency.java
new file mode 100644
index 00000000..73cb928d
--- /dev/null
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/WaterMovementEfficiency.java
@@ -0,0 +1,22 @@
+package net.Indyuce.mmoitems.stat;
+
+import net.Indyuce.mmoitems.stat.annotation.HasCategory;
+import net.Indyuce.mmoitems.stat.annotation.VersionDependant;
+import net.Indyuce.mmoitems.stat.type.DoubleStat;
+import org.bukkit.Material;
+
+@HasCategory(cat = "vanilla_attribute")
+@VersionDependant(version = {1, 21})
+public class WaterMovementEfficiency extends DoubleStat {
+ public WaterMovementEfficiency() {
+ super("WATER_MOVEMENT_EFFICIENCY",
+ Material.WATER_BUCKET,
+ "液体中移动效率",
+ "被液体淹没时的移动速度系数。系数越高,越能减轻水下移动的惩罚。请注意,这仅代表淹没因素,其他因素(如未接触地面)也会影响。默认值和最小值为0,最大值为1。");
+ }
+
+ @Override
+ public double multiplyWhenDisplaying() {
+ return 100;
+ }
+}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/annotation/HasCategory.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/annotation/HasCategory.java
new file mode 100644
index 00000000..e29052b2
--- /dev/null
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/annotation/HasCategory.java
@@ -0,0 +1,13 @@
+package net.Indyuce.mmoitems.stat.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Can be used to give categories to stats
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HasCategory {
+
+ public String cat();
+}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/annotation/VersionDependant.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/annotation/VersionDependant.java
new file mode 100644
index 00000000..a77f62b5
--- /dev/null
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/annotation/VersionDependant.java
@@ -0,0 +1,20 @@
+package net.Indyuce.mmoitems.stat.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Version string is MAJOR.MINOR.PATCH
+ *
+ * This annotation indicates the LOWEST VERSION at which
+ * the given feature is available. Usually, it's the
+ * version where some non-backwards compatible feature was
+ * implemented into Minecraft or Spigot.
+ *
+ * @author Jules
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface VersionDependant {
+
+ public int[] version();
+}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/category/StatCategory.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/category/StatCategory.java
new file mode 100644
index 00000000..8ac16fc9
--- /dev/null
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/category/StatCategory.java
@@ -0,0 +1,41 @@
+package net.Indyuce.mmoitems.stat.category;
+
+import org.jetbrains.annotations.NotNull;
+
+public class StatCategory {
+ private final String id, name, loreTag;
+
+ /**
+ * @param id Internal identifier of stat category. Must be unique
+ * @param name Name used to identify the category in the item browser
+ * @param loreTag Lore tag added to stats with the given category
+ */
+ public StatCategory(String id, String name, String loreTag) {
+ this.id = id;
+ this.name = name;
+ this.loreTag = loreTag;
+ }
+
+ @NotNull
+ public String getId() {
+ return id;
+ }
+
+ @NotNull
+ public String getName() {
+ return name;
+ }
+
+ @NotNull
+ public String getLoreTag() {
+ return loreTag;
+ }
+
+ public static final StatCategory
+ TEMPLATE_OPTION = new StatCategory("TEMPLATE_OPTION", "Template Option, Misc", "Template Option"),
+ SOULBOUND = new StatCategory("SOULBOUND", "Soulbound", "Soulbound"),
+ ELEMENTAL = new StatCategory("ELEMENTAL", "Elements", "Elements"),
+ VANILLA_ATTRIBUTE = new StatCategory("VANILLA_ATTRIBUTE", "Vanilla Attributes", "Vanilla Attribute"),
+ REQUIREMENT = new StatCategory("REQUIREMENT", "Item Requirements", "Item Requirement"),
+ USE_COST = new StatCategory("USE_COST", "Item Costs", "Use Cost");
+}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/ChooseStat.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/ChooseStat.java
index 77e06cb4..90a56c53 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/ChooseStat.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/ChooseStat.java
@@ -1,11 +1,10 @@
package net.Indyuce.mmoitems.stat.type;
import io.lumine.mythic.lib.api.util.AltChar;
-import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.gui.edition.EditionInventory;
import net.Indyuce.mmoitems.stat.data.StringData;
-import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
+import net.Indyuce.mmoitems.util.MMOUtils;
import net.Indyuce.mmoitems.util.StatChoice;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
@@ -15,7 +14,10 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
/**
* Choose Stats present a list of options from which the user may choose one.
@@ -52,7 +54,7 @@ public StatChoice getChoice(String id) {
@Override
public void whenClicked(@NotNull EditionInventory inv, @NotNull InventoryClickEvent event) {
- Validate.isTrue(choices.size() > 0, "基于选择的统计数据无效 '" + getId() + ": 没有可供选择的选项");
+ Validate.isTrue(!choices.isEmpty(), "基于选择的统计数据无效 '" + getId() + ": 没有可供选择的选项");
// If removing, reset to default
if (event.getAction() == InventoryAction.PICKUP_HALF) {
@@ -67,18 +69,14 @@ public void whenClicked(@NotNull EditionInventory inv, @NotNull InventoryClickEv
} else {
// Get current
- StatChoice current = getChoice(inv.getEditedSection().getString(getPath()));
-
- // Included?
- int currentIndex = current != null ? Math.max(0, choices.indexOf(current)) : 0;
+ String found = inv.getEditedSection().getString(getPath());
+ int currentIndex = found == null ? -1 : choices.indexOf(getChoice(found));
// Increase and Cap
if (++currentIndex >= choices.size()) currentIndex = 0;
- // Get
- current = choices.get(currentIndex);
-
// Edits into persistent files
+ StatChoice current = choices.get(currentIndex);
inv.getEditedSection().set(getPath(), current.getId());
inv.registerTemplateEdition();
@@ -89,14 +87,14 @@ public void whenClicked(@NotNull EditionInventory inv, @NotNull InventoryClickEv
@Override
public void whenDisplayed(List lore, Optional statData) {
- Validate.isTrue(choices.size() > 0, "基于选择的统计数据无效 '" + getId() + ": 没有可供选择的选项");
+ Validate.isTrue(!choices.isEmpty(), "基于选择的统计数据无效 '" + getId() + ": 没有可供选择的选项");
// To display current choosing, gets the very first element
- StatChoice def = statData.isPresent() ? getChoice(statData.get().toString()) : choices.get(0);
- lore.add(ChatColor.GRAY + "当前值: " + (statData.isPresent() ? ChatColor.GREEN : ChatColor.RED) + def);
+ @Nullable StatChoice found = statData.isPresent() ? getChoice(statData.get().toString()) : null;
+ lore.add(ChatColor.GRAY + "当前值: " + (found != null ? ChatColor.GREEN + found.getId() : ChatColor.RED + "None"));
// Display Definition
- for (String definition : SilentNumbers.chop(def.getHint(), 50, ""))
+ if (found != null && found.getHint() != null) for (String definition : MMOUtils.trimString(LORE_LINE_WIDTH, found.getHint()))
lore.add(ChatColor.GRAY + " " + definition);
lore.add("");
@@ -105,7 +103,7 @@ public void whenDisplayed(List lore, Optional statData) {
for (StatChoice existing : choices) {
// Is it the one?
- String pick = existing.equals(def) ? ChatColor.RED.toString() + ChatColor.BOLD : ChatColor.GOLD.toString();
+ String pick = existing.equals(found) ? ChatColor.RED.toString() + ChatColor.BOLD : ChatColor.GOLD.toString();
lore.add(pick + " " + AltChar.smallListDash + " " + ChatColor.GRAY + existing.getId());
}
}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/DoubleStat.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/DoubleStat.java
index 242580c1..1abab38e 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/DoubleStat.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/DoubleStat.java
@@ -20,6 +20,7 @@
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.data.type.UpgradeInfo;
+import net.Indyuce.mmoitems.util.MMOUtils;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@@ -44,6 +45,10 @@ public DoubleStat(String id, Material mat, String name, String[] lore) {
this(id, mat, name, lore, new String[]{"!miscellaneous", "!block", "all"}, true);
}
+ public DoubleStat(String id, Material mat, String name, String lore) {
+ this(id, mat, name, MMOUtils.trimString(LORE_LINE_WIDTH, lore), new String[]{"!miscellaneous", "!block", "all"}, true);
+ }
+
public DoubleStat(String id, Material mat, String name, String[] lore, String[] types, Material... materials) {
this(id, mat, name, lore, types, true, materials);
}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/FictiveNumericStat.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/FakeElementalStat.java
similarity index 90%
rename from MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/FictiveNumericStat.java
rename to MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/FakeElementalStat.java
index 5330c7f7..fa89d879 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/FictiveNumericStat.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/FakeElementalStat.java
@@ -6,6 +6,7 @@
import net.Indyuce.mmoitems.api.item.mmoitem.ReadMMOItem;
import net.Indyuce.mmoitems.api.util.NumericStatFormula;
import net.Indyuce.mmoitems.gui.edition.EditionInventory;
+import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.util.ElementStatType;
import org.bukkit.Material;
@@ -26,9 +27,10 @@
*
* @deprecated Definitely not a perfect implementation
*/
+@HasCategory(cat = "elemental")
@Deprecated
-public class FictiveNumericStat extends DoubleStat implements InternalStat {
- public FictiveNumericStat(Element el, ElementStatType type) {
+public class FakeElementalStat extends DoubleStat implements InternalStat {
+ public FakeElementalStat(Element el, ElementStatType type) {
super(type.getConcatenatedTagPath(el), Material.BARRIER, "虚拟统计", new String[0]);
}
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java
index 3c10dd98..ac584cdd 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java
@@ -8,9 +8,10 @@
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.api.item.mmoitem.ReadMMOItem;
import net.Indyuce.mmoitems.gui.edition.EditionInventory;
+import net.Indyuce.mmoitems.stat.category.StatCategory;
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
-import net.Indyuce.mmoitems.util.VersionDependant;
+import net.Indyuce.mmoitems.stat.annotation.VersionDependant;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.event.inventory.InventoryClickEvent;
@@ -30,7 +31,7 @@ public abstract class ItemStat, S extends StatData>
private final List compatibleTypes;
private final List compatibleMaterials;
- @Nullable
+ @NotNull
private String[] aliases = {};
/**
@@ -39,6 +40,10 @@ public abstract class ItemStat, S extends StatData>
*/
private boolean enabled = true;
+ private StatCategory category;
+
+ protected static final int LORE_LINE_WIDTH = 50;
+
/**
* Initializes an item stat
*
@@ -66,6 +71,12 @@ public ItemStat(@NotNull String id, @NotNull Material material, @NotNull String
final VersionDependant implVersion = getClass().getAnnotation(VersionDependant.class);
if (MythicLib.plugin.getVersion().isUnder(implVersion.version())) disable();
}
+
+ // Backwards compatibility
+ if (getClass().isAnnotationPresent(net.Indyuce.mmoitems.util.VersionDependant.class)) {
+ final net.Indyuce.mmoitems.util.VersionDependant implVersion = getClass().getAnnotation(net.Indyuce.mmoitems.util.VersionDependant.class);
+ if (MythicLib.plugin.getVersion().isUnder(implVersion.version())) disable();
+ }
}
/**
@@ -177,6 +188,15 @@ public String getGeneralStatFormat() {
return generalStatFormat;
}
+ @Nullable
+ public StatCategory getCategory() {
+ return category;
+ }
+
+ public void setCategory(@Nullable StatCategory category) {
+ this.category = category;
+ }
+
@NotNull
public String getName() {
return name;
@@ -199,7 +219,7 @@ public String getId() {
*
* Aliases have to follow the UPPER_CASE stat identifier format.
*/
- @Nullable
+ @NotNull
public String[] getAliases() {
return aliases;
}
@@ -302,6 +322,8 @@ public boolean equals(Object o) {
return id.equals(itemStat.id);
}
+
+
@Override
public int hashCode() {
return Objects.hash(id);
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/MMOUtils.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/MMOUtils.java
index 7a2b6c59..bca87c77 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/MMOUtils.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/MMOUtils.java
@@ -40,6 +40,32 @@ public static boolean isColorable(@NotNull Particle particle) {
return particle.getDataType() == Particle.DustOptions.class;
}
+ public static String[] trimString(int charactersPerLine, @NotNull String... inputs) {
+ List list = new ArrayList<>();
+
+ for (String input : inputs) {
+ if (input.length() <= charactersPerLine) {
+ list.add(input);
+ continue;
+ }
+
+ StringBuilder currentLine = new StringBuilder();
+
+ for (String word : input.split(" ")) {
+ if (!currentLine.isEmpty()) currentLine.append(" ");
+ currentLine.append(word);
+ if (currentLine.length() > charactersPerLine || word.endsWith("\n")) {
+ list.add(currentLine.toString()); // Return line
+ currentLine.setLength(0); // Empty current line
+ }
+ }
+
+ // Add last line (sometimes not necessary)
+ if (!currentLine.isEmpty()) list.add(currentLine.toString());
+ }
+
+ return list.toArray(new String[0]);
+ }
@NotNull
public static ItemStack readIcon(@NotNull String stringInput) {
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/StatChoice.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/StatChoice.java
index ab50df5b..44e073c8 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/StatChoice.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/StatChoice.java
@@ -8,7 +8,7 @@ public class StatChoice {
private final String id, hint;
public StatChoice(String id) {
- this(id, "- 无提示 -");
+ this(id, null);
}
public StatChoice(String id, @Nullable String hint) {
diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/VersionDependant.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/VersionDependant.java
index d6065fcc..7067314b 100644
--- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/VersionDependant.java
+++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/util/VersionDependant.java
@@ -4,15 +4,10 @@
import java.lang.annotation.RetentionPolicy;
/**
- * Version string is MAJOR.MINOR.PATCH
- *
- * This annotation indicates the LOWEST VERSION at which
- * the given feature is available. Usually, it's the
- * version where some non-backwards compatible feature was
- * implemented into Minecraft or Spigot.
- *
- * @author Jules
+ * @see net.Indyuce.mmoitems.stat.annotation.VersionDependant
+ * @deprecated Moved to another class
*/
+@Deprecated
@Retention(RetentionPolicy.RUNTIME)
public @interface VersionDependant {
diff --git a/MMOItems-Dist/pom.xml b/MMOItems-Dist/pom.xml
index 1420b45b..85837da8 100644
--- a/MMOItems-Dist/pom.xml
+++ b/MMOItems-Dist/pom.xml
@@ -15,11 +15,11 @@
-
+
io.papermc.paper
paper-api
- 1.20.6-R0.1-SNAPSHOT
+ 1.21.1-R0.1-SNAPSHOT
provided
true
@@ -46,6 +46,13 @@
1.1
provided
true
+
+
+
+ net.md-5
+ bungeecord-chat
+
+
diff --git a/MMOItems-Dist/src/main/resources/default/item/armor.yml b/MMOItems-Dist/src/main/resources/default/item/armor.yml
index ac432f63..0b1a50e0 100644
--- a/MMOItems-Dist/src/main/resources/default/item/armor.yml
+++ b/MMOItems-Dist/src/main/resources/default/item/armor.yml
@@ -164,6 +164,8 @@ DRAGON_BOOTS:
- Magenta
- Black
set: DRAGON
+
+# Spellcaster set
SPELLCASTER_HELMET:
base:
material: LEATHER_HELMET
@@ -300,6 +302,8 @@ SPELLCASTER_BOOTS:
hide-dye: true
dye-color: 125 0 255
set: SPELLCASTER
+
+# Omnielemental set
OMNIELEMENTAL_HELMET:
base:
material: LEATHER_HELMET
@@ -586,6 +590,8 @@ CONTROL_DEVICES:
armor: 7.0
tier: MAGICAL
unbreakable: true
+
+# Undead slayer
UNDEAD_SLAYER_HELMET:
base:
material: NETHERITE_HELMET
@@ -725,6 +731,8 @@ MYTHRIL_CHAINMAIL:
- Blue
required-level: 4.0
tier: UNCOMMON
+
+# Steel set
STEEL_HELMET:
base:
material: IRON_HELMET
@@ -891,6 +899,8 @@ HUGE_MOTHRON_WINGS:
unbreakable: true
movement-speed: -0.03
will-break: false
+
+# Arcane set
ARCANE_HELM:
base:
material: LEATHER_HELMET
@@ -967,6 +977,8 @@ ARCANE_BOOTS:
spread: 0.033
max-spread: 0.1
set: ARCANE
+
+# Gingerbread set
GINGERBREAD_HELM:
base:
material: LEATHER_HELMET
@@ -1129,6 +1141,8 @@ TRAVEL_BOOTS:
max-durability: 100.0
armor: 2.0
fall-damage-reduction: 5.0
+
+# Shadow set
SHADOWVEIL:
base:
material: LEATHER_HELMET
@@ -1219,6 +1233,187 @@ SHADOWBOOTS:
max-health: 8.0
movement-speed: 0.01
dye-color: 0 0 0
+
+# Misc
+HELMET_OF_THE_SEA:
+ base:
+ material: LEATHER_HELMET
+ max-durability: 8000.0
+ attack-damage:
+ base: 6.0
+ scale: 0.1
+ spread: 0.2
+ max-spread: 0.3
+ required-level: 10.0
+ weapon-damage:
+ base: 10.0
+ scale: 0.1
+ spread: 0.2
+ max-spread: 0.25
+ magic-damage:
+ base: 10.0
+ scale: 0.1
+ spread: 0.2
+ max-spread: 0.25
+ physical-damage:
+ base: 15.0
+ scale: 0.1
+ spread: 0.2
+ max-spread: 0.25
+ cooldown-reduction:
+ base: 15.0
+ scale: 0.1
+ spread: 0.2
+ max-spread: 0.25
+ pve-damage:
+ base: 15.0
+ scale: 0.1
+ spread: 0.2
+ max-spread: 0.25
+ tier: RARE
+ dye-color: 120 120 255
+ name: §9Helmet of the Ocean
+ hide-dye: true
+ element:
+ water:
+ defense:
+ base: 25.0
+ scale: 0.0
+ spread: 0.2
+ max-spread: 0.4
+ amphibian: DAMP
+ perm-effects:
+ NIGHT_VISION: 1.0
+ WATER_BREATHING: 1.0
+ lore:
+ - §3Will only work when §9§lUNDERWATER§3.
+ - §3Gives §9Night Vision §3and §9Water Breathing§3.
+MOON_BOOTS:
+ base:
+ material: DIAMOND_BOOTS
+ lore:
+ - §bMoon boots will simulate being on the moon!
+ - §7Gives §3Jump Boost II§7 when worn.
+ - §cWill only work in "the end" biome.
+ max-durability: 2650.0
+ name: §b§lMoon Boots
+ tier: UNIQUE
+ armor-toughness: 1.5
+ armor: 3.0
+ fall-damage-reduction: 75.0
+ perm-effects:
+ JUMP: 2.0
+ required-biomes:
+ - the_end
+CONTROL_DEVICES:
+ base:
+ material: LEATHER_HELMET
+ max-durability: 15000.0
+ name: §d§lControl Devices
+ dye-color: 255 102 204
+ ability: {}
+ set: PSYCHIC
+ perm-effects:
+ DAMAGE_RESISTANCE: 2.0
+ SPEED: 2.0
+ REGENERATION: 2.0
+ FIRE_RESISTANCE: 1.0
+ INCREASE_DAMAGE: 2.0
+ required-class:
+ - Mage
+ lore:
+ - §7To keep your powers in check...
+ armor-toughness: 2.0
+ armor: 7.0
+ tier: MAGICAL
+ unbreakable: true
+DEAD_PHARAOH_HELMET:
+ base:
+ material: PLAYER_HEAD
+ skull-texture:
+ value: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGU1NWRmOTc5YWI3OTc0OWY4YjU1MWI0MjM5YTQ2OWFhNzY5ZDliNDYwNTBhYWJkOWY2ZDFjZWU1M2VkMzYifX19
+ uuid: 852deb36-af4a-412f-ac76-2b06dc123ed2
+ name: '&cDead Pharaoh Helmet'
+ disable-interaction: true
+ item-particles:
+ type: FIREFLIES
+ particle: SMOKE_NORMAL
+ fire-damage-reduction: 30.0
+ armor: 4.0
+ undead-damage: 30.0
+ lore:
+ - '&7This powerful forgotten helmet'
+ - '&7will greatly increase your power'
+ - '&7against undead creatures.'
+ required-level: 9.0
+MOSSY_SKELETON_SKULL:
+ base:
+ material: PLAYER_HEAD
+ skull-texture:
+ value: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWE2MzE0ZWFjMzQ0MTZjZTEwYWIyMmMyZTFjNGRjYjQ3MmEzZmViOThkNGUwNGQzZmJiYjg1YTlhNDcxYjE4In19fQ
+ uuid: f455a085-3f09-43ac-8be1-175204d1a6ad
+ name: '&8Mossy Skeleton Skull'
+ required-level: 6.0
+ armor: 3.5
+ knockback-resistance: 0.1
+ movement-speed: -0.01
+ disable-interaction: true
+SKELETON_CROWN:
+ base:
+ material: PLAYER_HEAD
+ skull-texture:
+ value: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGM3OGQyMTAyZGI3NWYxYjM3NDRhNWU3ZTliYWNjZjg4ZmRhNGNjNDk3OWViYzBhODFiN2Q5ZWI1NzIxYzAifX19
+ uuid: ccb901e7-0919-463d-9bdd-ee9acae8e0e2
+ name: '&eSkeleton Crown'
+ required-level: 9.0
+ armor: 3.0
+ movement-speed: 0.01
+ ability:
+ ability1:
+ type: LIFE_ENDER
+ mode: DAMAGED
+ damage: 3.0
+ cooldown: 9.0
+ lore:
+ - '&7Every 9 seconds, summons a'
+ - '&cdeadly meteor&7 at your attacker,'
+ - '&7dealing &c4&7 damage while briefly'
+ - '&7knocking them away.'
+ disable-interaction: true
+WYVERN_CAP:
+ base:
+ material: GOLDEN_HELMET
+ name: '&fWyvern Cap'
+ required-level: 10.0
+ hide-enchants: false
+ enchants:
+ unbreaking: 9
+ armor: 2.5
+ fall-damage-reduction: 70.0
+ perm-effects:
+ JUMP: 2
+ lore:
+ - '&7Grants permanent jump boost II'
+ crafting:
+ shaped:
+ '1':
+ - TOME.WYVERN_FEATHER TOME.WYVERN_SOUL TOME.WYVERN_FEATHER
+ - TOME.WYVERN_FEATHER AIR TOME.WYVERN_FEATHER
+ - AIR AIR AIR
+ '2':
+ - AIR AIR AIR
+ - TOME.WYVERN_FEATHER TOME.WYVERN_SOUL TOME.WYVERN_FEATHER
+ - TOME.WYVERN_FEATHER AIR TOME.WYVERN_FEATHER
+TRAVEL_BOOTS:
+ base:
+ material: LEATHER_BOOTS
+ name: §fTravel boots
+ movement-speed: 0.005
+ dye-color: 187 118 126
+ will-break: true
+ max-durability: 100.0
+ armor: 2.0
+ fall-damage-reduction: 5.0
GARGOYLE_CHESTPLATE:
base:
material: IRON_CHESTPLATE
@@ -1246,3 +1441,103 @@ SHRINKING_BOOTS:
lore:
- '&7&oMay this item help you get'
- '&7&othrough the narrowest paths...'
+MYTHRIL_CHAINMAIL:
+ base:
+ material: CHAINMAIL_CHESTPLATE
+ name: '&b--] &fMythril Chainmail &b[--'
+ block-power:
+ base: 60.0
+ spread: 0.048
+ max-spread: 0.14
+ block-rating:
+ base: 12.5
+ spread: 0.06
+ max-spread: 0.17
+ armor: 5
+ element:
+ ice:
+ defense: 8.0
+ earth:
+ defense: 6.4
+ gem-sockets:
+ - Red
+ - Blue
+ required-level: 4.0
+ tier: UNCOMMON
+CURSED_WITHER_SKULL:
+ base:
+ material: WITHER_SKELETON_SKULL
+ name: '&7Cursed Wither Skull'
+ required-level: 30.0
+ tier: UNIQUE
+ gem-sockets:
+ - Red
+ - Blue
+ armor: 3.0
+ armor-toughness: 2.0
+ perm-effects:
+ ABSORPTION: 1
+ lore:
+ - '&7Grants a permanent &62'
+ - '&6hearts &7absorption shield.'
+ durability: 1.0
+ element:
+ thunder:
+ defense: 67.4
+ fire:
+ defense: 53.4
+ crafting:
+ shaped:
+ '1':
+ - BONE BONE BONE
+ - BONE MATERIAL.UNIQUE_WEAPON_ESSENCE BONE
+ - BONE BONE BONE
+LARGE_MOTHRON_WINGS:
+ base:
+ material: ELYTRA
+ max-durability: 5.0
+ two-handed: false
+ name: '&eLarge Mothron Wings'
+ tier: RARE
+ gravity: -0.02
+ unbreakable: true
+ movement-speed: -0.03
+ will-break: false
+FIREPROOF_JACKET:
+ base:
+ material: LEATHER_CHESTPLATE
+ burning-time: -0.9
+ name: Fireproof Jacket
+ enchants:
+ unbreaking: 4.0
+ trim-pattern: vex
+ trim-material: redstone
+BEE_WINGS:
+ base:
+ material: ELYTRA
+ name: Bee Wings
+ movement-speed: 0.02
+ fall-damage-multiplier: -0.5
+ jump-strength: 0.2
+ gravity: -0.04
+ safe-fall-distance: 7.0
+SOULWALKER:
+ base:
+ material: GOLDEN_BOOTS
+ name: Soulwalker
+ movement-efficiency: 0.9
+ armor: 3.0
+ step-height: 0.4
+ lore:
+ - '&7Negates soulsand movement impairing.'
+
+DIVING_BOOTS:
+ base:
+ material: GOLDEN_BOOTS
+ name: Diving Boots
+ trim-material: copper
+ trim-pattern: wild
+ water-movement-efficiency: 1.0
+ gravity: 2.0
+ step-height: 0.5
+
diff --git a/MMOItems-Dist/src/main/resources/default/item/dagger.yml b/MMOItems-Dist/src/main/resources/default/item/dagger.yml
index 10208e53..1d755b29 100644
--- a/MMOItems-Dist/src/main/resources/default/item/dagger.yml
+++ b/MMOItems-Dist/src/main/resources/default/item/dagger.yml
@@ -179,8 +179,8 @@ SNEAKY_DAGGER:
lore:
- §7这把匕首十分神秘。
tier: UNCOMMON
- attack-damage: 5.0
- attack-speed: 2.2
+ attack-damage: 11.0
+ attack-speed: 0.9
critical-strike-chance:
base: 9.0
scale: 0.1
@@ -197,4 +197,5 @@ SNEAKY_DAGGER:
type: BACKSTAB
mode: ATTACK
cooldown: 3.0
- extra: 50.0
\ No newline at end of file
+ extra: 50.0
+ sneaking-speed: 2.0
diff --git a/MMOItems-Dist/src/main/resources/default/item/tool.yml b/MMOItems-Dist/src/main/resources/default/item/tool.yml
index d45cb359..64dfec41 100644
--- a/MMOItems-Dist/src/main/resources/default/item/tool.yml
+++ b/MMOItems-Dist/src/main/resources/default/item/tool.yml
@@ -55,7 +55,7 @@ AUTOSMELT_PICKAXE:
- v magma_cream - 1.0..|v netherite_block - 1.0..|v magma_cream - 1.0..
- v AIR 0 1..|v stick - 1.0..|v AIR 0 1..
- v AIR 0 1..|v stick - 1.0..|v AIR 0 1..
-UNBREAKABLE_SHEARS:
+SILK_SHEARS:
base:
material: SHEARS
enchants:
@@ -66,3 +66,12 @@ UNBREAKABLE_SHEARS:
- §7能够采集§9草§7和§2玻璃§7。
tier: UNCOMMON
required-level: 5.0
+
+FAST_PICK:
+ base:
+ material: WOODEN_PICKAXE
+ mining-efficiency: 100.0
+ max-item-damage: 100.0
+ lore:
+ - '&7&oInsanely fast, but won''t loot'
+
diff --git a/MMOItems-Dist/src/main/resources/default/language/lore-format.yml b/MMOItems-Dist/src/main/resources/default/language/lore-format.yml
index 21f3c100..c01866d6 100644
--- a/MMOItems-Dist/src/main/resources/default/language/lore-format.yml
+++ b/MMOItems-Dist/src/main/resources/default/language/lore-format.yml
@@ -92,6 +92,15 @@ lore-format:
- '#safe-fall-distance#'
- '#scale#'
- '#step-height#'
+ - '#burning-time#'
+ - '#explosion-knockback-resistance#'
+ - '#mining-efficiency#'
+ - '#movement-efficiency#'
+ - '#oxygen-bonus#'
+ - '#sneaking-speed#'
+ - '#submerged-mining-speed#'
+ - '#sweeping-damage-ratio#'
+ - '#water-movement-efficiency#'
- '#lute-attack-effect#'
- '#two-handed#'
- '#handworn#'
diff --git a/MMOItems-Dist/src/main/resources/default/language/stats.yml b/MMOItems-Dist/src/main/resources/default/language/stats.yml
index e486ebed..6a079577 100644
--- a/MMOItems-Dist/src/main/resources/default/language/stats.yml
+++ b/MMOItems-Dist/src/main/resources/default/language/stats.yml
@@ -85,15 +85,24 @@ additional-experience-woodcutting: '&7■ 额外伐木经验: &f{value}%'
# 1.20.2+ Attributes
block-break-speed: '&3 &7■ 挖掘速度: &f{value}'
-block-interaction-range: '&3 &7■ 方块交互距离: &f{value}' # Range for interacting with blocks & mining.
-entity-interaction-range: '&3 &7■ 攻击距离: &f{value}'
-fall-damage-multiplier: '&3 &7■ 摔落伤害: &f{value}%'
-gravity: '&3 &7■ 重力: &f{value}%'
-jump-strength: '&3 &7■ 跳跃高度: &f{value}'
-max-absorption: '&3 &7■ 伤害吸收: &f{value}'
-safe-fall-distance: '&3 &7■ 安全摔落距离: &f{value}'
-scale: '&3 &7■ 大小: &f{value}%'
-step-height: '&3 &7■ Smooth Walking: &f{value}' # TODO 不知道怎么翻,先放着
+block-interaction-range: '&3 &7■ 范围: &f{value}' # Range for interacting with blocks & mining.
+entity-interaction-range: '&3 &7■ 战斗范围: &f{value}'
+fall-damage-multiplier: '&3 &7■ 坠落伤害: &f{value}%'
+gravity: '&3 &7■ 重力强度: &f{value}%'
+jump-strength: '&3 &7■ 跳跃强度: &f{value}'
+max-absorption: '&3 &7■ 最大伤害吸收: &f{value}'
+safe-fall-distance: '&3 &7■ 安全坠落距离: &f{value}'
+scale: ' &3 &7■ 大小: &f{value}%'
+step-height: ' &3 &7■ 平稳行走: &f{value}'
+burning-time: '&3 &7■ 燃烧时间: &f{value}%'
+explosion-knockback-resistance: '&3 &7■ 爆炸击退抗性: &f{value}%'
+mining-efficiency: '&3 &7■ 挖掘效率: &f{value}'
+movement-efficiency: '&3 &7■ 移动效率: &f{value}%'
+oxygen-bonus: '&3 &7■ 水下呼吸: &f{value}'
+sneaking-speed: '&3 &7■ 潜行速度: &f{value}%'
+submerged-mining-speed: '&3 &7■ 水下挖掘速度: &f{value}%'
+sweeping-damage-ratio: '&3 &7■ 横扫伤害: &f{value}%'
+water-movement-efficiency: '&3 &7■ 水下移动速度: &f{value}%'
# Extra Options
perm-effects: '&3 &7■ 永久效果 &f{effect}'
diff --git a/pom.xml b/pom.xml
index 2e758d89..de7369db 100644
--- a/pom.xml
+++ b/pom.xml
@@ -59,14 +59,22 @@
+
phoenix
https://nexus.phoenixdevt.fr/repository/maven-public/
+
- nexus
+ lumine
https://mvn.lumine.io/repository/maven-public/
+
+
+ papermc
+ https://repo.papermc.io/repository/maven-public/
+
+