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

重构配方前

This commit is contained in:
XiaoMoMi
2025-07-30 15:51:45 +08:00
parent 29b5d48809
commit 4947b47310
22 changed files with 416 additions and 96 deletions

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.logger.Debugger;
import net.momirealms.craftengine.core.util.Color;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.NBT;
@@ -49,8 +50,8 @@ public class FurnitureExtraData {
return Optional.empty();
}
public Optional<Integer> dyedColor() {
if (this.data.containsKey(DYED_COLOR)) return Optional.of(this.data.getInt(DYED_COLOR));
public Optional<Color> dyedColor() {
if (this.data.containsKey(DYED_COLOR)) return Optional.of(Color.fromDecimal(this.data.getInt(DYED_COLOR)));
return Optional.empty();
}
@@ -92,9 +93,9 @@ public class FurnitureExtraData {
return this;
}
public Builder dyedColor(Integer color) {
public Builder dyedColor(Color color) {
if (color == null) return this;
this.data.putInt(DYED_COLOR, color);
this.data.putInt(DYED_COLOR, color.color());
return this;
}

View File

@@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.item.data.FireworkExplosion;
import net.momirealms.craftengine.core.item.data.JukeboxPlayable;
import net.momirealms.craftengine.core.item.data.Trim;
import net.momirealms.craftengine.core.item.setting.EquipmentData;
import net.momirealms.craftengine.core.util.Color;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.UniqueKey;
import net.momirealms.sparrow.nbt.Tag;
@@ -107,13 +108,13 @@ public class AbstractItem<W extends ItemWrapper<I>, I> implements Item<I> {
}
@Override
public Item<I> dyedColor(Integer data) {
public Item<I> dyedColor(Color data) {
this.factory.dyedColor(this.item, data);
return this;
}
@Override
public Optional<Integer> dyedColor() {
public Optional<Color> dyedColor() {
return this.factory.dyedColor(this.item);
}
@@ -473,4 +474,14 @@ public class AbstractItem<W extends ItemWrapper<I>, I> implements Item<I> {
public void shrink(int amount) {
this.item.shrink(amount);
}
@Override
public boolean isDyeItem() {
return this.factory.isDyeItem(this.item);
}
@Override
public Optional<Color> dyeColor() {
return this.factory.dyeColor(this.item);
}
}

View File

@@ -548,10 +548,10 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
}, "dynamic-lore");
registerDataType((obj) -> {
if (obj instanceof Integer integer) {
return new DyedColorModifier<>(integer);
return new DyedColorModifier<>(Color.fromDecimal(integer));
} else {
Vector3f vector3f = MiscUtils.getAsVector3f(obj, "dyed-color");
return new DyedColorModifier<>(0 << 24 /*不可省略*/ | MCUtils.fastFloor(vector3f.x) << 16 | MCUtils.fastFloor(vector3f.y) << 8 | MCUtils.fastFloor(vector3f.z));
return new DyedColorModifier<>(Color.fromVector3f(vector3f));
}
}, "dyed-color");
registerDataType((obj) -> {

View File

@@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.item.data.JukeboxPlayable;
import net.momirealms.craftengine.core.item.data.Trim;
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
import net.momirealms.craftengine.core.item.setting.EquipmentData;
import net.momirealms.craftengine.core.util.Color;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.UniqueKey;
import net.momirealms.sparrow.nbt.Tag;
@@ -69,9 +70,10 @@ public interface Item<I> {
int maxDamage();
Item<I> dyedColor(Integer data);
// todo 考虑部分版本的show in tooltip保留
Item<I> dyedColor(Color data);
Optional<Integer> dyedColor();
Optional<Color> dyedColor();
Item<I> fireworkExplosion(FireworkExplosion explosion);
@@ -208,4 +210,8 @@ public interface Item<I> {
}
byte[] toByteArray();
boolean isDyeItem();
Optional<Color> dyeColor();
}

View File

@@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.item.data.Trim;
import net.momirealms.craftengine.core.item.setting.EquipmentData;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.AdventureHelper;
import net.momirealms.craftengine.core.util.Color;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.UniqueKey;
import net.momirealms.sparrow.nbt.Tag;
@@ -135,9 +136,9 @@ public abstract class ItemFactory<W extends ItemWrapper<I>, I> {
protected abstract void damage(W item, Integer damage);
protected abstract Optional<Integer> dyedColor(W item);
protected abstract Optional<Color> dyedColor(W item);
protected abstract void dyedColor(W item, Integer color);
protected abstract void dyedColor(W item, Color color);
protected abstract int maxDamage(W item);
@@ -210,4 +211,8 @@ public abstract class ItemFactory<W extends ItemWrapper<I>, I> {
protected abstract boolean isEmpty(W item);
protected abstract UniqueKey recipeIngredientID(W item);
protected abstract boolean isDyeItem(W item);
protected abstract Optional<Color> dyeColor(W item);
}

View File

@@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.item;
import net.momirealms.craftengine.core.util.Key;
public class ItemKeys {
public final class ItemKeys {
public static final Key AIR = Key.of("minecraft:air");
public static final Key FLINT_AND_STEEL = Key.of("minecraft:flint_and_steel");
public static final Key STONE = Key.of("minecraft:stone");
@@ -44,6 +44,22 @@ public class ItemKeys {
public static final Key GLOWSTONE = Key.of("minecraft:glowstone");
public static final Key SADDLE = Key.of("minecraft:saddle");
public static final Key HARNESS = Key.of("minecraft:harness");
public static final Key WHITE_DYE = Key.of("minecraft:white_dye");
public static final Key ORANGE_DYE = Key.of("minecraft:orange_dye");
public static final Key MAGENTA_DYE = Key.of("minecraft:magenta_dye");
public static final Key LIGHT_BLUE_DYE = Key.of("minecraft:light_blue_dye");
public static final Key YELLOW_DYE = Key.of("minecraft:yellow_dye");
public static final Key LIME_DYE = Key.of("minecraft:lime_dye");
public static final Key PINK_DYE = Key.of("minecraft:pink_dye");
public static final Key GRAY_DYE = Key.of("minecraft:gray_dye");
public static final Key LIGHT_GRAY_DYE = Key.of("minecraft:light_gray_dye");
public static final Key CYAN_DYE = Key.of("minecraft:cyan_dye");
public static final Key PURPLE_DYE = Key.of("minecraft:purple_dye");
public static final Key BLUE_DYE = Key.of("minecraft:blue_dye");
public static final Key BROWN_DYE = Key.of("minecraft:brown_dye");
public static final Key GREEN_DYE = Key.of("minecraft:green_dye");
public static final Key RED_DYE = Key.of("minecraft:red_dye");
public static final Key BLACK_DYE = Key.of("minecraft:black_dye");
public static final Key[] AXES = new Key[] {
WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE

View File

@@ -30,7 +30,7 @@ public class ItemSettings {
boolean renameable = true;
boolean canPlaceRelatedVanillaBlock = false;
ProjectileMeta projectileMeta;
boolean dyeable = true;
Tristate dyeable = Tristate.UNDEFINED;
Helmet helmet = null;
FoodData foodData = null;
Key consumeReplacement = null;
@@ -41,6 +41,8 @@ public class ItemSettings {
boolean respectRepairableComponent = false;
@Nullable
ItemEquipment equipment;
@Nullable
Color dyeColor;
private ItemSettings() {}
@@ -99,6 +101,7 @@ public class ItemSettings {
newSettings.canEnchant = settings.canEnchant;
newSettings.compostProbability = settings.compostProbability;
newSettings.respectRepairableComponent = settings.respectRepairableComponent;
newSettings.dyeColor = settings.dyeColor;
return newSettings;
}
@@ -138,7 +141,7 @@ public class ItemSettings {
return tags;
}
public boolean dyeable() {
public Tristate dyeable() {
return dyeable;
}
@@ -179,6 +182,11 @@ public class ItemSettings {
return equipment;
}
@Nullable
public Color dyeColor() {
return dyeColor;
}
public List<DamageSource> invulnerable() {
return invulnerable;
}
@@ -187,6 +195,11 @@ public class ItemSettings {
return compostProbability;
}
public ItemSettings dyeColor(Color color) {
this.dyeColor = color;
return this;
}
public ItemSettings repairItems(List<AnvilRepairItem> items) {
this.anvilRepairItems = items;
return this;
@@ -252,7 +265,7 @@ public class ItemSettings {
return this;
}
public ItemSettings dyeable(boolean bool) {
public ItemSettings dyeable(Tristate bool) {
this.dyeable = bool;
return this;
}
@@ -390,12 +403,19 @@ public class ItemSettings {
}));
registerFactory("dyeable", (value -> {
boolean bool = ResourceConfigUtils.getAsBoolean(value, "dyeable");
return settings -> settings.dyeable(bool);
return settings -> settings.dyeable(bool ? Tristate.TRUE : Tristate.FALSE);
}));
registerFactory("respect-repairable-component", (value -> {
boolean bool = ResourceConfigUtils.getAsBoolean(value, "respect-repairable-component");
return settings -> settings.respectRepairableComponent(bool);
}));
registerFactory("dye-color", (value -> {
if (value instanceof Integer i) {
return settings -> settings.dyeColor(Color.fromDecimal(i));
} else {
return settings -> settings.dyeColor(Color.fromVector3f(MiscUtils.getAsVector3f(value, "dye-color")));
}
}));
registerFactory("food", (value -> {
Map<String, Object> args = MiscUtils.castToMap(value, false);
FoodData data = new FoodData(

View File

@@ -4,14 +4,15 @@ 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.item.NetworkItemHandler;
import net.momirealms.craftengine.core.util.Color;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.Tag;
public class DyedColorModifier<I> implements ItemDataModifier<I> {
private final int color;
private final Color color;
public DyedColorModifier(int color) {
public DyedColorModifier(Color color) {
this.color = color;
}

View File

@@ -0,0 +1,159 @@
package net.momirealms.craftengine.core.item.recipe;
import net.momirealms.craftengine.core.item.CustomItem;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.recipe.input.CraftingInput;
import net.momirealms.craftengine.core.item.recipe.input.RecipeInput;
import net.momirealms.craftengine.core.util.Color;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.Tristate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class CustomDyeRecipe<T> implements Recipe<T> {
public static final Key ID = Key.of("armor_dye");
private static final Key DYEABLE = Key.of("dyeable");
public CustomDyeRecipe() {
}
@SuppressWarnings("unchecked")
@Override
public T assemble(RecipeInput input, ItemBuildContext context) {
List<Color> colors = new ArrayList<>();
CraftingInput<T> craftingInput = (CraftingInput<T>) input;
Item<T> itemToDye = null;
for (UniqueIdItem<T> uniqueIdItem : craftingInput) {
if (uniqueIdItem.isEmpty()) {
continue;
}
if (isDyeable(uniqueIdItem)) {
itemToDye = uniqueIdItem.item().copyWithCount(1);
} else {
Color dyeColor = getDyeColor(uniqueIdItem);
if (dyeColor != null) {
colors.add(dyeColor);
} else {
return null;
}
}
}
if (itemToDye == null || itemToDye.isEmpty() || colors.isEmpty()) {
return null;
}
return applyDyes(itemToDye, colors).getItem();
}
private Item<T> applyDyes(Item<T> item, List<Color> colors) {
int totalRed = 0;
int totalGreen = 0;
int totalBlue = 0;
int totalMaxComponent = 0;
int colorCount = 0;
Optional<Color> existingColor = item.dyedColor();
existingColor.ifPresent(colors::add);
for (Color color : colors) {
int dyeRed = color.r();
int dyeGreen = color.g();
int dyeBlue = color.b();
totalMaxComponent += Math.max(dyeRed, Math.max(dyeGreen, dyeBlue));
totalRed += dyeRed;
totalGreen += dyeGreen;
totalBlue += dyeBlue;
++colorCount;
}
int avgRed = totalRed / colorCount;
int avgGreen = totalGreen / colorCount;
int avgBlue = totalBlue / colorCount;
float avgMaxComponent = (float) totalMaxComponent / (float)colorCount;
float currentMaxComponent = (float) Math.max(avgRed, Math.max(avgGreen, avgBlue));
avgRed = (int) ((float) avgRed * avgMaxComponent / currentMaxComponent);
avgGreen = (int) ((float) avgGreen * avgMaxComponent / currentMaxComponent);
avgBlue = (int) ((float) avgBlue * avgMaxComponent / currentMaxComponent);
Color finalColor = new Color(0, avgRed, avgGreen, avgBlue);
return item.dyedColor(finalColor);
}
@SuppressWarnings("unchecked")
@Override
public boolean matches(RecipeInput input) {
CraftingInput<T> craftingInput = (CraftingInput<T>) input;
if (craftingInput.ingredientCount() < 2) {
return false;
}
boolean hasItemToDye = false;
boolean hasDye = false;
for(int i = 0; i < craftingInput.size(); ++i) {
UniqueIdItem<T> item = craftingInput.getItem(i);
if (!item.isEmpty()) {
if (isDyeable(item)) {
if (hasItemToDye) {
return false;
}
hasItemToDye = true;
} else {
if (!isDye(item)) {
return false;
}
hasDye = true;
}
}
}
return hasDye && hasItemToDye;
}
private boolean isDyeable(final UniqueIdItem<T> item) {
Optional<CustomItem<T>> optionalCustomItem = item.item().getCustomItem();
if (optionalCustomItem.isPresent()) {
CustomItem<T> customItem = optionalCustomItem.get();
if (customItem.settings().dyeable() == Tristate.FALSE) {
return false;
}
if (customItem.settings().dyeable() == Tristate.TRUE) {
return true;
}
}
return item.item().is(DYEABLE);
}
private boolean isDye(final UniqueIdItem<T> item) {
Item<T> dyeItem = item.item();
Optional<CustomItem<T>> optionalCustomItem = item.item().getCustomItem();
if (optionalCustomItem.isPresent()) {
CustomItem<T> customItem = optionalCustomItem.get();
return customItem.settings().dyeColor() != null || dyeItem.isDyeItem();
}
return dyeItem.isDyeItem();
}
@Nullable
private Color getDyeColor(final UniqueIdItem<T> item) {
Item<T> dyeItem = item.item();
Optional<CustomItem<T>> optionalCustomItem = item.item().getCustomItem();
if (optionalCustomItem.isPresent()) {
CustomItem<T> customItem = optionalCustomItem.get();
return Optional.ofNullable(customItem.settings().dyeColor()).orElseGet(() -> dyeItem.dyeColor().orElse(null));
}
return dyeItem.dyeColor().orElse(null);
}
@Override
public List<Ingredient<T>> ingredientsInUse() {
return List.of();
}
@Override
public @NotNull Key type() {
return RecipeTypes.SPECIAL;
}
@Override
public Key id() {
return ID;
}
}

View File

@@ -21,6 +21,7 @@ public class RecipeTypes {
public static final Key SMITHING_TRANSFORM = Key.of("minecraft:smithing_transform");
public static final Key SMITHING_TRIM = Key.of("minecraft:smithing_trim");
public static final Key BREWING = Key.of("minecraft:brewing");
public static final Key SPECIAL = Key.of("minecraft:special");
static {
register(SHAPED, CustomShapedRecipe.FACTORY);

View File

@@ -2,12 +2,14 @@ package net.momirealms.craftengine.core.item.recipe.input;
import net.momirealms.craftengine.core.item.recipe.RecipeFinder;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public final class CraftingInput<T> implements RecipeInput {
public final class CraftingInput<T> implements RecipeInput, Iterable<UniqueIdItem<T>> {
private final int width;
private final int height;
private final List<UniqueIdItem<T>> items;
@@ -99,4 +101,9 @@ public final class CraftingInput<T> implements RecipeInput {
public UniqueIdItem<T> getItem(int index) {
return this.items.get(index);
}
@Override
public @NotNull Iterator<UniqueIdItem<T>> iterator() {
return this.items.iterator();
}
}

View File

@@ -38,7 +38,7 @@ public class ParticleFunction<CTX extends Context> extends AbstractConditionalFu
})),
ParticleTypes.BLOCK, ParticleTypes.FALLING_DUST, ParticleTypes.DUST_PILLAR, ParticleTypes.BLOCK_CRUMBLE, ParticleTypes.BLOCK_MARKER);
registerParticleData(map -> new ColorData(
Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(","))),
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(","))),
ParticleTypes.ENTITY_EFFECT, ParticleTypes.TINTED_LEAVES);
registerParticleData(map -> new JavaTypeData(
ResourceConfigUtils.getAsFloat(map.get("charge"), "charge")),
@@ -47,12 +47,12 @@ public class ParticleFunction<CTX extends Context> extends AbstractConditionalFu
ResourceConfigUtils.getAsInt(map.get("shriek"), "shriek")),
ParticleTypes.SHRIEK);
registerParticleData(map -> new DustData(
Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")),
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")),
ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")),
ParticleTypes.DUST);
registerParticleData(map -> new DustTransitionData(
Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("from"), "warning.config.function.particle.missing_from").split(",")),
Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("to"), "warning.config.function.particle.missing_to").split(",")),
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("from"), "warning.config.function.particle.missing_from").split(",")),
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("to"), "warning.config.function.particle.missing_to").split(",")),
ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")),
ParticleTypes.DUST_COLOR_TRANSITION);
registerParticleData(map -> new ItemStackData(
@@ -75,7 +75,7 @@ public class ParticleFunction<CTX extends Context> extends AbstractConditionalFu
NumberProviders.fromObject(map.getOrDefault("target-x", 0)),
NumberProviders.fromObject(map.getOrDefault("target-y", 0)),
NumberProviders.fromObject(map.getOrDefault("target-z", 0)),
Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")),
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")),
NumberProviders.fromObject(map.getOrDefault("duration", 10))),
ParticleTypes.TRAIL);
}

View File

@@ -1,52 +1,95 @@
package net.momirealms.craftengine.core.util;
import org.joml.Vector3f;
import java.util.Arrays;
public class Color {
private static final int BIT_MASK = 0xff;
private static final byte DEFAULT_ALPHA = (byte) 255;
private final byte r;
private final byte g;
private final byte b;
private final byte a;
private final int color;
public Color(byte r, byte g, byte b, byte a) {
this.b = b;
this.g = g;
this.r = r;
this.a = a;
public Color(int color) {
this.color = color;
}
public Color(byte r, byte g, byte b) {
this(r, g, b, DEFAULT_ALPHA);
public Color(int r, int g, int b) {
this(DEFAULT_ALPHA, r, g, b);
}
public int toDecimal() {
return DEFAULT_ALPHA << 24 | (r << 16) | (g << 8) | b;
public Color(int a, int r, int g, int b) {
this(toDecimal(a, r, g, b));
}
public static Color fromString(String[] strings) {
public int color() {
return color;
}
public static int toDecimal(int a, int r, int g, int b) {
return a << 24 | r << 16 | g << 8 | b;
}
public static int toDecimal(int r, int g, int b) {
return DEFAULT_ALPHA << 24 | r << 16 | g << 8 | b;
}
public static Color fromDecimal(int decimal) {
return new Color(decimal);
}
public static Color fromVector3f(Vector3f vec) {
return new Color(0 << 24 /*不可省略*/ | MCUtils.fastFloor(vec.x) << 16 | MCUtils.fastFloor(vec.y) << 8 | MCUtils.fastFloor(vec.z));
}
public static int opaque(int color) {
return color | -16777216;
}
public static int transparent(int color) {
return color & 16777215;
}
public static int alpha(int color) {
return color >>> 24;
}
public static int red(int color) {
return color >> 16 & BIT_MASK;
}
public static int green(int color) {
return color >> 8 & BIT_MASK;
}
public static int blue(int color) {
return color & BIT_MASK;
}
public static Color fromStrings(String[] strings) {
if (strings.length == 3) {
return new Color(Byte.parseByte(strings[0]), Byte.parseByte(strings[1]), Byte.parseByte(strings[2]));
// rgb
return fromDecimal(toDecimal(Integer.parseInt(strings[0]), Integer.parseInt(strings[1]), Integer.parseInt(strings[2])));
} else if (strings.length == 4) {
return new Color(Byte.parseByte(strings[0]), Byte.parseByte(strings[1]), Byte.parseByte(strings[2]), Byte.parseByte(strings[3]));
// argb
return fromDecimal(toDecimal(Integer.parseInt(strings[0]), Integer.parseInt(strings[1]), Integer.parseInt(strings[2]), Integer.parseInt(strings[3])));
} else {
throw new IllegalArgumentException("Invalid color format: " + Arrays.toString(strings));
}
}
public byte a() {
return a;
public int a() {
return alpha(color);
}
public byte b() {
return b;
public int b() {
return blue(color);
}
public byte g() {
return g;
public int g() {
return green(color);
}
public byte r() {
return r;
public int r() {
return red(color);
}
}