9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

Merge pull request #506 from jhqwqmc/dev

第三方物品库适配切换到itembridge库
This commit is contained in:
XiaoMoMi
2025-12-18 23:01:29 +08:00
committed by GitHub
25 changed files with 150 additions and 420 deletions

View File

@@ -9,6 +9,7 @@ repositories {
maven("https://repo.momirealms.net/releases/")
maven("https://libraries.minecraft.net/")
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.gtemc.net/releases/")
}
dependencies {
@@ -62,6 +63,8 @@ dependencies {
compileOnly("com.mojang:authlib:${rootProject.properties["authlib_version"]}")
// concurrentutil
compileOnly("ca.spottedleaf:concurrentutil:${rootProject.properties["concurrent_util_version"]}")
// ItemBridge
compileOnly("cn.gtemc:itembridge:${rootProject.properties["itembridge_version"]}")
}
java {
@@ -90,6 +93,7 @@ tasks {
relocate("net.kyori", "net.momirealms.craftengine.libraries")
relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt")
relocate("net.momirealms.antigrieflib", "net.momirealms.craftengine.libraries.antigrieflib")
relocate("cn.gtemc.itembridge", "net.momirealms.craftengine.libraries.itembridge")
relocate("org.incendo", "net.momirealms.craftengine.libraries")
relocate("dev.dejvokep", "net.momirealms.craftengine.libraries")
relocate("org.bstats", "net.momirealms.craftengine.libraries.bstats")

View File

@@ -19,6 +19,7 @@ repositories {
maven("https://repo.codemc.io/repository/maven-public/") // quickshop
maven("https://repo.nexomc.com/releases/") // nexo
maven("https://repo.opencollab.dev/main/") // geyser
maven("https://repo.gtemc.net/releases/")
}
dependencies {
@@ -96,6 +97,8 @@ dependencies {
compileOnly("org.geysermc.geyser:api:2.9.0-SNAPSHOT")
// Floodgate
compileOnly("org.geysermc.floodgate:api:2.2.4-SNAPSHOT")
// ItemBridge
compileOnly("cn.gtemc:itembridge:${rootProject.properties["itembridge_version"]}")
}
java {

View File

@@ -5,7 +5,6 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlockEntityElementConfigs;
import net.momirealms.craftengine.bukkit.compatibility.bedrock.FloodgateUtils;
import net.momirealms.craftengine.bukkit.compatibility.bedrock.GeyserUtils;
import net.momirealms.craftengine.bukkit.compatibility.item.*;
import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor;
import net.momirealms.craftengine.bukkit.compatibility.leveler.*;
import net.momirealms.craftengine.bukkit.compatibility.model.bettermodel.BetterModelBlockEntityElementConfig;
@@ -26,7 +25,6 @@ import net.momirealms.craftengine.bukkit.compatibility.tag.CustomNameplateProvid
import net.momirealms.craftengine.bukkit.compatibility.viaversion.ViaVersionUtils;
import net.momirealms.craftengine.bukkit.compatibility.worldedit.WorldEditBlockRegister;
import net.momirealms.craftengine.bukkit.font.BukkitFontManager;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.core.block.BlockManager;
import net.momirealms.craftengine.core.entity.furniture.ExternalModel;
@@ -130,7 +128,6 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
this.hasPlaceholderAPI = true;
logHook("PlaceholderAPI");
}
this.initItemHooks();
if (this.isPluginEnabled("LuckPerms")) {
this.initLuckPermsHook();
logHook("LuckPerms");
@@ -167,7 +164,6 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
logHook("EcoJobs");
}
if (this.isPluginEnabled("MythicMobs")) {
BukkitItemManager.instance().registerExternalItemSource(new MythicMobsSource());
new MythicItemDropListener(this.plugin);
logHook("MythicMobs");
}
@@ -224,7 +220,7 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
private void initLuckPermsHook() {
new LuckPermsEventListeners(plugin.javaPlugin(), (uuid) -> {
BukkitFontManager fontManager = (BukkitFontManager) plugin.fontManager();
BukkitFontManager fontManager = plugin.fontManager();
fontManager.refreshEmojiSuggestions(uuid);
});
}
@@ -297,42 +293,6 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
}
}
private void initItemHooks() {
BukkitItemManager itemManager = BukkitItemManager.instance();
if (this.isPluginEnabled("NeigeItems")) {
itemManager.registerExternalItemSource(new NeigeItemsSource());
logHook("NeigeItems");
}
if (this.isPluginEnabled("MMOItems")) {
itemManager.registerExternalItemSource(new MMOItemsSource());
logHook("MMOItems");
}
if (this.isPluginEnabled("CustomFishing")) {
itemManager.registerExternalItemSource(new CustomFishingSource());
logHook("CustomFishing");
}
if (this.isPluginEnabled("Zaphkiel")) {
itemManager.registerExternalItemSource(new ZaphkielSource());
logHook("Zaphkiel");
}
if (this.isPluginEnabled("HeadDatabase")) {
itemManager.registerExternalItemSource(new HeadDatabaseSource());
logHook("HeadDatabase");
}
if (this.isPluginEnabled("SX-Item")) {
itemManager.registerExternalItemSource(new SXItemSource());
logHook("SX-Item");
}
if (this.isPluginEnabled("Slimefun")) {
itemManager.registerExternalItemSource(new SlimefunSource());
logHook("Slimefun");
}
if (this.isPluginEnabled("Nexo")) {
itemManager.registerExternalItemSource(new NexoItemSource());
logHook("Nexo");
}
}
private Plugin getPlugin(String name) {
return Bukkit.getPluginManager().getPlugin(name);
}

View File

@@ -1,36 +0,0 @@
package net.momirealms.craftengine.bukkit.compatibility.item;
import net.momirealms.craftengine.core.item.ExternalItemSource;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class CustomFishingSource implements ExternalItemSource<ItemStack> {
@Override
public String plugin() {
return "customfishing";
}
@SuppressWarnings("UnstableApiUsage")
@Nullable
@Override
public ItemStack build(String id, ItemBuildContext context) {
Context<Player> ctx = Context.player(
(Player) Optional.ofNullable(context.player())
.map(net.momirealms.craftengine.core.entity.player.Player::platformPlayer)
.orElse(null)
);
return BukkitCustomFishingPlugin.getInstance().getItemManager().buildInternal(ctx.arg(ContextKeys.ID, id), id);
}
@Override
public String id(ItemStack item) {
return BukkitCustomFishingPlugin.getInstance().getItemManager().getCustomFishingItemID(item);
}
}

View File

@@ -1,33 +0,0 @@
package net.momirealms.craftengine.bukkit.compatibility.item;
import me.arcaniax.hdb.api.HeadDatabaseAPI;
import net.momirealms.craftengine.core.item.ExternalItemSource;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
public class HeadDatabaseSource implements ExternalItemSource<ItemStack> {
private HeadDatabaseAPI api;
@Override
public String plugin() {
return "headdatabase";
}
@Nullable
@Override
public ItemStack build(String id, ItemBuildContext context) {
if (api == null) {
api = new HeadDatabaseAPI();
}
return api.getItemHead(id);
}
@Override
public String id(ItemStack item) {
if (api == null) {
api = new HeadDatabaseAPI();
}
return api.getItemID(item);
}
}

View File

@@ -1,38 +0,0 @@
package net.momirealms.craftengine.bukkit.compatibility.item;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import net.momirealms.craftengine.core.item.ExternalItemSource;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import static java.util.Objects.requireNonNull;
public class MMOItemsSource implements ExternalItemSource<ItemStack> {
@Override
public String plugin() {
return "mmoitems";
}
@Override
public @Nullable ItemStack build(String id, ItemBuildContext context) {
String[] split = id.split(":", 2);
if (split.length == 1) {
split = split[0].split("_", 2);
}
if (split.length == 1) return new ItemStack(Material.AIR);
// 这里与使用和mmoitems相同的转换id方法
String mmoItemId = split[1].toUpperCase().replace("-", "_").replace(" ", "_");
MMOItem mmoItem = MMOItems.plugin.getMMOItem(Type.get(split[0]), mmoItemId);
return mmoItem == null ? new ItemStack(Material.AIR) : requireNonNull(mmoItem.newBuilder().build());
}
@Override
public String id(ItemStack item) {
return MMOItems.getType(item) + "_" + MMOItems.getID(item);
}
}

View File

@@ -1,51 +0,0 @@
package net.momirealms.craftengine.bukkit.compatibility.item;
import io.lumine.mythic.api.adapters.AbstractPlayer;
import io.lumine.mythic.api.skills.SkillCaster;
import io.lumine.mythic.bukkit.BukkitAdapter;
import io.lumine.mythic.bukkit.MythicBukkit;
import io.lumine.mythic.core.drops.DropMetadataImpl;
import net.momirealms.craftengine.core.item.ExternalItemSource;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class MythicMobsSource implements ExternalItemSource<ItemStack> {
private MythicBukkit mythicBukkit;
@Override
public String plugin() {
return "mythicmobs";
}
@Nullable
@Override
public ItemStack build(String id, ItemBuildContext context) {
if (mythicBukkit == null || mythicBukkit.isClosed()) {
this.mythicBukkit = MythicBukkit.inst();
}
return Optional.ofNullable(context.player())
.map(p -> (Player) p.platformPlayer())
.map(p -> {
AbstractPlayer target = BukkitAdapter.adapt(p);
SkillCaster caster = mythicBukkit.getSkillManager().getCaster(target);
DropMetadataImpl meta = new DropMetadataImpl(caster, target);
return mythicBukkit.getItemManager().getItem(id)
.map(i -> i.generateItemStack(meta, 1))
.map(BukkitAdapter::adapt)
.orElse(null);
})
.orElseGet(() -> mythicBukkit.getItemManager().getItemStack(id));
}
@Override
public String id(ItemStack item) {
if (mythicBukkit == null || mythicBukkit.isClosed()) {
this.mythicBukkit = MythicBukkit.inst();
}
return mythicBukkit.getItemManager().getMythicTypeFromItem(item);
}
}

View File

@@ -1,27 +0,0 @@
package net.momirealms.craftengine.bukkit.compatibility.item;
import net.momirealms.craftengine.core.item.ExternalItemSource;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import pers.neige.neigeitems.manager.ItemManager;
import java.util.Optional;
public class NeigeItemsSource implements ExternalItemSource<ItemStack> {
@Override
public String plugin() {
return "neigeitems";
}
@Override
public ItemStack build(String id, ItemBuildContext context) {
return ItemManager.INSTANCE.getItemStack(id, Optional.ofNullable(context.player()).map(it -> (Player) it.platformPlayer()).orElse(null));
}
@Override
public String id(ItemStack item) {
return ItemManager.INSTANCE.getItemId(item);
}
}

View File

@@ -1,29 +0,0 @@
package net.momirealms.craftengine.bukkit.compatibility.item;
import com.nexomc.nexo.api.NexoItems;
import com.nexomc.nexo.items.ItemBuilder;
import net.momirealms.craftengine.core.item.ExternalItemSource;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
public class NexoItemSource implements ExternalItemSource<ItemStack> {
@Override
public String plugin() {
return "nexo";
}
@Nullable
@Override
public ItemStack build(String id, ItemBuildContext context) {
ItemBuilder itemBuilder = NexoItems.itemFromId(id);
if (itemBuilder == null) return null;
return itemBuilder.build();
}
@Override
public String id(ItemStack item) {
return NexoItems.idFromItem(item);
}
}

View File

@@ -1,29 +0,0 @@
package net.momirealms.craftengine.bukkit.compatibility.item;
import github.saukiya.sxitem.SXItem;
import net.momirealms.craftengine.core.item.ExternalItemSource;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class SXItemSource implements ExternalItemSource<ItemStack> {
@Override
public String plugin() {
return "sx-item";
}
@Nullable
@Override
public ItemStack build(String id, ItemBuildContext context) {
return SXItem.getItemManager().getItem(id, Optional.ofNullable(context.player()).map(p -> (Player) p.platformPlayer()).orElse(null));
}
@Override
public String id(ItemStack item) {
return SXItem.getItemManager().getItemKey(item);
}
}

View File

@@ -1,28 +0,0 @@
package net.momirealms.craftengine.bukkit.compatibility.item;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import net.momirealms.craftengine.core.item.ExternalItemSource;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class SlimefunSource implements ExternalItemSource<ItemStack> {
@Override
public String plugin() {
return "slimefun";
}
@Nullable
@Override
public ItemStack build(String id, ItemBuildContext context) {
return Optional.ofNullable(SlimefunItem.getById(id)).map(SlimefunItem::getItem).orElse(null);
}
@Override
public String id(ItemStack item) {
return Optional.ofNullable(SlimefunItem.getByItem(item)).map(SlimefunItem::getId).orElse(null);
}
}

View File

@@ -1,33 +0,0 @@
package net.momirealms.craftengine.bukkit.compatibility.item;
import ink.ptms.zaphkiel.Zaphkiel;
import net.momirealms.craftengine.core.item.ExternalItemSource;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import javax.annotation.Nullable;
import java.util.Optional;
/**
* @author iiabc
* @since 2025/8/30 09:39
*/
public class ZaphkielSource implements ExternalItemSource<ItemStack> {
@Override
public String plugin() {
return "zaphkiel";
}
@Override
public @Nullable ItemStack build(String id, ItemBuildContext context) {
Player player = Optional.ofNullable(context.player()).map(it -> (Player) it.platformPlayer()).orElse(null);
return Zaphkiel.INSTANCE.api().getItemManager().generateItemStack(id, player);
}
@Override
public String id(ItemStack item) {
return Zaphkiel.INSTANCE.api().getItemHandler().getItemId(item);
}
}

View File

@@ -7,6 +7,7 @@ repositories {
maven("https://jitpack.io/")
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.momirealms.net/releases/")
maven("https://repo.gtemc.net/releases/")
mavenCentral()
}
@@ -27,6 +28,7 @@ dependencies {
implementation("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}")
implementation("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}")
implementation("net.momirealms:craft-engine-nms-helper:${rootProject.properties["nms_helper_version"]}")
implementation("cn.gtemc:itembridge:${rootProject.properties["itembridge_version"]}")
}
java {
@@ -66,6 +68,7 @@ tasks {
relocate("net.kyori", "net.momirealms.craftengine.libraries")
relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt")
relocate("net.momirealms.antigrieflib", "net.momirealms.craftengine.libraries.antigrieflib")
relocate("cn.gtemc.itembridge", "net.momirealms.craftengine.libraries.itembridge")
relocate("org.incendo", "net.momirealms.craftengine.libraries")
relocate("dev.dejvokep", "net.momirealms.craftengine.libraries")
relocate("org.bstats", "net.momirealms.craftengine.libraries.bstats")

View File

@@ -11,6 +11,7 @@ repositories {
maven("https://jitpack.io/")
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.momirealms.net/releases/")
maven("https://repo.gtemc.net/releases/")
mavenCentral()
}
@@ -31,6 +32,7 @@ dependencies {
implementation("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}")
implementation("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}")
implementation("net.momirealms:craft-engine-nms-helper-mojmap:${rootProject.properties["nms_helper_version"]}")
implementation("cn.gtemc:itembridge:${rootProject.properties["itembridge_version"]}")
}
java {
@@ -92,15 +94,33 @@ paper {
register("BetterModel") { required = false }
// external items
register("NeigeItems") { required = false }
register("AzureFlow") { required = false }
register("CustomFishing") { required = false }
register("EcoArmor") { required = false }
register("EcoCrates") { required = false }
register("EcoItems") { required = false }
register("EcoMobs") { required = false }
register("EcoPets") { required = false }
register("EcoScrolls") { required = false }
register("ExecutableItems") { required = false }
register("HeadDatabase") { required = false }
register("HMCCosmetics") { required = false }
register("ItemsAdder") { required = false }
register("MagicGem") { required = false }
register("MMOItems") { required = false }
register("MythicMobs") { required = false }
register("CustomFishing") { required = false }
register("Zaphkiel") { required = false }
register("HeadDatabase") { required = false }
register("SX-Item") { required = false }
register("Slimefun") { required = false }
register("NeigeItems") { required = false }
register("Nexo") { required = false }
register("Nova") { required = false }
register("Oraxen") { required = false }
register("PxRpg") { required = false }
register("Ratziel") { required = false }
register("Reforges") { required = false }
register("Slimefun") { required = false }
register("StatTrackers") { required = false }
register("SX-Item") { required = false }
register("Talismans") { required = false }
register("Zaphkiel") { required = false }
// leveler
register("AuraSkills") { required = false }
@@ -155,6 +175,7 @@ tasks {
relocate("net.kyori", "net.momirealms.craftengine.libraries")
relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt")
relocate("net.momirealms.antigrieflib", "net.momirealms.craftengine.libraries.antigrieflib")
relocate("cn.gtemc.itembridge", "net.momirealms.craftengine.libraries.itembridge")
relocate("org.incendo", "net.momirealms.craftengine.libraries")
relocate("dev.dejvokep", "net.momirealms.craftengine.libraries")
relocate("org.bstats", "net.momirealms.craftengine.libraries.bstats")

View File

@@ -1,5 +1,7 @@
package net.momirealms.craftengine.bukkit.item;
import cn.gtemc.itembridge.api.Provider;
import cn.gtemc.itembridge.core.BukkitItemBridge;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -39,6 +41,7 @@ import java.nio.file.Path;
import java.util.*;
import java.util.function.Function;
@SuppressWarnings("unchecked")
public class BukkitItemManager extends AbstractItemManager<ItemStack> {
static {
registerVanillaItemExtraBehavior(FlintAndSteelItemBehavior.INSTANCE, ItemKeys.FLINT_AND_STEEL);
@@ -56,6 +59,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
private final Item<ItemStack> emptyItem;
private final UniqueIdItem<ItemStack> emptyUniqueItem;
private final Function<Object, Integer> decoratedHashOpsGenerator;
private BukkitItemBridge itemBridge;
private Set<Key> lastRegisteredPatterns = Set.of();
@SuppressWarnings("unchecked")
@@ -82,15 +86,13 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
@Override
public void delayedLoad() {
super.delayedLoad();
List<ExternalItemSource<ItemStack>> sources = new ArrayList<>();
List<Provider<ItemStack, org.bukkit.entity.Player>> sources = new ArrayList<>();
for (String externalSource : Config.recipeIngredientSources()) {
String sourceId = externalSource.toLowerCase(Locale.ENGLISH);
ExternalItemSource<ItemStack> provider = getExternalItemSource(sourceId);
if (provider != null) {
sources.add(provider);
}
Optional<Provider<ItemStack, org.bukkit.entity.Player>> provider = itemBridgeProvider().provider(sourceId);
provider.ifPresent(sources::add);
}
this.factory.resetRecipeIngredientSources(sources.isEmpty() ? null : sources.toArray(new ExternalItemSource[0]));
this.factory.resetRecipeIngredientSources(sources.isEmpty() ? null : sources.toArray(new Provider[0]));
}
@Override
@@ -442,4 +444,14 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
public Function<Object, Integer> decoratedHashOpsGenerator() {
return decoratedHashOpsGenerator;
}
@Override
public BukkitItemBridge itemBridgeProvider() {
if (this.itemBridge == null) {
BukkitItemBridge.BukkitBuilder builder = BukkitItemBridge.builder();
builder.removeById("craftengine");
this.itemBridge = builder.build();
}
return this.itemBridge;
}
}

View File

@@ -1,12 +1,12 @@
package net.momirealms.craftengine.bukkit.item.factory;
import cn.gtemc.itembridge.api.Provider;
import com.google.gson.JsonElement;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
import net.momirealms.craftengine.bukkit.util.ItemTags;
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.item.ExternalItemSource;
import net.momirealms.craftengine.core.item.ItemFactory;
import net.momirealms.craftengine.core.item.ItemKeys;
import net.momirealms.craftengine.core.item.ItemWrapper;
@@ -19,6 +19,7 @@ import net.momirealms.craftengine.core.util.UniqueKey;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.sparrow.nbt.Tag;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.Objects;
@@ -26,7 +27,7 @@ import java.util.Optional;
public abstract class BukkitItemFactory<W extends ItemWrapper<ItemStack>> extends ItemFactory<W, ItemStack> {
private boolean hasExternalRecipeSource = false;
private ExternalItemSource<ItemStack>[] recipeIngredientSources = null;
private Provider<ItemStack, Player>[] recipeIngredientSources = null;
protected BukkitItemFactory(CraftEngine plugin) {
super(plugin);
@@ -50,7 +51,7 @@ public abstract class BukkitItemFactory<W extends ItemWrapper<ItemStack>> extend
throw new IllegalStateException("Unsupported server version: " + VersionHelper.MINECRAFT_VERSION.version());
}
public void resetRecipeIngredientSources(ExternalItemSource<ItemStack>[] recipeIngredientSources) {
public void resetRecipeIngredientSources(Provider<ItemStack, Player>[] recipeIngredientSources) {
if (recipeIngredientSources == null || recipeIngredientSources.length == 0) {
this.recipeIngredientSources = null;
this.hasExternalRecipeSource = false;
@@ -102,8 +103,8 @@ public abstract class BukkitItemFactory<W extends ItemWrapper<ItemStack>> extend
return null;
}
if (this.hasExternalRecipeSource) {
for (ExternalItemSource<ItemStack> source : this.recipeIngredientSources) {
String id = source.id(item.getItem());
for (Provider<ItemStack, Player> source : this.recipeIngredientSources) {
String id = source.idOrNull(item.getItem());
if (id != null) {
return UniqueKey.create(Key.of(source.plugin(), StringUtils.toLowerCase(id)));
}

View File

@@ -563,16 +563,19 @@ warning.config.selector.invalid_type: "<yellow>在文件 <arg:0> 发现问题 -
warning.config.selector.invalid_target: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的选择器目标 '<arg:2>'</yellow>"
warning.config.resource_pack.item_model.already_exist: "<yellow>无法为 '<arg:0>' 生成物品模型, 因为文件 '<arg:1>' 已存在</yellow>"
warning.config.resource_pack.model.generation.already_exist: "<yellow>无法生成模型, 因为模型文件 '<arg:0>' 已存在</yellow>"
warning.config.resource_pack.generation.malformatted_json: "<yellow>Json文件 '<arg:0>' 格式错误</yellow>"
warning.config.resource_pack.generation.missing_font_texture: "<yellow>字体'<arg:0>'缺少必要纹理: '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_model_texture: "<yellow>模型'<arg:0>'缺少纹理'<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_item_model: "<yellow>物品'<arg:0>'缺少模型文件: '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_block_model: "<yellow>方块状态'<arg:0>'缺少模型文件: '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_parent_model: "<yellow>模型'<arg:0>'找不到父级模型文件: '<arg:1>'</yellow>"
warning.config.resource_pack.generation.malformatted_json: "<yellow>JSON 文件 '<arg:0>' 格式错误</yellow>"
warning.config.resource_pack.generation.missing_font_texture: "<yellow>字体 '<arg:0>' 缺少必要纹理: '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_model_texture: "<yellow>模型 '<arg:0>' 缺少纹理 '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_atlas_texture: "<yellow>纹理图集 '<arg:0>' 缺少纹理 '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_item_model: "<yellow>物品 '<arg:0>' 缺少模型文件: '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_block_model: "<yellow>方块状态 '<arg:0>' 缺少模型文件: '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_parent_model: "<yellow>模型 '<arg:0>' 找不到父级模型文件: '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_equipment_texture: "<yellow>装备 '<arg:0>' 缺少纹理 '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_sound: "<yellow>声音事件 '<arg:0>' 缺少 ogg 文件 '<arg:1>'</yellow>"
warning.config.resource_pack.generation.texture_not_in_atlas: "<yellow>纹理'<arg:0>'不在图集内. 你需要将纹理路径或文件夹前缀添加到图集内, 或者启用 config.yml 中的 'fix-atlas' 选项</yellow>"
warning.config.resource_pack.invalid_overlay_format: "<yellow>在 config.yml 的 'resource-pack.overlay-format' 处发现问题 - 无效的overlay格式 '<arg:0>'. Overlay格式必须包含占位符 '{version}'</yellow>"
warning.config.resource_pack.generation.texture_not_in_atlas: "<yellow>纹理 '<arg:0>' 不在纹理图集内. 你需要将纹理路径或文件夹前缀添加到纹理图集内, 或者启用 config.yml 中的 'fix-atlas' 选项</yellow>"
warning.config.resource_pack.generation.multiple_atlases: "<yellow>模型 '<arg:0>' 使用了多个纹理图集, 预期应来自 '<arg:1>', 但同时检测到 '<arg:2>'. 请确保模型使用的所有纹理均来自同一纹理图集以修复此问题</yellow>"
warning.config.resource_pack.generation.duplicated_sprite: "<yellow>无法加载模型 '<arg:0>'. 纹理图集 '<arg:2>' 中的精灵图 '<arg:1>' 与纹理图集 '<arg:3>' 中的定义重复</yellow>"
warning.config.resource_pack.invalid_overlay_format: "<yellow>在 config.yml 的 'resource-pack.overlay-format' 处发现问题 - 无效的叠加资源包格式 '<arg:0>'. 叠加资源包格式必须包含占位符 '{version}'</yellow>"
warning.config.equipment.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的装备配置 '<arg:1>'. 请检查其他文件中是否存在相同配置</yellow>"
warning.config.equipment.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 装备 '<arg:1>' 缺少必需的 'type' 参数</yellow>"
warning.config.equipment.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 装备 '<arg:1>' 使用了无效的 'type' 参数</yellow>"

View File

@@ -7,6 +7,7 @@ repositories {
maven("https://jitpack.io/")
maven("https://libraries.minecraft.net/")
maven("https://repo.momirealms.net/releases/")
maven("https://repo.gtemc.net/releases/")
}
dependencies {
@@ -71,6 +72,8 @@ dependencies {
compileOnly("ca.spottedleaf:concurrentutil:${rootProject.properties["concurrent_util_version"]}")
// bucket4j
compileOnly("com.bucket4j:bucket4j_jdk17-core:${rootProject.properties["bucket4j_version"]}")
// ItemBridge
compileOnly("cn.gtemc:itembridge:${rootProject.properties["itembridge_version"]}")
}
java {
@@ -110,6 +113,7 @@ tasks {
relocate("io.netty.handler.codec.spdy", "net.momirealms.craftengine.libraries.netty.handler.codec.spdy")
relocate("io.netty.handler.codec.http2", "net.momirealms.craftengine.libraries.netty.handler.codec.http2")
relocate("io.github.bucket4j", "net.momirealms.craftengine.libraries.bucket4j") // bucket4j
relocate("cn.gtemc.itembridge", "net.momirealms.craftengine.libraries.itembridge")
}
}

View File

@@ -13,7 +13,6 @@ import net.momirealms.craftengine.core.item.updater.ItemUpdaters;
import net.momirealms.craftengine.core.pack.AbstractPackManager;
import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.pack.ResourceLocation;
import net.momirealms.craftengine.core.pack.allocator.IdAllocator;
import net.momirealms.craftengine.core.pack.model.*;
import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator;
@@ -50,7 +49,6 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
private final ItemParser itemParser;
private final EquipmentParser equipmentParser;
protected final Map<String, ExternalItemSource<I>> externalItemSources = new HashMap<>();
protected final Map<Key, CustomItem<I>> customItemsById = new LinkedHashMap<>();
protected final Map<String, CustomItem<I>> customItemsByPath = new HashMap<>();
protected final Map<Key, List<UniqueKey>> customItemTags = new HashMap<>();
@@ -96,19 +94,6 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
return new ConfigParser[]{this.itemParser, this.equipmentParser};
}
@Override
public ExternalItemSource<I> getExternalItemSource(String name) {
return this.externalItemSources.get(name);
}
@Override
public boolean registerExternalItemSource(ExternalItemSource<I> externalItemSource) {
if (!ResourceLocation.isValidNamespace(externalItemSource.plugin())) return false;
if (this.externalItemSources.containsKey(externalItemSource.plugin())) return false;
this.externalItemSources.put(externalItemSource.plugin(), externalItemSource);
return true;
}
@Override
public void unload() {
super.clearModelsToGenerate();

View File

@@ -1,13 +0,0 @@
package net.momirealms.craftengine.core.item;
import org.jetbrains.annotations.Nullable;
public interface ExternalItemSource<I> {
String plugin();
@Nullable
I build(String id, ItemBuildContext context);
String id(I item);
}

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.core.item;
import cn.gtemc.itembridge.api.ItemBridge;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.equipment.Equipment;
@@ -60,10 +61,6 @@ public interface ItemManager<T> extends Manageable, ModelGenerator {
return loadedItems().keySet();
}
ExternalItemSource<T> getExternalItemSource(String name);
boolean registerExternalItemSource(ExternalItemSource<T> externalItemSource);
Optional<Equipment> getEquipment(Key key);
Optional<CustomItem<T>> getCustomItem(Key key);
@@ -124,4 +121,6 @@ public interface ItemManager<T> extends Manageable, ModelGenerator {
List<UniqueKey> getIngredientSubstitutes(Key item);
ItemUpdateResult updateItem(Item<T> item, Supplier<ItemBuildContext> contextSupplier);
<P> ItemBridge<T, P> itemBridgeProvider();
}

View File

@@ -1,24 +1,31 @@
package net.momirealms.craftengine.core.item.modifier;
import net.momirealms.craftengine.core.item.ExternalItemSource;
import cn.gtemc.itembridge.api.Provider;
import cn.gtemc.itembridge.api.context.BuildContext;
import cn.gtemc.itembridge.api.context.ContextKey;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.ItemDataModifierFactory;
import net.momirealms.craftengine.core.item.ItemManager;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.function.Supplier;
public class ExternalModifier<I> implements ItemDataModifier<I> {
public static final Factory<?> FACTORY = new Factory<>();
private static final ThreadLocal<Set<Dependency>> BUILD_STACK = ThreadLocal.withInitial(LinkedHashSet::new);
private final String id;
private final ExternalItemSource<I> provider;
private final Provider<I, Object> provider;
public ExternalModifier(String id, ExternalItemSource<I> provider) {
public ExternalModifier(String id, Provider<I, Object> provider) {
this.id = id;
this.provider = provider;
}
@@ -27,7 +34,7 @@ public class ExternalModifier<I> implements ItemDataModifier<I> {
return id;
}
public ExternalItemSource<I> source() {
public Provider<I, Object> source() {
return provider;
}
@@ -36,7 +43,6 @@ public class ExternalModifier<I> implements ItemDataModifier<I> {
return ItemDataModifiers.EXTERNAL;
}
@SuppressWarnings("unchecked")
@Override
public Item<I> apply(Item<I> item, ItemBuildContext context) {
Dependency dependency = new Dependency(provider.plugin(), id);
@@ -54,12 +60,14 @@ public class ExternalModifier<I> implements ItemDataModifier<I> {
buildStack.add(dependency);
try {
I another = this.provider.build(this.id, context);
ItemManager<I> itemManager = CraftEngine.instance().itemManager();
Player player = context.player();
I another = this.provider.buildOrNull(this.id, player == null ? null : player.platformPlayer(), adapt(context));
if (another == null) {
CraftEngine.instance().logger().warn("'" + this.id + "' could not be found in " + provider.plugin());
return item;
}
Item<I> anotherWrapped = (Item<I>) CraftEngine.instance().itemManager().wrap(another);
Item<I> anotherWrapped = itemManager.wrap(another);
item.merge(anotherWrapped);
return item;
} catch (Throwable e) {
@@ -71,16 +79,42 @@ public class ExternalModifier<I> implements ItemDataModifier<I> {
}
}
private static BuildContext adapt(ItemBuildContext context) {
if (!VersionHelper.IS_RUNNING_IN_DEV) return BuildContext.empty(); // 先不在生产环境启用
ContextHolder contexts = context.contexts();
if (contexts.isEmpty()) {
return BuildContext.empty();
}
BuildContext.Builder builder = BuildContext.builder();
for (Map.Entry<net.momirealms.craftengine.core.plugin.context.ContextKey<?>, Supplier<Object>> entry : contexts.params().entrySet()) {
Object value = entry.getValue().get();
if (value == null) {
continue;
}
Class<?> type = value.getClass(); // fixme 这个获取办法并不正确net.momirealms.craftengine.core.plugin.context.ContextKey 应该在创建的时候记录是什么类型
@SuppressWarnings("unchecked")
ContextKey<Object> contextKey = (ContextKey<Object>) ContextKey.of(type, entry.getKey().node());
with(builder, contextKey, entry.getValue());
}
return builder.build();
}
private static <T> void with(BuildContext.Builder builder, ContextKey<T> key, Supplier<T> value) {
builder.with(key, value);
}
public static class Factory<I> implements ItemDataModifierFactory<I> {
@SuppressWarnings("unchecked")
@Override
public ItemDataModifier<I> create(Object arg) {
Map<String, Object> data = ResourceConfigUtils.getAsMap(arg, "external");
String plugin = ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(data, "plugin", "source"), "warning.config.item.data.external.missing_source");
String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(data.get("id"), "warning.config.item.data.external.missing_id");
ExternalItemSource<I> provider = (ExternalItemSource<I>) CraftEngine.instance().itemManager().getExternalItemSource(plugin.toLowerCase(Locale.ENGLISH));
return new ExternalModifier<>(id, ResourceConfigUtils.requireNonNullOrThrow(provider, () -> new LocalizedResourceConfigException("warning.config.item.data.external.invalid_source", plugin)));
ItemManager<I> itemManager = CraftEngine.instance().itemManager();
Provider<I, Object> provider = itemManager.itemBridgeProvider().provider(plugin.toLowerCase(Locale.ENGLISH)).orElseThrow(
() -> new LocalizedResourceConfigException("warning.config.item.data.external.invalid_source", plugin)
);
return new ExternalModifier<>(id, provider);
}
}

View File

@@ -1,6 +1,7 @@
package net.momirealms.craftengine.core.plugin.context;
import com.google.common.collect.ImmutableMap;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -93,6 +94,16 @@ public class ContextHolder {
return (T) Optional.ofNullable(this.params.get(parameter)).map(Supplier::get).orElse(defaultValue);
}
@ApiStatus.Internal
public Map<ContextKey<?>, Supplier<Object>> params() {
return ImmutableMap.copyOf(this.params);
}
@ApiStatus.Internal
public boolean isEmpty() {
return this.params.isEmpty();
}
public static Builder builder() {
return new Builder();
}

View File

@@ -1,16 +1,20 @@
package net.momirealms.craftengine.core.world.chunk.storage;
import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
import it.unimi.dsi.fastutil.io.FastBufferedOutputStream;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.dependency.Dependencies;
import net.momirealms.craftengine.core.util.ReflectionUtils;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.util.Set;
import java.util.zip.DeflaterOutputStream;
@@ -22,8 +26,8 @@ public class CompressionMethod {
public static final int METHOD_COUNT = 5;
public static final CompressionMethod[] METHODS = new CompressionMethod[METHOD_COUNT +1];
public static final CompressionMethod NONE = register(new CompressionMethod(1, (stream) -> stream, (stream) -> stream));
public static final CompressionMethod DEFLATE = register(new CompressionMethod(2, (stream) -> new FastBufferedInputStream(new InflaterInputStream(stream)), (stream) -> new BufferedOutputStream(new DeflaterOutputStream(stream))));
public static final CompressionMethod GZIP = register(new CompressionMethod(3, (stream) -> new FastBufferedInputStream(new GZIPInputStream(stream)), (stream) -> new BufferedOutputStream(new GZIPOutputStream(stream))));
public static final CompressionMethod DEFLATE = register(new CompressionMethod(2, (stream) -> new FastBufferedInputStream(new InflaterInputStream(stream)), (stream) -> new FastBufferedOutputStream(new DeflaterOutputStream(stream))));
public static final CompressionMethod GZIP = register(new CompressionMethod(3, (stream) -> new FastBufferedInputStream(new GZIPInputStream(stream)), (stream) -> new FastBufferedOutputStream(new GZIPOutputStream(stream))));
public static final CompressionMethod LZ4 = register(new CompressionMethod(4, LZ4BlockInputStream::new, LZ4BlockOutputStream::new));
public static final CompressionMethod ZSTD;
@@ -31,24 +35,26 @@ public class CompressionMethod {
ClassLoader classLoader = CraftEngine.instance().dependencyManager().obtainClassLoaderWith(Set.of(Dependencies.ZSTD));
try {
Class<?> inputStreamClass = classLoader.loadClass("com.github.luben.zstd.ZstdInputStream");
Constructor<?> inputStreamConstructor = inputStreamClass.getConstructor(InputStream.class);
MethodHandle inputStreamConstructor = ReflectionUtils.unreflectConstructor(inputStreamClass.getConstructor(InputStream.class))
.asType(MethodType.methodType(InputStream.class, InputStream.class));
Class<?> outputStreamClass = classLoader.loadClass("com.github.luben.zstd.ZstdOutputStream");
Constructor<?> outputStreamConstructor = outputStreamClass.getConstructor(OutputStream.class);
MethodHandle outputStreamConstructor = ReflectionUtils.unreflectConstructor(outputStreamClass.getConstructor(OutputStream.class))
.asType(MethodType.methodType(OutputStream.class, OutputStream.class));
ZSTD = register(
new CompressionMethod(
5,
rawStream -> {
try {
return (InputStream) inputStreamConstructor.newInstance(rawStream);
} catch (Exception e) {
return (InputStream) inputStreamConstructor.invokeExact(rawStream);
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Could not instantiate ZstdInputStream", e);
return rawStream;
}
},
rawStream -> {
try {
return (OutputStream) outputStreamConstructor.newInstance(rawStream);
} catch (Exception e) {
return (OutputStream) outputStreamConstructor.invokeExact(rawStream);
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Could not instantiate ZstdOutputStream", e);
return rawStream;
}

View File

@@ -57,6 +57,7 @@ jimfs_version=1.3.1
authlib_version=7.0.60
concurrent_util_version=0.0.8-SNAPSHOT
bucket4j_version=8.15.0
itembridge_version=1.0.12
# Proxy settings
systemProp.socks.proxyHost=127.0.0.1