9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00
This commit is contained in:
XiaoMoMi
2025-03-15 05:47:49 +08:00
parent 0e42e5d610
commit 6967ea4399
30 changed files with 539 additions and 174 deletions

View File

@@ -12,10 +12,6 @@ forced-locale: ''
resource-pack:
# Should those images in minecraft:default font also work in minecraft:uniform
override-uniform-font: true
# Do not use this feature for the moment as it's under development
# Do not use this feature for the moment as it's under development
# Do not use this feature for the moment as it's under development
# Resource pack protection
protection:
# Warning: Do not attempt to unzip the resource pack with crash tools enabled.

View File

@@ -38,6 +38,10 @@ categories:
- default:topaz_bow
- default:topaz_crossbow
- default:topaz_rod
- default:topaz_helmet
- default:topaz_chestplate
- default:topaz_leggings
- default:topaz_boots
default:furniture:
name: "<!i><#FFD700><i18n:category.furniture></#FFD700>"
hidden: true

View File

@@ -13,6 +13,10 @@ i18n:
item.topaz_hoe: "Topaz Hoe"
item.topaz_shovel: "Topaz Shovel"
item.topaz_sword: "Topaz Sword"
item.topaz_helmet: "Topaz Helmet"
item.topaz_chestplate: "Topaz Chestplate"
item.topaz_leggings: "Topaz Leggings"
item.topaz_boots: "Topaz Boots"
item.topaz_ore: "Topaz Ore"
item.deepslate_topaz_ore: "Deepslate Topaz Ore"
item.topaz: "Topaz"
@@ -43,6 +47,10 @@ i18n:
item.topaz_hoe: "黄玉锄"
item.topaz_shovel: "黄玉锹"
item.topaz_sword: "黄玉剑"
item.topaz_helmet: "黄玉头盔"
item.topaz_chestplate: "黄玉胸甲"
item.topaz_leggings: "黄玉护腿"
item.topaz_boots: "黄玉靴子"
item.topaz_ore: "黄玉矿石"
item.deepslate_topaz_ore: "深层黄玉矿石"
item.topaz: "黄玉"

View File

@@ -125,6 +125,47 @@ items:
parent: "minecraft:item/handheld"
textures:
"layer0": "minecraft:item/custom/topaz_sword"
default:topaz_helmet:
template: default:topaz_armor
arguments:
part: helmet
slot: head
default:topaz_chestplate:
template: default:topaz_armor
arguments:
part: chestplate
slot: chest
default:topaz_leggings:
template: default:topaz_armor
arguments:
part: leggings
slot: legs
default:topaz_boots:
template: default:topaz_armor
arguments:
part: boots
slot: feet
templates:
default:topaz_armor:
material: "chainmail_{part}"
custom-model-data: 1000
data:
display-name: "<!i><#FF8C00><i18n:item.topaz_{part}>"
tooltip-style: minecraft:topaz
model:
type: minecraft:model
path: "minecraft:item/custom/topaz_{part}"
generation:
parent: "minecraft:item/generated"
textures:
"layer0": "minecraft:item/custom/topaz_{part}"
settings:
equippable:
slot: "{slot}"
asset-id: topaz
humanoid: "minecraft:entity/equipment/humanoid/topaz"
humanoid-leggings: "minecraft:entity/equipment/humanoid_leggings/topaz"
recipes:
default:topaz_shovel:

View File

@@ -19,7 +19,7 @@ import net.momirealms.craftengine.core.block.properties.Properties;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.ConfigManager;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;

View File

@@ -18,8 +18,9 @@ import net.momirealms.craftengine.core.item.modifier.IdModifier;
import net.momirealms.craftengine.core.item.modifier.ItemModelModifier;
import net.momirealms.craftengine.core.pack.LegacyOverridesModel;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration;
import net.momirealms.craftengine.core.pack.model.*;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.plugin.config.ConfigManager;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
@@ -41,12 +42,8 @@ import org.jetbrains.annotations.Nullable;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Stream;
public class BukkitItemManager extends AbstractItemManager<ItemStack> {
private static final Map<Key, List<ItemBehavior>> VANILLA_ITEM_EXTRA_BEHAVIORS = new HashMap<>();
private static final List<Key> VANILLA_ITEMS = new ArrayList<>();
static {
registerVanillaItemExtraBehavior(AxeItemBehavior.INSTANCE, ItemKeys.AXES);
registerVanillaItemExtraBehavior(WaterBucketItemBehavior.INSTANCE, ItemKeys.WATER_BUCKETS);
@@ -54,38 +51,16 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
registerVanillaItemExtraBehavior(BoneMealBehavior.INSTANCE, ItemKeys.BONE_MEAL);
}
private static void registerVanillaItemExtraBehavior(ItemBehavior behavior, Key... items) {
for (Key key : items) {
VANILLA_ITEM_EXTRA_BEHAVIORS.computeIfAbsent(key, k -> new ArrayList<>()).add(behavior);
}
}
private static BukkitItemManager instance;
private final BukkitItemFactory factory;
private final Map<Key, TreeSet<LegacyOverridesModel>> legacyOverrides;
private final Map<Key, TreeMap<Integer, ItemModel>> modernOverrides;
private final BukkitCraftEngine plugin;
private final ItemEventListener itemEventListener;
private final DebugStickListener debugStickListener;
private final Map<Key, List<Holder<Key>>> vanillaItemTags;
private final Map<Key, List<Holder<Key>>> customItemTags;
private final Map<Key, Map<Integer, Key>> cmdConflictChecker;
private final Map<Key, ItemModel> modernItemModels1_21_4;
private final Map<Key, List<LegacyOverridesModel>> modernItemModels1_21_2;
// Cached command suggestions
private final List<Suggestion> cachedSuggestions = new ArrayList<>();
public BukkitItemManager(BukkitCraftEngine plugin) {
super(plugin);
this.plugin = plugin;
this.factory = BukkitItemFactory.create(plugin);
this.legacyOverrides = new HashMap<>();
this.modernOverrides = new HashMap<>();
this.vanillaItemTags = new HashMap<>();
this.customItemTags = new HashMap<>();
this.cmdConflictChecker = new HashMap<>();
this.modernItemModels1_21_4 = new HashMap<>();
this.modernItemModels1_21_2 = new HashMap<>();
this.itemEventListener = new ItemEventListener(plugin);
this.debugStickListener = new DebugStickListener(plugin);
this.registerAllVanillaItems();
@@ -111,30 +86,6 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
return Optional.of(new CloneableConstantItem(key, new ItemStack(material)));
}
@Override
public List<Holder<Key>> tagToItems(Key tag) {
List<Holder<Key>> items = new ArrayList<>();
List<Holder<Key>> holders = vanillaItemTags.get(tag);
if (holders != null) {
items.addAll(holders);
}
List<Holder<Key>> customItems = customItemTags.get(tag);
if (customItems != null) {
items.addAll(customItems);
}
return items;
}
@Override
public List<Holder<Key>> tagToVanillaItems(Key tag) {
return this.vanillaItemTags.getOrDefault(tag, List.of());
}
@Override
public List<Holder<Key>> tagToCustomItems(Key tag) {
return this.customItemTags.getOrDefault(tag, List.of());
}
@Override
public int fuelTime(ItemStack itemStack) {
if (ItemUtils.isEmpty(itemStack)) return 0;
@@ -147,11 +98,6 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
return getCustomItem(id).map(it -> it.settings().fuelTime()).orElse(0);
}
@Override
public Collection<Suggestion> cachedSuggestions() {
return this.cachedSuggestions;
}
@Override
public void load() {
super.load();
@@ -160,16 +106,11 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
@Override
public void unload() {
super.unload();
this.cachedSuggestions.clear();
this.legacyOverrides.clear();
this.modernOverrides.clear();
this.customItemTags.clear();
this.cmdConflictChecker.clear();
}
@Override
public void disable() {
unload();
this.unload();
HandlerList.unregisterAll(this.itemEventListener);
HandlerList.unregisterAll(this.debugStickListener);
}
@@ -230,36 +171,9 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
return wrapped.id();
}
@Override
public Optional<List<ItemBehavior>> getItemBehavior(Key key) {
Optional<CustomItem<ItemStack>> customItemOptional = getCustomItem(key);
if (customItemOptional.isPresent()) {
CustomItem<ItemStack> customItem = customItemOptional.get();
Key vanillaMaterial = customItem.material();
List<ItemBehavior> behavior = VANILLA_ITEM_EXTRA_BEHAVIORS.get(vanillaMaterial);
if (behavior != null) {
return Optional.of(Stream.concat(customItem.behaviors().stream(), behavior.stream()).toList());
} else {
return Optional.of(List.copyOf(customItem.behaviors()));
}
} else {
List<ItemBehavior> behavior = VANILLA_ITEM_EXTRA_BEHAVIORS.get(key);
if (behavior != null) {
return Optional.of(List.copyOf(behavior));
} else {
return Optional.empty();
}
}
}
@Override
public Collection<Key> items() {
return new ArrayList<>(customItems.keySet());
}
@Override
public void parseSection(Pack pack, Path path, Key id, Map<String, Object> section) {
// just register and recipes
// just register for recipes
Holder.Reference<Key> holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(id)
.orElseGet(() -> ((WritableRegistry<Key>) BuiltInRegistries.OPTIMIZED_ITEM_ID)
.register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), id), id));
@@ -278,16 +192,26 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
CustomItem.Builder<ItemStack> itemBuilder = BukkitCustomItem.builder().id(id).material(materialId);
itemBuilder.modifier(new IdModifier<>(id));
boolean hasItemModelSection = section.containsKey("item-model");
// To get at least one model provider
// Sets some basic model info
if (customModelData != 0) {
itemBuilder.modifier(new CustomModelDataModifier<>(customModelData));
} else if (section.containsKey("model") && VersionHelper.isVersionNewerThan1_21_2()) {
}
// Requires the item to have model before apply item-model
else if (!hasItemModelSection && section.containsKey("model") && VersionHelper.isVersionNewerThan1_21_2()) {
// check server version here because components require 1.21.2+
// customize or use the id
itemModelKey = Key.from(section.getOrDefault("item-model", id.toString()).toString());
itemBuilder.modifier(new ItemModelModifier<>(itemModelKey));
}
if (hasItemModelSection) {
itemModelKey = Key.from(section.get("item-model").toString());
itemBuilder.modifier(new ItemModelModifier<>(itemModelKey));
}
// Get item behaviors
Object behaviorConfig = section.get("behavior");
if (behaviorConfig instanceof List<?>) {
@@ -328,12 +252,24 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
this.customItems.put(id, customItem);
this.cachedSuggestions.add(Suggestion.suggestion(id.toString()));
// regitser tags
// post process
// register tags
Set<Key> tags = customItem.settings().tags();
for (Key tag : tags) {
this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(holder);
}
// create trims
EquipmentGeneration equipment = customItem.settings().equipment();
if (equipment != null) {
EquipmentData modern = equipment.modernData();
// 1.21.2+
if (modern != null) {
this.equipmentsToGenerate.add(equipment);
}
// TODO 1.20
}
// model part, can be null
// but if it exists, either custom model data or item model should be configured
Map<String, Object> modelSection = MiscUtils.castToMap(section.get("model"), true);
@@ -341,7 +277,9 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
return;
}
boolean hasModel = false;
if (customModelData != 0) {
hasModel= true;
// use custom model data
// check conflict
Map<Integer, Key> conflict = this.cmdConflictChecker.computeIfAbsent(materialId, k -> new HashMap<>());
@@ -369,7 +307,9 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
TreeSet<LegacyOverridesModel> lom = this.legacyOverrides.computeIfAbsent(materialId, k -> new TreeSet<>());
lom.addAll(legacyOverridesModels);
}
} else if (itemModelKey != null) {
}
if (itemModelKey != null) {
hasModel = true;
// use components
ItemModel model = ItemModels.fromMap(modelSection);
for (ModelGeneration generation : model.modelsToGenerate()) {
@@ -390,36 +330,10 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
legacyOverridesModels.sort(LegacyOverridesModel::compareTo);
this.modernItemModels1_21_2.put(itemModelKey, legacyOverridesModels);
}
} else {
if (!VersionHelper.isVersionNewerThan1_21_2()) {
plugin.logger().warn(path, "No custom-model-data configured for " + id);
}
}
}
@Override
public Map<Key, ItemModel> modernItemModels1_21_4() {
return this.modernItemModels1_21_4;
}
@Override
public Map<Key, List<LegacyOverridesModel>> modernItemModels1_21_2() {
return this.modernItemModels1_21_2;
}
@Override
public Collection<Key> vanillaItems() {
return VANILLA_ITEMS;
}
@Override
public Map<Key, TreeSet<LegacyOverridesModel>> legacyItemOverrides() {
return this.legacyOverrides;
}
@Override
public Map<Key, TreeMap<Integer, ItemModel>> modernItemOverrides() {
return this.modernOverrides;
if (!hasModel) {
plugin.logger().warn(path, "No custom-model-data/item-model configured for " + id);
}
}
private void processModelRecursively(
@@ -603,7 +517,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
Set<Object> tags = (Set<Object>) Reflections.field$Holder$Reference$tags.get(mcHolder);
for (Object tag : tags) {
Key tagId = Key.of(Reflections.field$TagKey$location.get(tag).toString());
this.vanillaItemTags.computeIfAbsent(tagId, (key) -> new ArrayList<>()).add(holder);
VANILLA_ITEM_TAGS.computeIfAbsent(tagId, (key) -> new ArrayList<>()).add(holder);
}
}
}

View File

@@ -1,6 +1,6 @@
package net.momirealms.craftengine.core.block;
import net.momirealms.craftengine.core.pack.model.generator.AbstractModelGenerator;
import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator;
import net.momirealms.craftengine.core.plugin.CraftEngine;
public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager {

View File

@@ -2,8 +2,8 @@ package net.momirealms.craftengine.core.block;
import com.google.gson.JsonElement;
import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generator.ModelGenerator;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator;
import net.momirealms.craftengine.core.plugin.Reloadable;
import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser;
import net.momirealms.craftengine.core.util.Key;

View File

@@ -1,30 +1,64 @@
package net.momirealms.craftengine.core.item;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.modifier.*;
import net.momirealms.craftengine.core.pack.model.generator.AbstractModelGenerator;
import net.momirealms.craftengine.core.pack.LegacyOverridesModel;
import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration;
import net.momirealms.craftengine.core.pack.model.ItemModel;
import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.TypeUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.incendo.cloud.suggestion.Suggestion;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;
public abstract class AbstractItemManager<I> extends AbstractModelGenerator implements ItemManager<I> {
protected static final Map<Key, List<ItemBehavior>> VANILLA_ITEM_EXTRA_BEHAVIORS = new HashMap<>();
protected static final List<Key> VANILLA_ITEMS = new ArrayList<>();
protected static final Map<Key, List<Holder<Key>>> VANILLA_ITEM_TAGS = new HashMap<>();
protected final Map<String, Function<Object, ItemModifier<I>>> dataFunctions = new HashMap<>();
protected final Map<Key, CustomItem<I>> customItems = new HashMap<>();
protected final Map<Key, List<Holder<Key>>> customItemTags;
protected final Map<Key, Map<Integer, Key>> cmdConflictChecker;
protected final Map<Key, ItemModel> modernItemModels1_21_4;
protected final Map<Key, List<LegacyOverridesModel>> modernItemModels1_21_2;
protected final Map<Key, TreeSet<LegacyOverridesModel>> legacyOverrides;
protected final Map<Key, TreeMap<Integer, ItemModel>> modernOverrides;
protected final Set<EquipmentGeneration> equipmentsToGenerate;
// Cached command suggestions
protected final List<Suggestion> cachedSuggestions = new ArrayList<>();
private void registerDataFunction(Function<Object, ItemModifier<I>> function, String... alias) {
protected void registerDataFunction(Function<Object, ItemModifier<I>> function, String... alias) {
for (String a : alias) {
dataFunctions.put(a, function);
}
}
protected static void registerVanillaItemExtraBehavior(ItemBehavior behavior, Key... items) {
for (Key key : items) {
VANILLA_ITEM_EXTRA_BEHAVIORS.computeIfAbsent(key, k -> new ArrayList<>()).add(behavior);
}
}
@Override
public void unload() {
this.customItems.clear();
super.clearModelsToGenerate();
this.customItems.clear();
this.cachedSuggestions.clear();
this.legacyOverrides.clear();
this.modernOverrides.clear();
this.customItemTags.clear();
this.equipmentsToGenerate.clear();
this.cmdConflictChecker.clear();
this.modernItemModels1_21_4.clear();
this.modernItemModels1_21_2.clear();
}
@Override
@@ -35,6 +69,99 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
public AbstractItemManager(CraftEngine plugin) {
super(plugin);
this.registerFunctions();
this.legacyOverrides = new HashMap<>();
this.modernOverrides = new HashMap<>();
this.customItemTags = new HashMap<>();
this.cmdConflictChecker = new HashMap<>();
this.modernItemModels1_21_4 = new HashMap<>();
this.modernItemModels1_21_2 = new HashMap<>();
this.equipmentsToGenerate = new HashSet<>();
}
@Override
public List<Holder<Key>> tagToItems(Key tag) {
List<Holder<Key>> items = new ArrayList<>();
List<Holder<Key>> holders = VANILLA_ITEM_TAGS.get(tag);
if (holders != null) {
items.addAll(holders);
}
List<Holder<Key>> customItems = customItemTags.get(tag);
if (customItems != null) {
items.addAll(customItems);
}
return items;
}
@Override
public List<Holder<Key>> tagToVanillaItems(Key tag) {
return Collections.unmodifiableList(VANILLA_ITEM_TAGS.getOrDefault(tag, List.of()));
}
@Override
public List<Holder<Key>> tagToCustomItems(Key tag) {
return Collections.unmodifiableList(this.customItemTags.getOrDefault(tag, List.of()));
}
@Override
public Collection<Suggestion> cachedSuggestions() {
return Collections.unmodifiableCollection(this.cachedSuggestions);
}
@Override
public Optional<List<ItemBehavior>> getItemBehavior(Key key) {
Optional<CustomItem<I>> customItemOptional = getCustomItem(key);
if (customItemOptional.isPresent()) {
CustomItem<I> customItem = customItemOptional.get();
Key vanillaMaterial = customItem.material();
List<ItemBehavior> behavior = VANILLA_ITEM_EXTRA_BEHAVIORS.get(vanillaMaterial);
if (behavior != null) {
return Optional.of(Stream.concat(customItem.behaviors().stream(), behavior.stream()).toList());
} else {
return Optional.of(List.copyOf(customItem.behaviors()));
}
} else {
List<ItemBehavior> behavior = VANILLA_ITEM_EXTRA_BEHAVIORS.get(key);
if (behavior != null) {
return Optional.of(List.copyOf(behavior));
} else {
return Optional.empty();
}
}
}
@Override
public Collection<Key> items() {
return Collections.unmodifiableCollection(this.customItems.keySet());
}
@Override
public Map<Key, ItemModel> modernItemModels1_21_4() {
return Collections.unmodifiableMap(this.modernItemModels1_21_4);
}
@Override
public Map<Key, List<LegacyOverridesModel>> modernItemModels1_21_2() {
return Collections.unmodifiableMap(this.modernItemModels1_21_2);
}
@Override
public Collection<Key> vanillaItems() {
return Collections.unmodifiableCollection(VANILLA_ITEMS);
}
@Override
public Map<Key, TreeSet<LegacyOverridesModel>> legacyItemOverrides() {
return Collections.unmodifiableMap(this.legacyOverrides);
}
@Override
public Map<Key, TreeMap<Integer, ItemModel>> modernItemOverrides() {
return Collections.unmodifiableMap(this.modernOverrides);
}
@Override
public Collection<EquipmentGeneration> equipmentsToGenerate() {
return Collections.unmodifiableCollection(this.equipmentsToGenerate);
}
private void registerFunctions() {
@@ -64,6 +191,12 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
}
return new EnchantmentModifier<>(enchantments);
}, "enchantment", "enchantments", "enchant");
registerDataFunction((obj) -> {
Map<String, Object> data = MiscUtils.castToMap(obj, false);
String material = data.get("material").toString().toLowerCase(Locale.ENGLISH);
String pattern = data.get("pattern").toString().toLowerCase(Locale.ENGLISH);
return new TrimModifier<>(material, pattern);
}, "trim");
if (VersionHelper.isVersionNewerThan1_20_5()) {
registerDataFunction((obj) -> {
String name = obj.toString();
@@ -88,5 +221,11 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
return new TooltipStyleModifier<>(Key.of(id));
}, "tooltip-style");
}
if (VersionHelper.isVersionNewerThan1_21_2()) {
registerDataFunction((obj) -> {
Map<String, Object> data = MiscUtils.castToMap(obj, false);
return new EquippableModifier<>(EquipmentData.fromMap(data));
}, "equippable");
}
}
}

View File

@@ -18,4 +18,5 @@ public class ComponentKeys {
public static final String ITEM_MODEL = Key.key("minecraft", "item_model").asString();
public static final String TOOLTIP_STYLE = Key.key("minecraft", "tooltip_style").asString();
public static final String JUKEBOX_PLAYABLE = Key.key("minecraft", "jukebox_playable").asString();
public static final String TRIM = Key.key("minecraft", "trim").asString();
}

View File

@@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class EquipmentData {
@@ -22,7 +23,13 @@ public class EquipmentData {
@Nullable
private final Key cameraOverlay;
public EquipmentData(@NotNull EquipmentSlot slot, @Nullable Key assetId, boolean dispensable, boolean swappable, boolean damageOnHurt, boolean equipOnInteract, @Nullable Key cameraOverlay) {
public EquipmentData(@NotNull EquipmentSlot slot,
@Nullable Key assetId,
boolean dispensable,
boolean swappable,
boolean damageOnHurt,
boolean equipOnInteract,
@Nullable Key cameraOverlay) {
this.slot = slot;
this.assetId = assetId;
this.dispensable = dispensable;
@@ -32,6 +39,34 @@ public class EquipmentData {
this.cameraOverlay = cameraOverlay;
}
public static EquipmentData fromMap(@NotNull final Map<String, Object> data) {
String slot = (String) data.get("slot");
if (slot == null) {
throw new IllegalArgumentException("No `slot` option set for `equippable`");
}
EquipmentSlot slotEnum = EquipmentSlot.valueOf(slot.toUpperCase(Locale.ENGLISH));
EquipmentData.Builder builder = EquipmentData.builder().slot(slotEnum);
if (data.containsKey("asset-id")) {
builder.assetId(Key.of(data.get("asset-id").toString()));
}
if (data.containsKey("camera-overlay")) {
builder.cameraOverlay(Key.of(data.get("camera-overlay").toString()));
}
if (data.containsKey("dispensable")) {
builder.dispensable((boolean) data.get("dispensable"));
}
if (data.containsKey("swappable")) {
builder.swappable((boolean) data.get("swappable"));
}
if (data.containsKey("equip-on-interact")) {
builder.equipOnInteract((boolean) data.get("equip-on-interact"));
}
if (data.containsKey("damage-on-hurt")) {
builder.damageOnHurt((boolean) data.get("damage-on-hurt"));
}
return builder.build();
}
public EquipmentSlot slot() {
return slot;
}
@@ -62,7 +97,7 @@ public class EquipmentData {
public Map<String, Object> toMap() {
Map<String, Object> map = new HashMap<>();
map.put("slot", this.slot.toString());
map.put("slot", this.slot.toString().toLowerCase(Locale.ENGLISH));
if (this.assetId != null) {
map.put("asset_id", this.assetId.toString());
}

View File

@@ -4,8 +4,9 @@ import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.pack.LegacyOverridesModel;
import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration;
import net.momirealms.craftengine.core.pack.model.ItemModel;
import net.momirealms.craftengine.core.pack.model.generator.ModelGenerator;
import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator;
import net.momirealms.craftengine.core.plugin.Reloadable;
import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser;
import net.momirealms.craftengine.core.registry.Holder;
@@ -26,6 +27,8 @@ public interface ItemManager<T> extends Reloadable, ModelGenerator, ConfigSectio
Map<Key, TreeMap<Integer, ItemModel>> modernItemOverrides();
Collection<EquipmentGeneration> equipmentsToGenerate();
Map<Key, ItemModel> modernItemModels1_21_4();
Map<Key, List<LegacyOverridesModel>> modernItemModels1_21_2();

View File

@@ -1,10 +1,11 @@
package net.momirealms.craftengine.core.item;
import net.momirealms.craftengine.core.entity.EquipmentSlot;
import net.momirealms.craftengine.core.item.modifier.EquippableModifier;
import net.momirealms.craftengine.core.item.modifier.ItemModifier;
import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -14,13 +15,15 @@ public class ItemSettings {
int fuelTime;
Set<Key> tags = Set.of();
@Nullable
EquipmentData equipmentData;
EquipmentGeneration equipment;
private ItemSettings() {}
public <I> List<ItemModifier<I>> modifiers() {
if (this.equipmentData == null) return Collections.emptyList();
return List.of(new EquippableModifier<>(this.equipmentData));
ArrayList<ItemModifier<I>> modifiers = new ArrayList<>();
if (VersionHelper.isVersionNewerThan1_21_2() && this.equipment != null && this.equipment.modernData() != null) modifiers.add(new EquippableModifier<>(this.equipment.modernData()));
return modifiers;
}
public static ItemSettings of() {
@@ -35,7 +38,7 @@ public class ItemSettings {
ItemSettings newSettings = of();
newSettings.fuelTime = settings.fuelTime;
newSettings.tags = settings.tags;
newSettings.equipmentData = settings.equipmentData;
newSettings.equipment = settings.equipment;
return newSettings;
}
@@ -60,8 +63,8 @@ public class ItemSettings {
}
@Nullable
public EquipmentData equipmentData() {
return equipmentData;
public EquipmentGeneration equipment() {
return equipment;
}
public ItemSettings fuelTime(int fuelTime) {
@@ -74,8 +77,8 @@ public class ItemSettings {
return this;
}
public ItemSettings equipmentData(EquipmentData equipmentData) {
this.equipmentData = equipmentData;
public ItemSettings equipment(EquipmentGeneration equipment) {
this.equipment = equipment;
return this;
}
@@ -104,20 +107,21 @@ public class ItemSettings {
return settings -> settings.tags(tags.stream().map(Key::of).collect(Collectors.toSet()));
}));
registerFactory("equippable", (value -> {
Map<String, Object> data = MiscUtils.castToMap(value, false);
String slot = (String) data.get("slot");
if (slot == null) {
throw new IllegalArgumentException("No slot specified");
}
EquipmentSlot slotEnum = EquipmentSlot.valueOf(slot.toUpperCase(Locale.ENGLISH));
EquipmentData.Builder builder = EquipmentData.builder().slot(slotEnum);
if (data.containsKey("asset-id")) {
builder.assetId(Key.of(data.get("asset-id").toString()));
}
if (data.containsKey("camera-overlay")) {
builder.cameraOverlay(Key.of(data.get("camera-overlay").toString()));
}
return settings -> settings.equipmentData(builder.build());
Map<String, Object> args = MiscUtils.castToMap(value, false);
EquipmentData data;
if (VersionHelper.isVersionNewerThan1_21_2() && args.containsKey("slot")) data = EquipmentData.fromMap(args);
else data = null;
EquipmentGeneration equipment = new EquipmentGeneration(
EquipmentGeneration.Layer.fromConfig(args.get("humanoid")),
EquipmentGeneration.Layer.fromConfig(args.get("humanoid-leggings")),
EquipmentGeneration.Layer.fromConfig(args.get("llama-body")),
EquipmentGeneration.Layer.fromConfig(args.get("horse-body")),
EquipmentGeneration.Layer.fromConfig(args.get("wolf-body")),
EquipmentGeneration.Layer.fromConfig(args.get("wings")),
data,
MiscUtils.getAsInt(args.getOrDefault("trim", -1))
);
return settings -> settings.equipment(equipment);
}));
}

View File

@@ -0,0 +1,36 @@
package net.momirealms.craftengine.core.item.modifier;
import net.momirealms.craftengine.core.item.ComponentKeys;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.util.VersionHelper;
import java.util.Map;
public class TrimModifier<I> implements ItemModifier<I> {
private final String material;
private final String pattern;
public TrimModifier(String material, String pattern) {
this.material = material;
this.pattern = pattern;
}
@Override
public String name() {
return "trim";
}
@Override
public void apply(Item<I> item, ItemBuildContext context) {
if (VersionHelper.isVersionNewerThan1_20_5()) {
item.setComponent(ComponentKeys.TRIM, Map.of(
"pattern", this.pattern,
"material", this.material
));
} else {
item.setTag(this.material, "Trim", "material");
item.setTag(this.pattern, "Trim", "pattern");
}
}
}

View File

@@ -8,12 +8,14 @@ import dev.dejvokep.boostedyaml.YamlDocument;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.craftengine.core.font.BitmapImage;
import net.momirealms.craftengine.core.font.Font;
import net.momirealms.craftengine.core.item.EquipmentData;
import net.momirealms.craftengine.core.pack.conflict.resolution.ConditionalResolution;
import net.momirealms.craftengine.core.pack.host.HostMode;
import net.momirealms.craftengine.core.pack.host.ResourcePackHost;
import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration;
import net.momirealms.craftengine.core.pack.model.ItemModel;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generator.ModelGenerator;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator;
import net.momirealms.craftengine.core.pack.obfuscation.ObfA;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.PluginProperties;
@@ -237,6 +239,8 @@ public abstract class AbstractPackManager implements PackManager {
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow_pulling_1.png");
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow_pulling_2.png");
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow.png");
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/entity/equipment/humanoid/topaz.png");
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/entity/equipment/humanoid_leggings/topaz.png");
for (String item : List.of("helmet", "chestplate", "leggings", "boots", "pickaxe", "axe", "sword", "hoe", "shovel")) {
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_" + item + ".png");
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_" + item + ".png.mcmeta");
@@ -403,6 +407,7 @@ public abstract class AbstractPackManager implements PackManager {
this.generateOverrideSounds(generatedPackPath);
this.generateCustomSounds(generatedPackPath);
this.generateClientLang(generatedPackPath);
this.generateEquipments(generatedPackPath);
Path zipFile = resourcePackPath();
try {
@@ -433,6 +438,45 @@ public abstract class AbstractPackManager implements PackManager {
}
}
private void generateEquipments(Path generatedPackPath) {
for (EquipmentGeneration generator : this.plugin.itemManager().equipmentsToGenerate()) {
EquipmentData equipmentData = generator.modernData();
if (equipmentData != null && ConfigManager.packMaxVersion() >= 21.2f) {
Path equipmentPath = generatedPackPath
.resolve("assets")
.resolve(equipmentData.assetId().namespace())
.resolve("equipment")
.resolve(equipmentData.assetId().value() + ".json");
JsonObject equipmentJson = null;
if (Files.exists(equipmentPath)) {
try (BufferedReader reader = Files.newBufferedReader(equipmentPath)) {
equipmentJson = JsonParser.parseReader(reader).getAsJsonObject();
} catch (IOException e) {
plugin.logger().warn("Failed to load existing sounds.json", e);
return;
}
}
if (equipmentJson != null) {
equipmentJson = GsonHelper.deepMerge(equipmentJson, generator.get());
} else {
equipmentJson = generator.get();
}
try {
Files.createDirectories(equipmentPath.getParent());
} catch (IOException e) {
plugin.logger().severe("Error creating " + equipmentPath.toAbsolutePath());
return;
}
try {
GsonHelper.writeJsonFile(equipmentJson, equipmentPath);
} catch (IOException e) {
this.plugin.logger().severe("Error writing equipment file", e);
}
}
}
}
private void generateClientLang(Path generatedPackPath) {
for (Map.Entry<String, I18NData> entry : this.plugin.translationManager().clientLangManager().langData().entrySet()) {
JsonObject json = new JsonObject();

View File

@@ -0,0 +1,140 @@
package net.momirealms.craftengine.core.pack.misc;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.item.EquipmentData;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
public class EquipmentGeneration implements Supplier<JsonObject> {
private final List<Layer> humanoid;
private final List<Layer> humanoidLeggings;
private final List<Layer> llamaBody;
private final List<Layer> horseBody;
private final List<Layer> wolfBody;
private final List<Layer> wings;
private final EquipmentData modernData;
private final int trim;
public EquipmentGeneration(List<Layer> humanoid,
List<Layer> humanoidLeggings,
List<Layer> llamaBody,
List<Layer> horseBody,
List<Layer> wolfBody,
List<Layer> wings,
EquipmentData modernData,
int trim) {
this.humanoid = humanoid;
this.humanoidLeggings = humanoidLeggings;
this.llamaBody = llamaBody;
this.horseBody = horseBody;
this.wolfBody = wolfBody;
this.wings = wings;
this.trim = trim;
this.modernData = modernData;
}
public EquipmentData modernData() {
return modernData;
}
public int trim() {
return trim;
}
public List<Layer> humanoid() {
return humanoid;
}
public List<Layer> humanoidLeggings() {
return humanoidLeggings;
}
public List<Layer> llamaBody() {
return llamaBody;
}
public List<Layer> horseBody() {
return horseBody;
}
public List<Layer> wolfBody() {
return wolfBody;
}
public List<Layer> wings() {
return wings;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (!(object instanceof EquipmentGeneration that)) return false;
return trim == that.trim && Objects.equals(humanoid, that.humanoid) && Objects.equals(humanoidLeggings, that.humanoidLeggings) && Objects.equals(llamaBody, that.llamaBody) && Objects.equals(horseBody, that.horseBody) && Objects.equals(wolfBody, that.wolfBody) && Objects.equals(wings, that.wings) && Objects.equals(modernData, that.modernData);
}
@Override
public int hashCode() {
return Objects.hash(humanoid, humanoidLeggings, llamaBody, horseBody, wolfBody, wings, modernData, trim);
}
@Override
public JsonObject get() {
JsonObject jsonObject = new JsonObject();
JsonObject layersJson = new JsonObject();
jsonObject.add("layers", layersJson);
setLayerJson(layersJson, humanoid(), "humanoid");
setLayerJson(layersJson, humanoidLeggings(), "humanoid_leggings");
setLayerJson(layersJson, llamaBody(), "llama_body");
setLayerJson(layersJson, horseBody(), "horse_body");
setLayerJson(layersJson, wolfBody(), "wolf_body");
setLayerJson(layersJson, wings(), "wings");
return jsonObject;
}
private void setLayerJson(JsonObject layersJson, List<Layer> layers, String key) {
if (layers.isEmpty()) return;
JsonArray layersArray = new JsonArray();
for (Layer layer : layers) {
layersArray.add(layer.get());
}
layersJson.add(key, layersArray);
}
public record Layer(String texture, boolean dyeable) implements Supplier<JsonObject> {
@NotNull
public static List<Layer> fromConfig(Object obj) {
if (obj instanceof String texture) {
return List.of(new Layer(texture, false));
} else if (obj instanceof Map<?, ?> map) {
String texture = map.get("texture").toString();
return List.of(new Layer(texture, map.containsKey("dyeable")));
} else if (obj instanceof List<?> list) {
List<Layer> layers = new ArrayList<>();
for (Object inner : list) {
layers.addAll(fromConfig(inner));
}
return layers;
} else {
return List.of();
}
}
@Override
public JsonObject get() {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("texture", texture);
if (dyeable) {
jsonObject.add("dyeable", new JsonObject());
}
return jsonObject;
}
}
}

View File

@@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.pack.model;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.tint.Tint;
import net.momirealms.craftengine.core.pack.model.tint.Tints;
import net.momirealms.craftengine.core.util.Key;

View File

@@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.pack.model;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.util.Key;
import java.util.ArrayList;

View File

@@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.pack.model;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.pack.model.condition.ConditionProperties;
import net.momirealms.craftengine.core.pack.model.condition.ConditionProperty;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.util.Key;
import java.util.ArrayList;

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.core.pack.model;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.util.Key;
import java.util.List;

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.core.pack.model;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.util.Key;
import java.util.List;

View File

@@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.pack.model;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.rangedisptach.RangeDispatchProperties;
import net.momirealms.craftengine.core.pack.model.rangedisptach.RangeDispatchProperty;
import net.momirealms.craftengine.core.util.Key;

View File

@@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.pack.model;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.select.SelectProperties;
import net.momirealms.craftengine.core.pack.model.select.SelectProperty;
import net.momirealms.craftengine.core.util.Key;

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.core.pack.model;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.pack.model.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.pack.model.special.SpecialModel;
import net.momirealms.craftengine.core.pack.model.special.SpecialModels;
import net.momirealms.craftengine.core.util.Key;

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.pack.model.generator;
package net.momirealms.craftengine.core.pack.model.generation;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.Key;

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.pack.model.generator;
package net.momirealms.craftengine.core.pack.model.generation;
import com.google.gson.JsonObject;
import dev.dejvokep.boostedyaml.block.implementation.Section;

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.pack.model.generator;
package net.momirealms.craftengine.core.pack.model.generation;
import java.util.Collection;

View File

@@ -1,6 +1,6 @@
# Project settings
# Rule: [major update].[feature update].[bug fix]
project_version=0.0.31
project_version=0.0.32
config_version=12
lang_version=2
project_group=net.momirealms