From 7f98d25f257231c93e530dc91e5e80b3a82cd12e Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Fri, 14 Mar 2025 05:18:33 +0300 Subject: [PATCH 01/55] initial work towards custom items --- .../spongetools/codec/MathCodecs.java | 153 +++++++++ .../codec/StringRepresentableCodec.java | 8 +- .../custom/item/model/ChargeType.java | 28 ++ .../custom/item/model/CompassTarget.java | 27 ++ .../item/model/ConditionalProperty.java | 208 ++++++++++++ .../custom/item/model/GuiLight.java | 26 ++ .../custom/item/model/ItemDisplayContext.java | 33 ++ .../custom/item/model/ItemModel.java | 128 +++++++ .../item/model/ItemModelDefinition.java | 270 +++++++++++++++ .../custom/item/model/ItemTintSource.java | 205 ++++++++++++ .../custom/item/model/ItemTransforms.java | 85 +++++ .../custom/item/model/ModelTemplate.java | 236 +++++++++++++ .../custom/item/model/RangeSelectEntry.java | 19 ++ .../item/model/RangeSelectProperty.java | 255 ++++++++++++++ .../custom/item/model/SelectProperty.java | 305 +++++++++++++++++ .../custom/item/model/SelectSwitch.java | 21 ++ .../custom/item/model/SelectSwitchCase.java | 23 ++ .../custom/item/model/SkullType.java | 31 ++ .../custom/item/model/SpecialModel.java | 315 ++++++++++++++++++ .../custom/item/model/TextureSlot.java | 87 +++++ .../custom/item/model/TexturedModel.java | 95 ++++++ .../custom/item/model/Textures.java | 90 +++++ .../custom/item/model/TimeSource.java | 26 ++ .../custom/item/model/WoodTypes.java | 23 ++ .../hellheim/spongetools/util/ModelUtil.java | 48 +++ 25 files changed, 2743 insertions(+), 2 deletions(-) create mode 100644 src/main/java/net/hellheim/spongetools/codec/MathCodecs.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/ChargeType.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/CompassTarget.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/ConditionalProperty.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/GuiLight.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/ItemDisplayContext.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/ItemModel.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/ItemModelDefinition.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/ItemTintSource.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/ItemTransforms.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/ModelTemplate.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/RangeSelectEntry.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/RangeSelectProperty.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/SelectProperty.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/SelectSwitch.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/SelectSwitchCase.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/SkullType.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/SpecialModel.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/TextureSlot.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/TexturedModel.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/Textures.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/TimeSource.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/model/WoodTypes.java create mode 100644 src/main/java/net/hellheim/spongetools/util/ModelUtil.java diff --git a/src/main/java/net/hellheim/spongetools/codec/MathCodecs.java b/src/main/java/net/hellheim/spongetools/codec/MathCodecs.java new file mode 100644 index 0000000..674a05d --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/codec/MathCodecs.java @@ -0,0 +1,153 @@ +package net.hellheim.spongetools.codec; + +import java.util.List; + +import org.spongepowered.api.util.Transform; +import org.spongepowered.math.imaginary.Complexd; +import org.spongepowered.math.imaginary.Complexf; +import org.spongepowered.math.imaginary.Quaterniond; +import org.spongepowered.math.imaginary.Quaternionf; +import org.spongepowered.math.matrix.Matrix2d; +import org.spongepowered.math.matrix.Matrix2f; +import org.spongepowered.math.matrix.Matrix3d; +import org.spongepowered.math.matrix.Matrix3f; +import org.spongepowered.math.matrix.Matrix4d; +import org.spongepowered.math.matrix.Matrix4f; +import org.spongepowered.math.vector.Vector2d; +import org.spongepowered.math.vector.Vector2f; +import org.spongepowered.math.vector.Vector2i; +import org.spongepowered.math.vector.Vector2l; +import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.math.vector.Vector3f; +import org.spongepowered.math.vector.Vector3i; +import org.spongepowered.math.vector.Vector3l; +import org.spongepowered.math.vector.Vector4d; +import org.spongepowered.math.vector.Vector4f; +import org.spongepowered.math.vector.Vector4i; +import org.spongepowered.math.vector.Vector4l; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +public final class MathCodecs { + + public static final Codec VECTOR2I = list(Codec.INT, 2).xmap( + l -> new Vector2i(l.get(0), l.get(1)), v -> List.of(v.x(), v.y())); + public static final Codec VECTOR3I = list(Codec.INT, 3).xmap( + l -> new Vector3i(l.get(0), l.get(1), l.get(2)), v -> List.of(v.x(), v.y(), v.z())); + public static final Codec VECTOR4I = list(Codec.INT, 4).xmap( + l -> new Vector4i(l.get(0), l.get(1), l.get(2), l.get(3)), v -> List.of(v.x(), v.y(), v.z(), v.w())); + + public static final Codec VECTOR2L = list(Codec.LONG, 2).xmap( + l -> new Vector2l(l.get(0), l.get(1)), v -> List.of(v.x(), v.y())); + public static final Codec VECTOR3L = list(Codec.LONG, 3).xmap( + l -> new Vector3l(l.get(0), l.get(1), l.get(2)), v -> List.of(v.x(), v.y(), v.z())); + public static final Codec VECTOR4L = list(Codec.LONG, 4).xmap( + l -> new Vector4l(l.get(0), l.get(1), l.get(2), l.get(3)), v -> List.of(v.x(), v.y(), v.z(), v.w())); + + public static final Codec VECTOR2F = list(Codec.FLOAT, 2).xmap( + l -> new Vector2f(l.get(0), l.get(1)), v -> List.of(v.x(), v.y())); + public static final Codec VECTOR3F = list(Codec.FLOAT, 3).xmap( + l -> new Vector3f(l.get(0), l.get(1), l.get(2)), v -> List.of(v.x(), v.y(), v.z())); + public static final Codec VECTOR4F = list(Codec.FLOAT, 4).xmap( + l -> new Vector4f(l.get(0), l.get(1), l.get(2), l.get(3)), v -> List.of(v.x(), v.y(), v.z(), v.w())); + + public static final Codec VECTOR2D = list(Codec.DOUBLE, 2).xmap( + l -> new Vector2d(l.get(0), l.get(1)), v -> List.of(v.x(), v.y())); + public static final Codec VECTOR3D = list(Codec.DOUBLE, 3).xmap( + l -> new Vector3d(l.get(0), l.get(1), l.get(2)), v -> List.of(v.x(), v.y(), v.z())); + public static final Codec VECTOR4D = list(Codec.DOUBLE, 4).xmap( + l -> new Vector4d(l.get(0), l.get(1), l.get(2), l.get(3)), v -> List.of(v.x(), v.y(), v.z(), v.w())); + + public static final Codec MATRIX2F = list(Codec.FLOAT, 4).xmap( + l -> Matrix2f.from( + l.get(0), l.get(1), + l.get(2), l.get(3) + ), + m -> List.of( + m.get(0, 0), m.get(0, 1), + m.get(1, 0), m.get(1, 1) + )); + public static final Codec MATRIX3F = list(Codec.FLOAT, 9).xmap( + l -> Matrix3f.from( + l.get(0), l.get(1), l.get(2), + l.get(3), l.get(4), l.get(5), + l.get(6), l.get(7), l.get(9) + ), + m -> List.of( + m.get(0, 0), m.get(0, 1), m.get(0, 2), + m.get(1, 0), m.get(1, 1), m.get(1, 2), + m.get(2, 0), m.get(2, 1), m.get(2, 2) + )); + public static final Codec MATRIX4F = list(Codec.FLOAT, 16).xmap( + l -> Matrix4f.from( + l.get(0), l.get(1), l.get(2), l.get(3), + l.get(4), l.get(5), l.get(6), l.get(7), + l.get(8), l.get(9), l.get(10), l.get(11), + l.get(12), l.get(13), l.get(14), l.get(15) + ), + m -> List.of( + m.get(0, 0), m.get(0, 1), m.get(0, 2), m.get(0, 3), + m.get(1, 0), m.get(1, 1), m.get(1, 2), m.get(1, 3), + m.get(2, 0), m.get(2, 1), m.get(2, 2), m.get(2, 3), + m.get(3, 0), m.get(3, 1), m.get(3, 2), m.get(3, 3) + )); + + public static final Codec MATRIX2D = list(Codec.DOUBLE, 4).xmap( + l -> Matrix2d.from( + l.get(0), l.get(1), + l.get(2), l.get(3) + ), + m -> List.of( + m.get(0, 0), m.get(0, 1), + m.get(1, 0), m.get(1, 1) + )); + public static final Codec MATRIX3D = list(Codec.DOUBLE, 9).xmap( + l -> Matrix3d.from( + l.get(0), l.get(1), l.get(2), + l.get(3), l.get(4), l.get(5), + l.get(6), l.get(7), l.get(9) + ), + m -> List.of( + m.get(0, 0), m.get(0, 1), m.get(0, 2), + m.get(1, 0), m.get(1, 1), m.get(1, 2), + m.get(2, 0), m.get(2, 1), m.get(2, 2) + )); + public static final Codec MATRIX4D = list(Codec.DOUBLE, 16).xmap( + l -> Matrix4d.from( + l.get(0), l.get(1), l.get(2), l.get(3), + l.get(4), l.get(5), l.get(6), l.get(7), + l.get(8), l.get(9), l.get(10), l.get(11), + l.get(12), l.get(13), l.get(14), l.get(15) + ), + m -> List.of( + m.get(0, 0), m.get(0, 1), m.get(0, 2), m.get(0, 3), + m.get(1, 0), m.get(1, 1), m.get(1, 2), m.get(1, 3), + m.get(2, 0), m.get(2, 1), m.get(2, 2), m.get(2, 3), + m.get(3, 0), m.get(3, 1), m.get(3, 2), m.get(3, 3) + )); + + public static final Codec COMPLEXF = list(Codec.FLOAT, 2).xmap( + l -> Complexf.from(l.get(0), l.get(1)), c -> List.of(c.x(), c.y())); + public static final Codec COMPLEXD = list(Codec.DOUBLE, 2).xmap( + l -> Complexd.from(l.get(0), l.get(1)), c -> List.of(c.x(), c.y())); + + public static final Codec QUATERNIONF = list(Codec.FLOAT, 4).xmap( + l -> Quaternionf.from(l.get(0), l.get(1), l.get(2), l.get(3)), c -> List.of(c.x(), c.y(), c.z(), c.w())); + public static final Codec QUATERNIOND = list(Codec.DOUBLE, 4).xmap( + l -> Quaterniond.from(l.get(0), l.get(1), l.get(2), l.get(3)), c -> List.of(c.x(), c.y(), c.z(), c.w())); + + public static final Codec TRANSFORM = RecordCodecBuilder.create( + instance -> instance.group( + MathCodecs.VECTOR3D.optionalFieldOf("translation", Vector3d.ZERO).forGetter(Transform::position), + MathCodecs.VECTOR3D.optionalFieldOf("rotation", Vector3d.ZERO).forGetter(Transform::rotation), + MathCodecs.VECTOR3D.optionalFieldOf("scale", Vector3d.ONE).forGetter(Transform::scale) + ).apply(instance, Transform::of)); + + private static Codec> list(final Codec codec, final int size) { + return ExtraCodecs.sizeLimitedCollection(codec.listOf(), size); + } + + private MathCodecs() { + } +} diff --git a/src/main/java/net/hellheim/spongetools/codec/StringRepresentableCodec.java b/src/main/java/net/hellheim/spongetools/codec/StringRepresentableCodec.java index 01ca46e..7af31a9 100644 --- a/src/main/java/net/hellheim/spongetools/codec/StringRepresentableCodec.java +++ b/src/main/java/net/hellheim/spongetools/codec/StringRepresentableCodec.java @@ -30,7 +30,11 @@ public StringRepresentableCodec( ); } - static StringRepresentableCodec fromValues(final Supplier values) { + public static StringRepresentableCodec fromValues(final S[] values) { + return StringRepresentableCodec.fromValues(() -> values); + } + + public static StringRepresentableCodec fromValues(final Supplier values) { final Supplier memoized = Suppliers.memoize(values::get); final Supplier> memoizedList = Suppliers.memoize(() -> List.of(memoized.get())); @@ -40,7 +44,7 @@ static StringRepresentableCodec fromValues(fi return new StringRepresentableCodec<>(memoized, nameLookup, indexLookup); } - static Function nameLookup( + public static Function nameLookup( final Supplier values, final Function keyFunction ) { final Supplier memoized = Suppliers.memoize(values::get); diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/ChargeType.java b/src/main/java/net/hellheim/spongetools/custom/item/model/ChargeType.java new file mode 100644 index 0000000..b6efa2c --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/item/model/ChargeType.java @@ -0,0 +1,28 @@ +package net.hellheim.spongetools.custom.item.model; + +import org.spongepowered.api.data.type.StringRepresentable; + +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.codec.StringRepresentableCodec; + +// TODO Maybe expose as registry? +public enum ChargeType implements StringRepresentable { + + NONE("none"), + ARROW("arrow"), + ROCKET("rocket"); + + public static final Codec CODEC = StringRepresentableCodec.fromValues(ChargeType::values); + + private final String name; + + private ChargeType(final String name) { + this.name = name; + } + + @Override + public String serializationString() { + return this.name; + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/CompassTarget.java b/src/main/java/net/hellheim/spongetools/custom/item/model/CompassTarget.java new file mode 100644 index 0000000..332d13b --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/item/model/CompassTarget.java @@ -0,0 +1,27 @@ +package net.hellheim.spongetools.custom.item.model; + +import org.spongepowered.api.data.type.StringRepresentable; + +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.codec.StringRepresentableCodec; + +public enum CompassTarget implements StringRepresentable { + NONE("none"), + LODESTONE("lodestone"), + SPAWN("spawn"), + RECOVERY("recovery"); + + public static final Codec CODEC = StringRepresentableCodec.fromValues(CompassTarget::values); + + private final String name; + + private CompassTarget(final String name) { + this.name = name; + } + + @Override + public String serializationString() { + return this.name; + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/ConditionalProperty.java b/src/main/java/net/hellheim/spongetools/custom/item/model/ConditionalProperty.java new file mode 100644 index 0000000..5397888 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/item/model/ConditionalProperty.java @@ -0,0 +1,208 @@ +package net.hellheim.spongetools.custom.item.model; + +import java.util.function.Function; + +import org.spongepowered.api.ResourceKey; + +import com.google.common.base.Preconditions; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.hellheim.spongetools.codec.ExtraCodecs; +import net.hellheim.spongetools.codec.LateBoundIdMapper; +import net.hellheim.spongetools.codec.SpongeCodecs; + +public interface ConditionalProperty { + + final MapCodec CODEC = Registrar.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) + .dispatchMap("property", ConditionalProperty::codec, Function.identity()); + + final class Registrar { + + private static final LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); + + static { + ID_MAPPER.put(ResourceKey.minecraft("custom_model_data"), CustomModelData.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("using_item"), Using.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("broken"), Broken.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("damaged"), Damaged.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("fishing_rod/cast"), FishingRodCast.CODEC); + // TODO + // ID_MAPPER.put(ResourceKey.minecraft("has_component"), HasComponent.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("bundle/has_selected_item"), BundleHasSelectedItem.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("selected"), Selected.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("carried"), Carried.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("extended_view"), ExtendedView.CODEC); + // TODO + // ID_MAPPER.put(ResourceKey.minecraft("keybind_down"), KeybindDown.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("view_entity"), ViewingEntity.CODEC); + } + + private Registrar() { + } + } + + static Broken broken() { + return Broken.INSTANCE; + } + + static Damaged damaged() { + return Damaged.INSTANCE; + } + + static Carried carried() { + return Carried.INSTANCE; + } + + static Selected selected() { + return Selected.INSTANCE; + } + + static ExtendedView extendedView() { + return ExtendedView.INSTANCE; + } + + static FishingRodCast rodCast() { + return FishingRodCast.INSTANCE; + } + + static BundleHasSelectedItem bundleHasSelectedItem() { + return BundleHasSelectedItem.INSTANCE; + } + + static Using using() { + return Using.INSTANCE; + } + + static ViewingEntity viewingEntity() { + return ViewingEntity.INSTANCE; + } + + static CustomModelData custom() { + return ConditionalProperty.custom(CustomModelData.DEFAULT); + } + + static CustomModelData custom(final int index) { + return new CustomModelData(index); + } + + MapCodec codec(); + + record Broken() implements ConditionalProperty { + public static final Broken INSTANCE = new Broken(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record Damaged() implements ConditionalProperty { + public static final Damaged INSTANCE = new Damaged(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record Carried() implements ConditionalProperty { + public static final Carried INSTANCE = new Carried(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record Selected() implements ConditionalProperty { + public static final Selected INSTANCE = new Selected(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record ExtendedView() implements ConditionalProperty { + public static final ExtendedView INSTANCE = new ExtendedView(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record FishingRodCast() implements ConditionalProperty { + public static final FishingRodCast INSTANCE = new FishingRodCast(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record BundleHasSelectedItem() implements ConditionalProperty { + public static final BundleHasSelectedItem INSTANCE = new BundleHasSelectedItem(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record Using() implements ConditionalProperty { + public static final Using INSTANCE = new Using(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record ViewingEntity() implements ConditionalProperty { + public static final ViewingEntity INSTANCE = new ViewingEntity(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record CustomModelData(int index) implements ConditionalProperty { + public static final int DEFAULT = 0; + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + ExtraCodecs.NON_NEGATIVE_INT.optionalFieldOf("index", DEFAULT).forGetter(CustomModelData::index) + ).apply(instance, CustomModelData::new)); + + public CustomModelData(final int index) { + Preconditions.checkArgument(index >= 0, "Index must not be negative: " + index); + this.index = index; + } + + @Override + public MapCodec codec() { + return CODEC; + } + } + + // TODO expose DataComponentType + /*record HasComponent() implements ConditionalProperty { + + }*/ + + // TODO + /*record KeybindDown() implements ConditionalProperty { + + }*/ +} diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/GuiLight.java b/src/main/java/net/hellheim/spongetools/custom/item/model/GuiLight.java new file mode 100644 index 0000000..455ec95 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/item/model/GuiLight.java @@ -0,0 +1,26 @@ +package net.hellheim.spongetools.custom.item.model; + +import org.spongepowered.api.data.type.StringRepresentable; + +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.codec.StringRepresentableCodec; + +public enum GuiLight implements StringRepresentable { + FRONT("front"), + SIDE("side"); + + public static final Codec CODEC = StringRepresentableCodec.fromValues(GuiLight.values()); + public static final GuiLight DEFAULT = GuiLight.SIDE; + + private final String name; + + private GuiLight(String name) { + this.name = name; + } + + @Override + public String serializationString() { + return this.name; + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/ItemDisplayContext.java b/src/main/java/net/hellheim/spongetools/custom/item/model/ItemDisplayContext.java new file mode 100644 index 0000000..6261398 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/item/model/ItemDisplayContext.java @@ -0,0 +1,33 @@ +package net.hellheim.spongetools.custom.item.model; + +import org.spongepowered.api.data.type.StringRepresentable; + +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.codec.StringRepresentableCodec; + +// TODO Maybe expose as registry? +public enum ItemDisplayContext implements StringRepresentable { + NONE("none"), + THIRD_PERSON_LEFT_HAND("thirdperson_lefthand"), + THIRD_PERSON_RIGHT_HAND("thirdperson_righthand"), + FIRST_PERSON_LEFT_HAND("firstperson_lefthand"), + FIRST_PERSON_RIGHT_HAND("firstperson_righthand"), + HEAD("head"), + GUI("gui"), + GROUND("ground"), + FIXED("fixed"); + + public static final Codec CODEC = StringRepresentableCodec.fromValues(ItemDisplayContext::values); + + private final String name; + + private ItemDisplayContext(String name) { + this.name = name; + } + + @Override + public String serializationString() { + return this.name; + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/ItemModel.java b/src/main/java/net/hellheim/spongetools/custom/item/model/ItemModel.java new file mode 100644 index 0000000..8e60029 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/item/model/ItemModel.java @@ -0,0 +1,128 @@ +package net.hellheim.spongetools.custom.item.model; + +import java.util.Objects; +import java.util.function.Consumer; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.util.CopyableBuilder; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +public record ItemModel(TexturedModel model, ItemTransforms display, GuiLight guiLight) { + + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + TexturedModel.MAP_CODEC.forGetter(ItemModel::model), + ItemTransforms.CODEC.fieldOf("display").forGetter(ItemModel::display), + GuiLight.CODEC.fieldOf("gui_light").forGetter(ItemModel::guiLight) + ).apply(instance, ItemModel::new)); + + public ItemModel(final TexturedModel model, final ItemTransforms display, final GuiLight guiLight) { + this.model = Objects.requireNonNull(model, "model"); + this.display = Objects.requireNonNull(display, "display"); + this.guiLight = Objects.requireNonNull(guiLight, "guiLight"); + } + + public static ItemModel of(final TexturedModel model, final ItemTransforms display) { + return new ItemModel(model, display, GuiLight.DEFAULT); + } + + public static ItemModel of(final ModelTemplate parent, final Textures textures, final ItemTransforms display) { + return ItemModel.of(TexturedModel.of(parent, textures), display); + } + + public static Builder builder() { + return new Builder(); + } + + public ModelTemplate parent() { + return this.model.parent(); + } + + public Textures textures() { + return this.model.textures(); + } + + public static class Builder implements + org.spongepowered.api.util.Builder, + CopyableBuilder { + + private @Nullable ModelTemplate parent; + private @Nullable Textures textures; + private @Nullable ItemTransforms display; + private @Nullable GuiLight guiLight; + + public Builder() { + this.reset(); + } + + public Builder model(final TexturedModel model) { + Objects.requireNonNull(model, "model"); + return this.parent(model.parent()).textures(model.textures()); + } + + public Builder parent(final ModelTemplate parent) { + this.parent = Objects.requireNonNull(parent, "parent"); + return this; + } + + public Builder textures(final Textures textures) { + this.textures = Objects.requireNonNull(textures, "textures"); + return this; + } + + public Builder textures(final Textures.Builder builder) { + return this.textures(Objects.requireNonNull(builder, "builder").build()); + } + + public Builder textures(final Consumer configurator) { + final Textures.Builder builder = Textures.builder(); + Objects.requireNonNull(configurator, "configurator").accept(builder); + return this.textures(builder); + } + + public Builder display(final ItemTransforms display) { + this.display = Objects.requireNonNull(display, "display"); + return this; + } + + public Builder display(final ItemTransforms.Builder builder) { + return this.display(Objects.requireNonNull(builder, "builder").build()); + } + + public Builder display(final Consumer configurator) { + final ItemTransforms.Builder builder = ItemTransforms.builder(); + Objects.requireNonNull(configurator, "configurator").accept(builder); + return this.display(builder); + } + + public Builder light(final GuiLight guiLight) { + this.guiLight = Objects.requireNonNull(guiLight, "guiLight"); + return this; + } + + @Override + public Builder from(final ItemModel value) { + this.parent = value.parent(); + this.textures = value.textures(); + this.display = value.display(); + this.guiLight = value.guiLight; + return this; + } + + @Override + public Builder reset() { + this.parent = null; + this.textures = null; + this.display = null; + this.guiLight = null; + return this; + } + + @Override + public ItemModel build() { + return new ItemModel(TexturedModel.of(this.parent, this.textures), this.display, this.guiLight); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/ItemModelDefinition.java b/src/main/java/net/hellheim/spongetools/custom/item/model/ItemModelDefinition.java new file mode 100644 index 0000000..9d278fe --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/item/model/ItemModelDefinition.java @@ -0,0 +1,270 @@ +package net.hellheim.spongetools.custom.item.model; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +import org.spongepowered.api.ResourceKey; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.hellheim.spongetools.codec.LateBoundIdMapper; +import net.hellheim.spongetools.codec.SpongeCodecs; + +public interface ItemModelDefinition { + + final Codec CODEC = Registrar.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) + .dispatch(ItemModelDefinition::codec, Function.identity()); + + final class Registrar { + + private static final LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); + + static { + ID_MAPPER.put(ResourceKey.minecraft("empty"), Empty.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("model"), Simple.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("range_dispatch"), RangeSelect.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("special"), Special.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("composite"), Composite.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("bundle/selected_item"), BundleSelectedItem.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("select"), Select.CODEC); + ID_MAPPER.put(ResourceKey.minecraft("condition"), Conditional.CODEC); + } + + private Registrar() { + } + } + + static Empty empty() { + return Empty.INSTANCE; + } + + static BundleSelectedItem bundleSelectedItem() { + return BundleSelectedItem.INSTANCE; + } + + static Simple simple(final ResourceKey model, final ItemTintSource... tints) { + return new Simple(model, List.of(tints)); + } + + static Simple simple(final ResourceKey model, final Collection tints) { + return new Simple(model, List.copyOf(tints)); + } + + static Composite composite(final ItemModelDefinition... models) { + return new Composite(List.of(models)); + } + + static Composite composote(final Collection models) { + return new Composite(List.copyOf(models)); + } + + static Conditional conditional(final ConditionalProperty property, final ItemModelDefinition onTrue, final ItemModelDefinition onFalse) { + return new Conditional(property, onTrue, onFalse); + } + + @SafeVarargs + static Select select(final SelectProperty property, final SelectSwitchCase... cases) { + return ItemModelDefinition.select(property, Optional.empty(), cases); + } + + @SafeVarargs + static Select select(final SelectProperty property, final ItemModelDefinition fallback, final SelectSwitchCase... cases) { + return ItemModelDefinition.select(property, Optional.of(fallback), cases); + } + + @SafeVarargs + static Select select(final SelectProperty property, final Optional fallback, final SelectSwitchCase... cases) { + return ItemModelDefinition.select(SelectSwitch.of(property, List.of(cases)), fallback); + } + + static Select select(final SelectProperty property, final Collection> cases) { + return ItemModelDefinition.select(property, Optional.empty(), cases); + } + + static Select select(final SelectProperty property, final ItemModelDefinition fallback, final Collection> cases) { + return ItemModelDefinition.select(property, Optional.of(fallback), cases); + } + + static Select select(final SelectProperty property, final Optional fallback, final Collection> cases) { + return ItemModelDefinition.select(SelectSwitch.of(property, List.copyOf(cases)), fallback); + } + + static Select select(final SelectSwitch body) { + return ItemModelDefinition.select(body, Optional.empty()); + } + + static Select select(final SelectSwitch body, final ItemModelDefinition fallback) { + return ItemModelDefinition.select(body, Optional.of(fallback)); + } + + static Select select(final SelectSwitch body, final Optional fallback) { + return new Select(body, fallback); + } + + static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final RangeSelectEntry... entries) { + return ItemModelDefinition.rangeSelect(property, scale, Optional.empty(), entries); + } + + static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final ItemModelDefinition fallback, final RangeSelectEntry... entries) { + return ItemModelDefinition.rangeSelect(property, scale, Optional.of(fallback), entries); + } + + static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final Optional fallback, final RangeSelectEntry... entries) { + return new RangeSelect(property, scale, fallback, List.of(entries)); + } + + static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final Collection entries) { + return ItemModelDefinition.rangeSelect(property, scale, Optional.empty(), entries); + } + + static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final ItemModelDefinition fallback, final Collection entries) { + return ItemModelDefinition.rangeSelect(property, scale, Optional.of(fallback), entries); + } + + static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final Optional fallback, final Collection entries) { + return new RangeSelect(property, scale, fallback, List.copyOf(entries)); + } + + static Special special(final ResourceKey base, final SpecialModel model) { + return new Special(base, model); + } + + MapCodec codec(); + + record Empty() implements ItemModelDefinition { + public static final Empty INSTANCE = new Empty(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record BundleSelectedItem() implements ItemModelDefinition { + public static final BundleSelectedItem INSTANCE = new BundleSelectedItem(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record Simple(ResourceKey model, List tints) implements ItemModelDefinition { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + SpongeCodecs.RESOURCE_KEY.fieldOf("model").forGetter(Simple::model), + ItemTintSource.CODEC.listOf().optionalFieldOf("tints", List.of()).forGetter(Simple::tints) + ).apply(instance, Simple::new)); + + public Simple(final ResourceKey model, final List tints) { + this.model = Objects.requireNonNull(model, "model"); + this.tints = Objects.requireNonNull(tints, "tints"); + } + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record Composite(List models) implements ItemModelDefinition { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + ItemModelDefinition.CODEC.listOf().fieldOf("models").forGetter(Composite::models) + ).apply(instance, Composite::new)); + + public Composite(final List models) { + this.models = Objects.requireNonNull(models, "models"); + } + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record Conditional(ConditionalProperty property, ItemModelDefinition onTrue, ItemModelDefinition onFalse) implements ItemModelDefinition { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + ConditionalProperty.CODEC.forGetter(Conditional::property), + ItemModelDefinition.CODEC.fieldOf("on_true").forGetter(Conditional::onTrue), + ItemModelDefinition.CODEC.fieldOf("on_false").forGetter(Conditional::onFalse)) + .apply(instance, Conditional::new)); + + public Conditional(final ConditionalProperty property, final ItemModelDefinition onTrue, final ItemModelDefinition onFalse) { + this.property = Objects.requireNonNull(property, "property"); + this.onTrue = Objects.requireNonNull(onTrue, "onTrue"); + this.onFalse = Objects.requireNonNull(onFalse, "onFalse"); + } + + @Override + public MapCodec codec() { + return CODEC; + } + } + + record Select(SelectSwitch body, Optional fallback) implements ItemModelDefinition { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( SelectSwitch.CODEC.forGetter(Select::body), - ItemModelDefinition.CODEC.optionalFieldOf("fallback").forGetter(Select::fallback) + ItemDefinition.CODEC.optionalFieldOf("fallback").forGetter(Select::fallback) ).apply(instance, Select::new)); - public Select(final SelectSwitch body, final Optional fallback) { + public Select(final SelectSwitch body, final Optional fallback) { this.body = Objects.requireNonNull(body, "body"); this.fallback = Objects.requireNonNull(fallback, "fallback"); } @Override - public MapCodec codec() { + public MapCodec codec() { return CODEC; } } - record RangeSelect(RangeSelectProperty property, float scale, Optional fallback, List entries) implements ItemModelDefinition { + record RangeSelect(RangeSelectProperty property, float scale, Optional fallback, List entries) implements ItemDefinition { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( RangeSelectProperty.CODEC.forGetter(RangeSelect::property), Codec.FLOAT.optionalFieldOf("scale", Float.valueOf(1.0F)).forGetter(RangeSelect::scale), - ItemModelDefinition.CODEC.optionalFieldOf("fallback").forGetter(RangeSelect::fallback), + ItemDefinition.CODEC.optionalFieldOf("fallback").forGetter(RangeSelect::fallback), RangeSelectEntry.CODEC.listOf().fieldOf("entries").forGetter(RangeSelect::entries) ).apply(instance, RangeSelect::new)); - public RangeSelect(final RangeSelectProperty property, final float scale, final Optional fallback, final List entries) { + public RangeSelect(final RangeSelectProperty property, final float scale, final Optional fallback, final List entries) { this.property = Objects.requireNonNull(property, "property"); this.scale = scale; this.fallback = Objects.requireNonNull(fallback, "fallback"); @@ -236,12 +236,12 @@ public RangeSelect(final RangeSelectProperty property, final float scale, final } @Override - public MapCodec codec() { + public MapCodec codec() { return CODEC; } } - record Special(ResourceKey base, SpecialModel model) implements ItemModelDefinition { + record Special(ResourceKey base, SpecialModel model) implements ItemDefinition { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( SpongeCodecs.RESOURCE_KEY.fieldOf("base").forGetter(Special::base), @@ -254,7 +254,7 @@ public Special(final ResourceKey base, final SpecialModel model) { } @Override - public MapCodec codec() { + public MapCodec codec() { return CODEC; } } diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/ItemDisplayContext.java b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemDisplayContext.java similarity index 94% rename from src/main/java/net/hellheim/spongetools/custom/item/model/ItemDisplayContext.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/ItemDisplayContext.java index 6261398..80c9b86 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/ItemDisplayContext.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemDisplayContext.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model; +package net.hellheim.spongetools.custom.model.item; import org.spongepowered.api.data.type.StringRepresentable; diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/ItemModel.java b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java similarity index 72% rename from src/main/java/net/hellheim/spongetools/custom/item/model/ItemModel.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java index 31cd3ba..e251968 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/ItemModel.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model; +package net.hellheim.spongetools.custom.model.item; import java.util.Objects; import java.util.function.Consumer; @@ -11,15 +11,18 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.hellheim.spongetools.SpongeTools; -import net.hellheim.spongetools.custom.item.model.enums.GuiLight; +import net.hellheim.spongetools.custom.model.ModelTemplate; +import net.hellheim.spongetools.custom.model.TexturedModel; +import net.hellheim.spongetools.custom.model.Textures; +import net.hellheim.spongetools.custom.model.item.enums.GuiLight; public record ItemModel(TexturedModel model, ItemTransforms display, GuiLight guiLight) { public static final Codec CODEC = RecordCodecBuilder.create( instance -> instance.group( TexturedModel.MAP_CODEC.forGetter(ItemModel::model), - ItemTransforms.CODEC.fieldOf("display").forGetter(ItemModel::display), - GuiLight.CODEC.fieldOf("gui_light").forGetter(ItemModel::guiLight) + ItemTransforms.CODEC.optionalFieldOf("display", ItemTransforms.DEFAULT).forGetter(ItemModel::display), + GuiLight.CODEC.optionalFieldOf("gui_light", GuiLight.DEFAULT).forGetter(ItemModel::guiLight) ).apply(instance, ItemModel::new)); public ItemModel(final TexturedModel model, final ItemTransforms display, final GuiLight guiLight) { @@ -32,14 +35,38 @@ public static DefaultedRegistryType registry() { return SpongeTools.Registries.ITEM_MODEL; } - public static ItemModel of(final TexturedModel model, final ItemTransforms display) { - return new ItemModel(model, display, GuiLight.DEFAULT); + public static ItemModel of(final ModelTemplate parent, final Textures textures) { + return ItemModel.of(TexturedModel.of(parent, textures)); } public static ItemModel of(final ModelTemplate parent, final Textures textures, final ItemTransforms display) { return ItemModel.of(TexturedModel.of(parent, textures), display); } + public static ItemModel of(final ModelTemplate parent, final Textures textures, final GuiLight light) { + return ItemModel.of(TexturedModel.of(parent, textures), light); + } + + public static ItemModel of(final ModelTemplate parent, final Textures textures, final ItemTransforms display, final GuiLight light) { + return ItemModel.of(TexturedModel.of(parent, textures), display, light); + } + + public static ItemModel of(final TexturedModel model) { + return ItemModel.of(model, ItemTransforms.DEFAULT, GuiLight.DEFAULT); + } + + public static ItemModel of(final TexturedModel model, final ItemTransforms display) { + return ItemModel.of(model, display, GuiLight.DEFAULT); + } + + public static ItemModel of(final TexturedModel model, final GuiLight light) { + return ItemModel.of(model, ItemTransforms.DEFAULT, light); + } + + public static ItemModel of(final TexturedModel model, final ItemTransforms display, final GuiLight light) { + return new ItemModel(model, display, light); + } + public static Builder builder() { return new Builder(); } diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/ItemTransforms.java b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemTransforms.java similarity index 95% rename from src/main/java/net/hellheim/spongetools/custom/item/model/ItemTransforms.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/ItemTransforms.java index 35b5823..f5813b4 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/ItemTransforms.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemTransforms.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model; +package net.hellheim.spongetools.custom.model.item; import java.util.HashMap; import java.util.Map; @@ -13,6 +13,8 @@ public record ItemTransforms(Map transforms) { + public static final ItemTransforms DEFAULT = new ItemTransforms(Map.of()); + public static final Codec CODEC = Codec.unboundedMap(ItemDisplayContext.CODEC, MathCodecs.TRANSFORM) .xmap(ItemTransforms::new, ItemTransforms::transforms); diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/RangeSelectEntry.java b/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectEntry.java similarity index 60% rename from src/main/java/net/hellheim/spongetools/custom/item/model/RangeSelectEntry.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectEntry.java index f649731..95ad01c 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/RangeSelectEntry.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectEntry.java @@ -1,18 +1,18 @@ -package net.hellheim.spongetools.custom.item.model; +package net.hellheim.spongetools.custom.model.item; import java.util.Objects; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; -public record RangeSelectEntry(float threshold, ItemModelDefinition model) { +public record RangeSelectEntry(float threshold, ItemDefinition model) { public static final Codec CODEC = RecordCodecBuilder.create( instance -> instance.group( Codec.FLOAT.fieldOf("threshold").forGetter(RangeSelectEntry::threshold), - ItemModelDefinition.CODEC.fieldOf("model").forGetter(RangeSelectEntry::model) + ItemDefinition.CODEC.fieldOf("model").forGetter(RangeSelectEntry::model) ).apply(instance, RangeSelectEntry::new)); - public RangeSelectEntry(final float threshold, final ItemModelDefinition model) { + public RangeSelectEntry(final float threshold, final ItemDefinition model) { this.threshold = threshold; this.model = Objects.requireNonNull(model, "model"); } diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/RangeSelectProperty.java b/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java similarity index 97% rename from src/main/java/net/hellheim/spongetools/custom/item/model/RangeSelectProperty.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java index e20bb56..f3ef094 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/RangeSelectProperty.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model; +package net.hellheim.spongetools.custom.model.item; import java.util.Objects; import java.util.function.Function; @@ -13,8 +13,8 @@ import net.hellheim.spongetools.codec.LateBoundIdMapper; import net.hellheim.spongetools.codec.list.ExtraCodecs; import net.hellheim.spongetools.codec.list.SpongeCodecs; -import net.hellheim.spongetools.custom.item.model.enums.CompassTarget; -import net.hellheim.spongetools.custom.item.model.enums.TimeSource; +import net.hellheim.spongetools.custom.model.item.enums.CompassTarget; +import net.hellheim.spongetools.custom.model.item.enums.TimeSource; public interface RangeSelectProperty { diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/SelectProperty.java b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java similarity index 98% rename from src/main/java/net/hellheim/spongetools/custom/item/model/SelectProperty.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java index ef9ecb6..e7e49cb 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/SelectProperty.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model; +package net.hellheim.spongetools.custom.model.item; import java.text.SimpleDateFormat; import java.util.List; @@ -28,7 +28,7 @@ import net.hellheim.spongetools.codec.list.ExtraCodecs; import net.hellheim.spongetools.codec.list.RegistryCodecs; import net.hellheim.spongetools.codec.list.SpongeCodecs; -import net.hellheim.spongetools.custom.item.model.enums.ChargeType; +import net.hellheim.spongetools.custom.model.item.enums.ChargeType; public interface SelectProperty { diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/SelectSwitch.java b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitch.java similarity index 93% rename from src/main/java/net/hellheim/spongetools/custom/item/model/SelectSwitch.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitch.java index 7cb9da4..9900854 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/SelectSwitch.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitch.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model; +package net.hellheim.spongetools.custom.model.item; import java.util.List; import java.util.Objects; diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/SelectSwitchCase.java b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitchCase.java similarity index 68% rename from src/main/java/net/hellheim/spongetools/custom/item/model/SelectSwitchCase.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitchCase.java index aa4e0e0..4aea643 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/SelectSwitchCase.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitchCase.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model; +package net.hellheim.spongetools.custom.model.item; import java.util.List; import java.util.Objects; @@ -8,15 +8,15 @@ import net.hellheim.spongetools.codec.list.ExtraCodecs; -public record SelectSwitchCase(List values, ItemModelDefinition model) { +public record SelectSwitchCase(List values, ItemDefinition model) { public static Codec> codec(Codec codec) { return RecordCodecBuilder.create(instance -> instance.group( ExtraCodecs.nonEmptyCollection(ExtraCodecs.compactList(codec)).fieldOf("when").forGetter(SelectSwitchCase::values), - ItemModelDefinition.CODEC.fieldOf("model").forGetter(SelectSwitchCase::model) + ItemDefinition.CODEC.fieldOf("model").forGetter(SelectSwitchCase::model) ).apply(instance, SelectSwitchCase::new)); } - public SelectSwitchCase(final List values, final ItemModelDefinition model) { + public SelectSwitchCase(final List values, final ItemDefinition model) { this.values = Objects.requireNonNull(values, "values"); this.model = Objects.requireNonNull(model, "model"); } diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/SpecialModel.java b/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java similarity index 98% rename from src/main/java/net/hellheim/spongetools/custom/item/model/SpecialModel.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java index d9b6fdb..bfdd75d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/SpecialModel.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model; +package net.hellheim.spongetools.custom.model.item; import java.util.Objects; import java.util.Optional; @@ -16,7 +16,7 @@ import net.hellheim.spongetools.codec.LateBoundIdMapper; import net.hellheim.spongetools.codec.list.SpongeCodecs; import net.hellheim.spongetools.codec.list.StringRepresentableCodecs; -import net.hellheim.spongetools.custom.item.model.enums.SkullType; +import net.hellheim.spongetools.custom.model.item.enums.SkullType; public interface SpecialModel { diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/TintSource.java b/src/main/java/net/hellheim/spongetools/custom/model/item/TintSource.java similarity index 99% rename from src/main/java/net/hellheim/spongetools/custom/item/model/TintSource.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/TintSource.java index 475d7c2..d8b88b7 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/TintSource.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/TintSource.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model; +package net.hellheim.spongetools.custom.model.item; import java.util.function.Function; diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/ChargeType.java b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/ChargeType.java similarity index 91% rename from src/main/java/net/hellheim/spongetools/custom/item/model/enums/ChargeType.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/enums/ChargeType.java index c3649ce..4d2b287 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/ChargeType.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/ChargeType.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model.enums; +package net.hellheim.spongetools.custom.model.item.enums; import org.spongepowered.api.data.type.StringRepresentable; diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/CompassTarget.java b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/CompassTarget.java similarity index 91% rename from src/main/java/net/hellheim/spongetools/custom/item/model/enums/CompassTarget.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/enums/CompassTarget.java index a6e55c7..b70267c 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/CompassTarget.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/CompassTarget.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model.enums; +package net.hellheim.spongetools.custom.model.item.enums; import org.spongepowered.api.data.type.StringRepresentable; diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/GuiLight.java b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/GuiLight.java similarity index 90% rename from src/main/java/net/hellheim/spongetools/custom/item/model/enums/GuiLight.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/enums/GuiLight.java index d8adb18..31527ec 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/GuiLight.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/GuiLight.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model.enums; +package net.hellheim.spongetools.custom.model.item.enums; import org.spongepowered.api.data.type.StringRepresentable; diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/SkullType.java b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/SkullType.java similarity index 92% rename from src/main/java/net/hellheim/spongetools/custom/item/model/enums/SkullType.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/enums/SkullType.java index cff867a..cb0036e 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/SkullType.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/SkullType.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model.enums; +package net.hellheim.spongetools.custom.model.item.enums; import org.spongepowered.api.data.type.StringRepresentable; diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/TimeSource.java b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/TimeSource.java similarity index 91% rename from src/main/java/net/hellheim/spongetools/custom/item/model/enums/TimeSource.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/enums/TimeSource.java index 959ce8d..00e8efe 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/TimeSource.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/TimeSource.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model.enums; +package net.hellheim.spongetools.custom.model.item.enums; import org.spongepowered.api.data.type.StringRepresentable; diff --git a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/WoodTypes.java b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/WoodTypes.java similarity index 88% rename from src/main/java/net/hellheim/spongetools/custom/item/model/enums/WoodTypes.java rename to src/main/java/net/hellheim/spongetools/custom/model/item/enums/WoodTypes.java index c5102e7..15eda33 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/model/enums/WoodTypes.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/enums/WoodTypes.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.model.enums; +package net.hellheim.spongetools.custom.model.item.enums; public final class WoodTypes { From 0ec4861f0cc85a872a483abdbdab11f7b5efd93f Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Wed, 26 Mar 2025 05:17:18 +0300 Subject: [PATCH 08/55] continue custom items --- .../spongetools/codec/LateBoundIdMapper.java | 2 +- .../custom/metadata/AnimationFrame.java | 53 ++++ .../custom/metadata/GuiScaling.java | 173 ++++++++++ .../spongetools/custom/metadata/Metadata.java | 36 +++ .../custom/metadata/MetadataLike.java | 6 + .../custom/metadata/MetadataSection.java | 297 ++++++++++++++++++ .../custom/metadata/MetadataSectionLike.java | 11 + .../custom/metadata/VillagerHat.java | 31 ++ .../model/item/ConditionalProperty.java | 31 +- .../custom/model/item/ItemDefinition.java | 27 +- .../model/item/RangeSelectProperty.java | 31 +- .../custom/model/item/SelectProperty.java | 27 +- .../custom/model/item/SelectSwitch.java | 2 +- .../custom/model/item/SpecialModel.java | 33 +- .../custom/model/item/TintSource.java | 4 +- 15 files changed, 683 insertions(+), 81 deletions(-) create mode 100644 src/main/java/net/hellheim/spongetools/custom/metadata/AnimationFrame.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/metadata/GuiScaling.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/metadata/Metadata.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/metadata/MetadataLike.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSection.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSectionLike.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/metadata/VillagerHat.java diff --git a/src/main/java/net/hellheim/spongetools/codec/LateBoundIdMapper.java b/src/main/java/net/hellheim/spongetools/codec/LateBoundIdMapper.java index 5211d96..6d6b11c 100644 --- a/src/main/java/net/hellheim/spongetools/codec/LateBoundIdMapper.java +++ b/src/main/java/net/hellheim/spongetools/codec/LateBoundIdMapper.java @@ -13,7 +13,7 @@ public class LateBoundIdMapper { protected final BiMap idToValue = HashBiMap.create(); public Codec codec(final Codec idCodec) { - BiMap bimap = this.idToValue.inverse(); + final BiMap bimap = this.idToValue.inverse(); return ExtraCodecs.idResolver(idCodec, this.idToValue::get, bimap::get); } diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/AnimationFrame.java b/src/main/java/net/hellheim/spongetools/custom/metadata/AnimationFrame.java new file mode 100644 index 0000000..8b14668 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/metadata/AnimationFrame.java @@ -0,0 +1,53 @@ +package net.hellheim.spongetools.custom.metadata; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +import com.google.common.base.Preconditions; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.hellheim.spongetools.codec.list.ExtraCodecs; +import net.hellheim.spongetools.proxy.solid.codec.CodecProxy; + +public record AnimationFrame(int index, Optional time) implements CodecProxy { + + public static final Codec FULL_CODEC = RecordCodecBuilder.create( + instance -> instance.group( + ExtraCodecs.NON_NEGATIVE_INT.fieldOf("index").forGetter(AnimationFrame::index), + ExtraCodecs.POSITIVE_INT.optionalFieldOf("time").forGetter(AnimationFrame::time) + ).apply(instance, AnimationFrame::new)); + + public static final Codec CODEC = Codec.either(ExtraCodecs.NON_NEGATIVE_INT, FULL_CODEC) + .xmap( + either -> either.map(AnimationFrame::of, Function.identity()), + frame -> frame.time().isPresent() ? Either.right(frame) : Either.left(frame.index()) + ); + + public AnimationFrame(final int index, final Optional time) { + Preconditions.checkArgument(index >= 0, "index must not be negative: " + index); + Objects.requireNonNull(time, "time"); + time.ifPresent(t -> Preconditions.checkArgument(t > 0, "time must be positive: " + t)); + this.index = index; + this.time = time; + } + + @Override + public Codec codec() { + return CODEC; + } + + public static AnimationFrame of(int index) { + return AnimationFrame.of(index, Optional.empty()); + } + + public static AnimationFrame of(int index, int time) { + return AnimationFrame.of(index, Optional.of(time)); + } + + public static AnimationFrame of(int index, Optional time) { + return new AnimationFrame(index, time); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/GuiScaling.java b/src/main/java/net/hellheim/spongetools/custom/metadata/GuiScaling.java new file mode 100644 index 0000000..f21f1b4 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/metadata/GuiScaling.java @@ -0,0 +1,173 @@ +package net.hellheim.spongetools.custom.metadata; + +import java.util.Objects; +import java.util.OptionalInt; +import java.util.function.Function; + +import com.google.common.base.Preconditions; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.hellheim.spongetools.codec.LateBoundIdMapper; +import net.hellheim.spongetools.codec.list.ExtraCodecs; +import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; + +public interface GuiScaling extends MapCodecProxy, MetadataSectionLike { + + GuiScaling DEFAULT = GuiScaling.stretch(); + + LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); + + Codec CODEC = GuiScaling.ID_MAPPER.codec(Codec.STRING) + .dispatch(GuiScaling::mapCodec, Function.identity()); + + static Stretch stretch() { + return Stretch.INSTANCE; + } + + static Tile tile(final int width, final int height) { + return new Tile(width, height); + } + + static NineSlice nineSlice(final int width, final int height, final NineSlice.Border border) { + return GuiScaling.nineSlice(width, height, border, NineSlice.DEFAULT_STRETCH_INNER); + } + + static NineSlice nineSlice(final int width, final int height, final NineSlice.Border border, final boolean stretchInner) { + return new NineSlice(width, height, border, stretchInner); + } + + static NineSlice.Border border(final int size) { + Preconditions.checkArgument(size >= 0, "size must not be negative: " + size); + return GuiScaling.border(size, size, size, size); + } + + static NineSlice.Border border(final int left, final int top, final int right, final int bottom) { + return new NineSlice.Border(left, top, right, bottom); + } + + @Override + default MetadataSection.Gui asSection() { + return MetadataSection.gui(this); + } + + record Stretch() implements GuiScaling { + + public static final Stretch INSTANCE = new Stretch(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec mapCodec() { + return CODEC; + } + } + + record Tile(int width, int height) implements GuiScaling { + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance .group( + ExtraCodecs.POSITIVE_INT.fieldOf("width").forGetter(Tile::width), + ExtraCodecs.POSITIVE_INT.fieldOf("height").forGetter(Tile::height) + ).apply(instance, Tile::new)); + + public Tile(final int width, final int height) { + Preconditions.checkArgument(width > 0, "width must be positive: " + width); + Preconditions.checkArgument(height > 0, "height must be positive: " + height); + this.width = width; + this.height = height; + } + + @Override + public MapCodec mapCodec() { + return CODEC; + } + } + + record NineSlice( + int width, int height, Border border, boolean stretchInner + ) implements GuiScaling { + + public static final boolean DEFAULT_STRETCH_INNER = false; + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + ExtraCodecs.POSITIVE_INT.fieldOf("width").forGetter(NineSlice::width), + ExtraCodecs.POSITIVE_INT.fieldOf("height").forGetter(NineSlice::height), + Border.CODEC.fieldOf("border").forGetter(NineSlice::border), + Codec.BOOL.optionalFieldOf("stretch_inner", NineSlice.DEFAULT_STRETCH_INNER).forGetter(NineSlice::stretchInner) + ).apply(instance, NineSlice::new)) + .validate(NineSlice::validate); + + private static DataResult validate(NineSlice nineSlice) { + Border border = nineSlice.border(); + if (border.left() + border.right() >= nineSlice.width()) { + return DataResult.error(() -> "Nine-sliced texture has no horizontal center slice: " + + border.left() + " + " + border.right() + + " >= " + nineSlice.width()); + } else { + return border.top() + border.bottom() >= nineSlice + .height() + ? DataResult.error(() -> "Nine-sliced texture has no vertical center slice: " + + border.top() + " + " + border.bottom() + " >= " + nineSlice.height()) + : DataResult.success(nineSlice); + } + } + + public NineSlice(final int width, final int height, final Border border, final boolean stretchInner) { + Preconditions.checkArgument(width > 0, "width must be positive: " + width); + Preconditions.checkArgument(height > 0, "height must be positive: " + height); + this.width = width; + this.height = height; + this.border = Objects.requireNonNull(border, "border"); + this.stretchInner = stretchInner; + } + + @Override + public MapCodec mapCodec() { + return CODEC; + } + + public record Border(int left, int top, int right, int bottom) { + public static final Codec INLINE_CODEC = + ExtraCodecs.POSITIVE_INT.flatComapMap( + i -> new Border(i, i, i, i), + border -> { + OptionalInt optionalint = border.inlined(); + return optionalint.isPresent() ? DataResult.success(optionalint.getAsInt()) + : DataResult.error(() -> "Border has different side sizes"); + }); + + public static final Codec FULL_CODEC = RecordCodecBuilder.create( + instance -> instance.group( + ExtraCodecs.NON_NEGATIVE_INT.fieldOf("left").forGetter(Border::left), + ExtraCodecs.NON_NEGATIVE_INT.fieldOf("top").forGetter(Border::top), + ExtraCodecs.NON_NEGATIVE_INT.fieldOf("right").forGetter(Border::right), + ExtraCodecs.NON_NEGATIVE_INT.fieldOf("bottom").forGetter(Border::bottom) + ).apply(instance, Border::new)); + + public static final Codec CODEC = Codec.either(INLINE_CODEC, FULL_CODEC) + .xmap(Either::unwrap, border -> border.inlined().isPresent() + ? Either.left(border) + : Either.right(border)); + + public Border(final int left, final int top, final int right, final int bottom) { + Preconditions.checkArgument(left >= 0, "left must not be negative: " + left); + Preconditions.checkArgument(top >= 0, "top must not be negative: " + top); + Preconditions.checkArgument(right >= 0, "right must not be negative: " + right); + Preconditions.checkArgument(bottom >= 0, "bottom must not be negative: " + bottom); + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + private OptionalInt inlined() { + return this.left() == this.top() && this.top() == this.right() && this.right() == this.bottom() + ? OptionalInt.of(this.left()) + : OptionalInt.empty(); + } + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/Metadata.java b/src/main/java/net/hellheim/spongetools/custom/metadata/Metadata.java new file mode 100644 index 0000000..734c40a --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/metadata/Metadata.java @@ -0,0 +1,36 @@ +package net.hellheim.spongetools.custom.metadata; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.proxy.solid.codec.CodecProxy; + +public record Metadata(List sections) implements CodecProxy, MetadataLike { + + public static final Codec CODEC = MetadataSection.LIST_CODEC.xmap(Metadata::new, Metadata::sections); + + public Metadata(final List sections) { + this.sections = List.copyOf(sections); + } + + public static Metadata of(final MetadataSectionLike... sections) { + return new Metadata(Arrays.stream(sections).map(MetadataSectionLike::asSection).toList()); + } + + public static Metadata of(final Collection sections) { + return new Metadata(sections.stream().map(MetadataSectionLike::asSection).toList()); + } + + @Override + public Codec codec() { + return CODEC; + } + + @Override + public Metadata asMetadata() { + return this; + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataLike.java b/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataLike.java new file mode 100644 index 0000000..d2bfbdb --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataLike.java @@ -0,0 +1,6 @@ +package net.hellheim.spongetools.custom.metadata; + +public interface MetadataLike { + + Metadata asMetadata(); +} diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSection.java b/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSection.java new file mode 100644 index 0000000..34cc469 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSection.java @@ -0,0 +1,297 @@ +package net.hellheim.spongetools.custom.metadata; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import com.google.common.base.Preconditions; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.hellheim.spongetools.codec.list.AdventureCodecs; +import net.hellheim.spongetools.codec.list.ExtraCodecs; +import net.hellheim.spongetools.proxy.solid.codec.CodecProxy; +import net.kyori.adventure.text.Component; + +public interface MetadataSection extends CodecProxy, MetadataSectionLike { + + BiMap> ID_MAPPER = HashBiMap.create(); + + Codec> MAP_CODEC = Codec.dispatchedMap(Codec.STRING, ID_MAPPER::get); + + Codec> LIST_CODEC = MAP_CODEC.xmap( + map -> List.copyOf(map.values()), + list -> list.stream().collect(Collectors.toUnmodifiableMap( + section -> ID_MAPPER.inverse().get(section.codec()), + Function.identity() + )) + ); + + static Pack pack(final Component description, final int format) { + return MetadataSection.pack(description, format, Optional.empty()); + } + + static Pack pack(final Component description, final int format, final Pair supportedFormats) { + return MetadataSection.pack(description, format, Optional.of(supportedFormats)); + } + + static Pack pack(final Component description, final int format, final Optional> supportedFormats) { + supportedFormats.ifPresent(range -> { + final int min = range.getFirst(), max = range.getSecond(); + if (min > max) { + throw new IllegalArgumentException(String.format( + "min_inclusive (%s) must be less than or equal to max_inclusive (%s)", min, max)); + } + }); + return new Pack(description, format, supportedFormats); + } + + static Villager villager(final VillagerHat hat) { + return new Villager(hat); + } + + static Gui gui(final GuiScaling scaling) { + return new Gui(scaling); + } + + static Texture textureBlur(final boolean blur) { + return MetadataSection.texture(blur, Texture.DEFAULT_CLAMP); + } + + static Texture textureClamp(final boolean clamp) { + return MetadataSection.texture(Texture.DEFAULT_BLUR, clamp); + } + + static Texture texture(final boolean blur, final boolean clamp) { + return new Texture(blur, clamp); + } + + static Animation.Builder animation() { + return new Animation.Builder(); + } + + @Override + default MetadataSection asSection() { + return this; + } + + record Pack(Component description, int format, Optional> supportedFormats) implements MetadataSection { + public static final Codec> RANGE_CODEC = ExtraCodecs.interval(Codec.INT, + "min_inclusive", "max_inclusive", + (min, max) -> { + return min <= max + ? DataResult.success(Pair.of(min, max)) + : DataResult.error(() -> "min_inclusive must be less than or equal to max_inclusive"); + }, + Pair::getFirst, Pair::getSecond); + public static final Codec CODEC = RecordCodecBuilder.create( + p_337567_ -> p_337567_.group( + AdventureCodecs.COMPONENT.fieldOf("description").forGetter(Pack::description), + Codec.INT.fieldOf("pack_format").forGetter(Pack::format), + Pack.RANGE_CODEC.optionalFieldOf("supported_formats").forGetter(Pack::supportedFormats) + ).apply(p_337567_, Pack::new)); + + public Pack(final Component description, final int format, final Optional> supportedFormats) { + this.description = Objects.requireNonNull(description, "description"); + this.format = format; + this.supportedFormats = Objects.requireNonNull(supportedFormats, "supportedFormats"); + } + + @Override + public Codec codec() { + return CODEC; + } + } + + record Villager(VillagerHat hat) implements MetadataSection { + + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + VillagerHat.CODEC.optionalFieldOf("hat", VillagerHat.NONE).forGetter(Villager::hat) + ).apply(instance, Villager::new)); + + public Villager(final VillagerHat hat) { + this.hat = Objects.requireNonNull(hat, "hat"); + } + + @Override + public Codec codec() { + return CODEC; + } + } + + record Gui(GuiScaling scaling) implements MetadataSection { + + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + GuiScaling.CODEC.optionalFieldOf("scaling", GuiScaling.DEFAULT).forGetter(Gui::scaling) + ).apply(instance, Gui::new) + ); + + public Gui(final GuiScaling scaling) { + this.scaling = Objects.requireNonNull(scaling, "scaling"); + } + + @Override + public Codec codec() { + return CODEC; + } + } + + record Texture(boolean blur, boolean clamp) implements MetadataSection { + + public static final boolean DEFAULT_BLUR = false; + public static final boolean DEFAULT_CLAMP = false; + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + Codec.BOOL.optionalFieldOf("blur", Texture.DEFAULT_BLUR).forGetter(Texture::blur), + Codec.BOOL.optionalFieldOf("clamp", Texture.DEFAULT_CLAMP).forGetter(Texture::clamp) + ).apply(instance, Texture::new)); + + public Texture(final boolean blur, final boolean clamp) { + this.blur = blur; + this.clamp = clamp; + } + + @Override + public Codec codec() { + return CODEC; + } + } + + record Animation( + Optional width, Optional height, + int frameTime, boolean interpolate, + List frames + ) implements MetadataSection { + + public static final int DEFAULT_FRAME_TIME = 1; + public static final boolean DEFAULT_INTERPOLATE = false; + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + ExtraCodecs.POSITIVE_INT.optionalFieldOf("width").forGetter(Animation::width), + ExtraCodecs.POSITIVE_INT.optionalFieldOf("height").forGetter(Animation::height), + ExtraCodecs.POSITIVE_INT.optionalFieldOf("frametime", Animation.DEFAULT_FRAME_TIME).forGetter(Animation::frameTime), + Codec.BOOL.optionalFieldOf("interpolate", Animation.DEFAULT_INTERPOLATE).forGetter(Animation::interpolate), + AnimationFrame.CODEC.listOf().optionalFieldOf("frames", List.of()).forGetter(Animation::frames) + ).apply(instance, Animation::new)); + + public Animation( + final Optional width, final Optional height, + final int frameTime, final boolean interpolate, + final List frames + ) { + Objects.requireNonNull(width, "width").ifPresent(Animation::checkWidth); + Objects.requireNonNull(height, "height").ifPresent(Animation::checkHeight); + Animation.checkFrameTime(frameTime); + this.width = width; + this.height = height; + this.frameTime = frameTime; + this.interpolate = interpolate; + this.frames = List.copyOf(frames); + } + + private static void checkWidth(final @Nullable Integer width) { + if (width != null) { + Preconditions.checkArgument(width > 0, "width must be positive: " + width); + } + } + + private static void checkHeight(final @Nullable Integer height) { + if (height != null) { + Preconditions.checkArgument(height > 0, "height must be positive: " + height); + } + } + + private static void checkFrameTime(final int frameTime) { + Preconditions.checkArgument(frameTime > 0, "frameTime must be positive: " + frameTime); + } + + @Override + public Codec codec() { + return CODEC; + } + + public static final class Builder implements org.spongepowered.api.util.Builder { + + private @Nullable Integer width; + private @Nullable Integer height; + private int frameTime; + private boolean interpolate; + private final List frames = new ArrayList<>(); + + public Builder() { + this.reset(); + } + + public Builder addAll(final AnimationFrame... frames) { + for (AnimationFrame frame : Objects.requireNonNull(frames, "frames")) { + this.add(frame); + } + return this; + } + + public Builder addAll(final Iterable frames) { + for (AnimationFrame frame : Objects.requireNonNull(frames, "frames")) { + this.add(frame); + } + return this; + } + + public Builder add(final AnimationFrame frame) { + this.frames.add(Objects.requireNonNull(frame, "frame")); + return this; + } + + public Builder width(final @Nullable Integer width) { + Animation.checkWidth(width); + this.width = width; + return this; + } + + public Builder height(final @Nullable Integer height) { + Animation.checkHeight(height); + this.height = height; + return this; + } + + public Builder frameTime(final int frameTime) { + Animation.checkFrameTime(frameTime); + this.frameTime = frameTime; + return this; + } + + public Builder interpolate(final boolean interpolate) { + this.interpolate = interpolate; + return this; + } + + @Override + public Builder reset() { + this.width = null; + this.height = null; + this.frameTime = Animation.DEFAULT_FRAME_TIME; + this.interpolate = Animation.DEFAULT_INTERPOLATE; + this.frames.clear(); + return this; + } + + @Override + public Animation build() { + return new Animation( + Optional.ofNullable(this.width), Optional.ofNullable(this.height), + this.frameTime, this.interpolate, this.frames); + } + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSectionLike.java b/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSectionLike.java new file mode 100644 index 0000000..5c310e5 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSectionLike.java @@ -0,0 +1,11 @@ +package net.hellheim.spongetools.custom.metadata; + +public interface MetadataSectionLike extends MetadataLike { + + MetadataSection asSection(); + + @Override + default Metadata asMetadata() { + return Metadata.of(this); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/VillagerHat.java b/src/main/java/net/hellheim/spongetools/custom/metadata/VillagerHat.java new file mode 100644 index 0000000..52d0225 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/metadata/VillagerHat.java @@ -0,0 +1,31 @@ +package net.hellheim.spongetools.custom.metadata; + +import org.spongepowered.api.data.type.StringRepresentable; + +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.codec.StringRepresentableCodec; + +public enum VillagerHat implements StringRepresentable, MetadataSectionLike { + NONE("none"), + PARTIAL("partial"), + FULL("full"); + + public static final Codec CODEC = StringRepresentableCodec.fromValues(VillagerHat::values); + + private final String name; + + private VillagerHat(String name) { + this.name = name; + } + + @Override + public String serializationString() { + return this.name; + } + + @Override + public MetadataSection.Villager asSection() { + return MetadataSection.villager(this); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/ConditionalProperty.java b/src/main/java/net/hellheim/spongetools/custom/model/item/ConditionalProperty.java index 4a8e59c..8d06896 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/ConditionalProperty.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/ConditionalProperty.java @@ -11,13 +11,14 @@ import net.hellheim.spongetools.codec.LateBoundIdMapper; import net.hellheim.spongetools.codec.list.ExtraCodecs; import net.hellheim.spongetools.codec.list.SpongeCodecs; +import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; -public interface ConditionalProperty { +public interface ConditionalProperty extends MapCodecProxy { - final LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); + LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); - final MapCodec CODEC = ConditionalProperty.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) - .dispatchMap("property", ConditionalProperty::codec, Function.identity()); + MapCodec CODEC = ConditionalProperty.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) + .dispatchMap("property", ConditionalProperty::mapCodec, Function.identity()); static Broken broken() { return Broken.INSTANCE; @@ -63,14 +64,12 @@ static CustomModelData custom(final int index) { return new CustomModelData(index); } - MapCodec codec(); - record Broken() implements ConditionalProperty { public static final Broken INSTANCE = new Broken(); public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -80,7 +79,7 @@ record Damaged() implements ConditionalProperty { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -90,7 +89,7 @@ record Carried() implements ConditionalProperty { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -100,7 +99,7 @@ record Selected() implements ConditionalProperty { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -110,7 +109,7 @@ record ExtendedView() implements ConditionalProperty { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -120,7 +119,7 @@ record FishingRodCast() implements ConditionalProperty { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -130,7 +129,7 @@ record BundleHasSelectedItem() implements ConditionalProperty { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -140,7 +139,7 @@ record Using() implements ConditionalProperty { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -150,7 +149,7 @@ record ViewingEntity() implements ConditionalProperty { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -168,7 +167,7 @@ public CustomModelData(final int index) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemDefinition.java b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemDefinition.java index 493e559..46ff798 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemDefinition.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemDefinition.java @@ -14,13 +14,14 @@ import net.hellheim.spongetools.codec.LateBoundIdMapper; import net.hellheim.spongetools.codec.list.SpongeCodecs; +import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; -public interface ItemDefinition { +public interface ItemDefinition extends MapCodecProxy { - final LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); + LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); - final Codec CODEC = ItemDefinition.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) - .dispatch(ItemDefinition::codec, Function.identity()); + Codec CODEC = ItemDefinition.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) + .dispatch(ItemDefinition::mapCodec, Function.identity()); static Empty empty() { return Empty.INSTANCE; @@ -117,8 +118,6 @@ static Special special(final ResourceKey base, final SpecialModel model) { return new Special(base, model); } - MapCodec codec(); - default Item asItem(final boolean handAnimationOnSwap) { return Item.of(this, handAnimationOnSwap); } @@ -132,7 +131,7 @@ record Empty() implements ItemDefinition { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -142,7 +141,7 @@ record BundleSelectedItem() implements ItemDefinition { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -160,7 +159,7 @@ public Simple(final ResourceKey model, final List tints) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -176,7 +175,7 @@ public Composite(final List models) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -196,7 +195,7 @@ public Conditional(final ConditionalProperty property, final ItemDefinition onTr } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -214,7 +213,7 @@ public Select(final SelectSwitch body, final Optional fall } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -236,7 +235,7 @@ public RangeSelect(final RangeSelectProperty property, final float scale, final } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -254,7 +253,7 @@ public Special(final ResourceKey base, final SpecialModel model) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java b/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java index f3ef094..1f4ac1d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java @@ -15,13 +15,14 @@ import net.hellheim.spongetools.codec.list.SpongeCodecs; import net.hellheim.spongetools.custom.model.item.enums.CompassTarget; import net.hellheim.spongetools.custom.model.item.enums.TimeSource; +import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; -public interface RangeSelectProperty { +public interface RangeSelectProperty extends MapCodecProxy { - final LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); + LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); - final MapCodec CODEC = RangeSelectProperty.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) - .dispatchMap("property", RangeSelectProperty::codec, Function.identity()); + MapCodec CODEC = RangeSelectProperty.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) + .dispatchMap("property", RangeSelectProperty::mapCodec, Function.identity()); static Cooldown cooldown() { return Cooldown.INSTANCE; @@ -91,14 +92,12 @@ static Time time(final boolean wobble, final TimeSource source) { return new Time(wobble, source); } - MapCodec codec(); - record Cooldown() implements RangeSelectProperty { public static final Cooldown INSTANCE = new Cooldown(); public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -108,7 +107,7 @@ record BundleFullness() implements RangeSelectProperty { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -118,7 +117,7 @@ record CrossbowPull() implements RangeSelectProperty { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -131,7 +130,7 @@ record Quantity(boolean normalize) implements RangeSelectProperty { ).apply(instance, Quantity::new)); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -144,7 +143,7 @@ record Damage(boolean normalize) implements RangeSelectProperty { ).apply(instance, Damage::new)); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -162,7 +161,7 @@ public CustomModelData(final int index) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -180,7 +179,7 @@ public UseCycle(final float period) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -193,7 +192,7 @@ record UseDuration(boolean remaining) implements RangeSelectProperty { ).apply(instance, UseDuration::new)); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -212,7 +211,7 @@ public CompassAngle(final boolean wobble, final CompassTarget target) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -231,7 +230,7 @@ public Time(final boolean wobble, final TimeSource source) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java index e7e49cb..eba328d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java @@ -29,12 +29,13 @@ import net.hellheim.spongetools.codec.list.RegistryCodecs; import net.hellheim.spongetools.codec.list.SpongeCodecs; import net.hellheim.spongetools.custom.model.item.enums.ChargeType; +import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; -public interface SelectProperty { +public interface SelectProperty extends MapCodecProxy> { - final LateBoundIdMapper>> ID_MAPPER = new LateBoundIdMapper<>(); + LateBoundIdMapper>> ID_MAPPER = new LateBoundIdMapper<>(); - final Codec>> CODEC = SelectProperty.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY); + Codec>> CODEC = SelectProperty.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY); static Charge charge() { return Charge.INSTANCE; @@ -98,15 +99,13 @@ static LocalTime localTime(final String format, final Locale locale, final Optio return time; } - MapCodec> codec(); - record Charge() implements SelectProperty { public static final Charge INSTANCE = new Charge(); public static final MapCodec CODEC = MapCodec.unit(INSTANCE); public static final MapCodec> SWITCH = SelectProperty.create(CODEC, ChargeType.CODEC); @Override - public MapCodec> codec() { + public MapCodec> mapCodec() { return SWITCH; } } @@ -117,7 +116,7 @@ record World() implements SelectProperty> { public static final MapCodec> SWITCH = SelectProperty.create(CODEC, SpongeCodecs.registryKey(RegistryTypes.WORLD_TYPE)); @Override - public MapCodec> codec() { + public MapCodec> mapCodec() { return SWITCH; } } @@ -128,7 +127,7 @@ record Entity() implements SelectProperty> SWITCH = SelectProperty.create(CODEC, SpongeCodecs.registryKey(RegistryTypes.ENTITY_TYPE)); @Override - public MapCodec> codec() { + public MapCodec> mapCodec() { return SWITCH; } } @@ -139,7 +138,7 @@ record Trim() implements SelectProperty> { public static final MapCodec> SWITCH = SelectProperty.create(CODEC, SpongeCodecs.registryKey(RegistryTypes.TRIM_MATERIAL)); @Override - public MapCodec> codec() { + public MapCodec> mapCodec() { return SWITCH; } } @@ -150,7 +149,7 @@ record Display() implements SelectProperty { public static final MapCodec> SWITCH = SelectProperty.create(CODEC, ItemDisplayContext.CODEC); @Override - public MapCodec> codec() { + public MapCodec> mapCodec() { return SWITCH; } } @@ -161,7 +160,7 @@ record MainHand() implements SelectProperty { public static final MapCodec> SWITCH = SelectProperty.create(CODEC, RegistryCodecs.HAND_PREFERENCE); @Override - public MapCodec> codec() { + public MapCodec> mapCodec() { return SWITCH; } } @@ -180,7 +179,7 @@ public CustomModelData(final int index) { } @Override - public MapCodec> codec() { + public MapCodec> mapCodec() { return SWITCH; } } @@ -197,7 +196,7 @@ public StateProperty(final String property) { } @Override - public MapCodec> codec() { + public MapCodec> mapCodec() { return SWITCH; } } @@ -229,7 +228,7 @@ private static DataResult validate(LocalTime data) { } @Override - public MapCodec> codec() { + public MapCodec> mapCodec() { return SWITCH; } } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitch.java b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitch.java index 9900854..b795097 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitch.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitch.java @@ -8,7 +8,7 @@ public record SelectSwitch>(P property, List> cases) { public static final MapCodec> CODEC = SelectProperty.CODEC - .dispatchMap("property", s -> s.property().codec(), Function.identity()); + .dispatchMap("property", s -> s.property().mapCodec(), Function.identity()); public SelectSwitch(final P property, final List> cases) { this.property = Objects.requireNonNull(property, "property"); diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java b/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java index bfdd75d..41c2b57 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java @@ -17,13 +17,14 @@ import net.hellheim.spongetools.codec.list.SpongeCodecs; import net.hellheim.spongetools.codec.list.StringRepresentableCodecs; import net.hellheim.spongetools.custom.model.item.enums.SkullType; +import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; -public interface SpecialModel { +public interface SpecialModel extends MapCodecProxy { - final LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); + LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); - final Codec CODEC = SpecialModel.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) - .dispatch(SpecialModel::codec, Function.identity()); + Codec CODEC = SpecialModel.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) + .dispatch(SpecialModel::mapCodec, Function.identity()); static Conduit conduit() { return Conduit.INSTANCE; @@ -121,14 +122,12 @@ static Skull skull(final SkullType type, final float animation, final Optional codec(); - record Conduit() implements SpecialModel { public static final Conduit INSTANCE = new Conduit(); public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -138,7 +137,7 @@ record DecoratedPot() implements SpecialModel { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -148,7 +147,7 @@ record Trident() implements SpecialModel { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -158,7 +157,7 @@ record Shield() implements SpecialModel { public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -174,7 +173,7 @@ public Banner(final DyeColor base) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -190,7 +189,7 @@ public Bed(final ResourceKey texture) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -209,7 +208,7 @@ public Chest(final ResourceKey texture, final float openness) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -232,7 +231,7 @@ public ShulkerBox(final ResourceKey texture, final float openness, final Directi } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -250,7 +249,7 @@ public StandingSign(final String woodType, final Optional texture) } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -268,7 +267,7 @@ public HangingSign(final String woodType, final Optional texture) { } @Override - public MapCodec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -289,7 +288,7 @@ public Skull(final SkullType type, final float animation, final Optional codec() { + public MapCodec mapCodec() { return CODEC; } } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/TintSource.java b/src/main/java/net/hellheim/spongetools/custom/model/item/TintSource.java index d8b88b7..bf5bd9c 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/TintSource.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/TintSource.java @@ -15,9 +15,9 @@ public interface TintSource { - final LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); + LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); - final Codec CODEC = TintSource.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) + Codec CODEC = TintSource.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) .dispatch(TintSource::codec, Function.identity()); static Constant constant(final int value) { From ee2b212a9f98b38865744db7c40e78e033aa319b Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sun, 20 Apr 2025 18:47:03 +0300 Subject: [PATCH 09/55] continue custom stuff --- .../net/hellheim/spongetools/SpongeTools.java | 32 ++++-- .../spongetools/codec/list/DataCodecs.java | 58 +++++++++- .../codec/list/RegistryCodecs.java | 22 +++- .../codec/list/StringRepresentableCodecs.java | 5 + .../custom/behaviour/Behaviour.java | 33 ++++++ .../custom/behaviour/BehaviourHolder.java | 54 ++++++++++ .../behaviour/BehaviourHolderProxy.java | 17 +++ .../custom/behaviour/BehaviourManager.java | 43 ++++++++ .../custom/behaviour/BehaviourMerger.java | 15 +++ .../custom/behaviour/BehaviourType.java | 8 ++ .../AnalogSignalPowerBlockStateBehaviour.java | 19 ++++ .../block/state/BlockStateBehaviour.java | 18 ++++ .../block/state/BlockStateBehaviours.java | 82 ++++++++++++++ .../block/state/BlockStateExtension.java | 27 +++++ .../state/MapColorBlockStateBehaviour.java | 20 ++++ .../NeighbourUpdateBlockStateBehaviour.java | 11 ++ .../PushReactionBlockStateBehaviour.java | 17 +++ .../state/ReplaceBlockStateBehaviour.java | 20 ++++ .../state/ShapeUpdateBlockStateBehaviour.java | 29 +++++ .../SignalConductorBlockStateBehaviour.java | 19 ++++ .../state/SignalPowerBlockStateBehaviour.java | 20 ++++ .../SpawnValidatorBlockStateBehaviour.java | 20 ++++ .../block/state/TickBlockStateBehaviour.java | 20 ++++ .../custom/block/BlockStateProvider.java | 92 ++++++++++++++++ .../custom/block/BlockStateRegistrar.java | 31 ++++++ .../custom/block/CustomBlockType.java | 12 +++ .../block/DefaultedCustomBlockType.java | 26 +++++ .../block/NoAvailableStateException.java | 14 +++ .../custom/item/CustomItemType.java | 15 ++- .../custom/item/CustomItemTypeProperties.java | 2 +- .../custom/item/EitherItemType.java | 21 +++- .../custom/item/data/CustomConsumeEffect.java | 61 +++++++++++ .../custom/metadata/MetadataSection.java | 27 ++--- .../spongetools/custom/model/item/Item.java | 5 + .../custom/model/item/ItemDisplayContext.java | 33 ------ .../custom/model/item/ItemModel.java | 5 + .../custom/model/item/ItemTransforms.java | 41 +++++-- .../custom/model/item/SelectProperty.java | 6 +- .../event/RegisterBehaviourDataEvent.java | 58 ++++++++++ .../RegisterBlockStateBehaviourEvent.java | 102 ++++++++++++++++++ .../object/CodecDataSerializable.java | 22 ++++ ...taHolderBuilder.java => DataOperator.java} | 2 +- .../spongetools/object/ValueSetBuilder.java | 2 +- .../proxy/solid/codec/CodecProxy.java | 2 +- 44 files changed, 1101 insertions(+), 87 deletions(-) create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourMerger.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviours.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateExtension.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/NeighbourUpdateBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/block/NoAvailableStateException.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/item/data/CustomConsumeEffect.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/model/item/ItemDisplayContext.java create mode 100644 src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java create mode 100644 src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java create mode 100644 src/main/java/net/hellheim/spongetools/object/CodecDataSerializable.java rename src/main/java/net/hellheim/spongetools/object/{DataHolderBuilder.java => DataOperator.java} (97%) diff --git a/src/main/java/net/hellheim/spongetools/SpongeTools.java b/src/main/java/net/hellheim/spongetools/SpongeTools.java index e7831d8..9de8b4b 100644 --- a/src/main/java/net/hellheim/spongetools/SpongeTools.java +++ b/src/main/java/net/hellheim/spongetools/SpongeTools.java @@ -1,15 +1,19 @@ package net.hellheim.spongetools; import org.spongepowered.api.ResourceKey; -import org.spongepowered.api.Sponge; import org.spongepowered.api.data.Key; import org.spongepowered.api.data.persistence.DataQuery; +import org.spongepowered.api.data.value.ListValue; import org.spongepowered.api.data.value.Value; import org.spongepowered.api.registry.DefaultedRegistryType; import org.spongepowered.api.registry.RegistryRoots; import org.spongepowered.api.registry.RegistryType; +import com.mojang.serialization.MapCodec; + import net.hellheim.spongetools.custom.item.CustomItemType; +import net.hellheim.spongetools.custom.item.EitherItemType; +import net.hellheim.spongetools.custom.item.data.CustomConsumeEffect; import net.hellheim.spongetools.custom.model.item.Item; import net.hellheim.spongetools.custom.model.item.ItemModel; @@ -23,20 +27,24 @@ public static ResourceKey key(final String value) { public static final class Registries { - public static final DefaultedRegistryType CUSTOM_ITEM = Registries.registry("custom_item"); + public static final DefaultedRegistryType CUSTOM_ITEM_TYPE = Registries.key("item"); + + public static final DefaultedRegistryType EITHER_ITEM_TYPE = Registries.key("either_item"); /** * Items from this registry will be included in built ResourcePack. */ - public static final DefaultedRegistryType ITEM = Registries.registry("items"); + public static final DefaultedRegistryType ITEM = Registries.key("items"); /** * Models from this registry will be included in built ResourcePack. */ - public static final DefaultedRegistryType ITEM_MODEL = Registries.registry("model/item"); + public static final DefaultedRegistryType ITEM_MODEL = Registries.key("models/item"); + + public static final DefaultedRegistryType> CONSUME_EFFECT_TYPE = Registries.key("consume_effect_type"); - private static DefaultedRegistryType registry(final String key) { - return RegistryType.of(RegistryRoots.SPONGE, SpongeTools.key(key)).asDefaultedType(Sponge::server); + private static DefaultedRegistryType key(final String key) { + return RegistryType.of(RegistryRoots.SPONGE, SpongeTools.key(key)).asScopedType(); } private Registries() { @@ -45,19 +53,25 @@ private Registries() { public static final class Keys { - public static final Key> CUSTOM_ITEM = Keys.key("custom_item", CustomItemType.class); + public static final Key> ITEM_TYPE = Keys.key("item", CustomItemType.class); + + public static final Key> CONSUME_EFFECTS = Keys.listKey("consume_effects", CustomConsumeEffect.class); private static Key> key(final String key, final Class type) { return Key.from(SpongeTools.key(key), type); } + private static Key> listKey(final String key, final Class type) { + return Key.fromList(SpongeTools.key(key), type); + } + private Keys() { } } public static final class Queries { - public static final DataQuery CUSTOM_ITEM = DataQuery.of("custom_item"); + public static final DataQuery ITEM_TYPE = DataQuery.of("item"); private Queries() { } @@ -65,7 +79,7 @@ private Queries() { public static final class Versions { - public static final int CUSTOM_ITEM = 0; + public static final int ITEM_TYPE = 0; private Versions() { } diff --git a/src/main/java/net/hellheim/spongetools/codec/list/DataCodecs.java b/src/main/java/net/hellheim/spongetools/codec/list/DataCodecs.java index 22559dc..d63b41d 100644 --- a/src/main/java/net/hellheim/spongetools/codec/list/DataCodecs.java +++ b/src/main/java/net/hellheim/spongetools/codec/list/DataCodecs.java @@ -14,14 +14,23 @@ import org.spongepowered.api.data.Key; import org.spongepowered.api.data.persistence.DataBuilder; import org.spongepowered.api.data.persistence.DataContainer; +import org.spongepowered.api.data.persistence.DataFormats; import org.spongepowered.api.data.persistence.DataSerializable; +import org.spongepowered.api.data.persistence.DataView; import org.spongepowered.api.data.persistence.InvalidDataException; import org.spongepowered.api.data.persistence.StringDataFormat; import org.spongepowered.api.data.value.Value; import org.spongepowered.api.data.value.ValueContainer; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; +import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.JsonOps; /** * Codecs for SpongeAPI's DataAPI types @@ -104,7 +113,7 @@ public static Codec serializable( } return DataResult.success(value.get()); - } catch (InvalidDataException e) { + } catch (final InvalidDataException e) { return DataResult.error(e::toString); } }, DataSerializable::toContainer); @@ -115,23 +124,64 @@ public static Codec container(final Supplier container(final StringDataFormat format) { + return DataCodecs.CONTAINERS.computeIfAbsent(format, f -> DataCodecs.container(Codec.STRING, format)); + } + + public static Codec container(final Codec stringCodec, final Supplier format) { + return DataCodecs.container(stringCodec, format.get()); + } + + public static Codec container(final Codec stringCodec, final StringDataFormat format) { return DataCodecs.CONTAINERS.computeIfAbsent(format, f -> { - return Codec.STRING.flatXmap(string -> { + return stringCodec.flatXmap(string -> { try { return DataResult.success(f.read(string)); - } catch (IOException e) { + } catch (final IOException e) { return DataResult.error(e::toString); } }, container -> { try { return DataResult.success(f.write(container)); - } catch (IOException e) { + } catch (final IOException e) { return DataResult.error(e::toString); } }); }); } + private static final Gson GSON = new GsonBuilder().create(); + public static DataContainer toContainer(final Codec codec, final T value) { + final DataResult encoded = codec.encodeStart(JsonOps.INSTANCE, value); + final JsonElement json = encoded.getOrThrow(IllegalArgumentException::new); + final String str = GSON.toJson(json); + try { + return DataFormats.JSON.get().read(str); + } catch (final IOException | InvalidDataException e) { + // Should never happen + throw new RuntimeException(e); + } + } + + public static T fromContainer(final Codec codec, final DataView container) throws InvalidDataException { + try { + final String str = DataFormats.JSON.get().write(container); + final JsonElement json = JsonParser.parseString(str); + final DataResult decoded = codec.decode(JsonOps.INSTANCE, json).map(Pair::getFirst); + return decoded.getOrThrow(InvalidDataException::new); + } catch (final IOException | JsonParseException e) { + throw new InvalidDataException(e); + } + } + + public static DataBuilder dataBuilder(final Codec codec) { + return new DataBuilder<>() { + @Override + public Optional build(final DataView container) throws InvalidDataException { + return Optional.of(DataCodecs.fromContainer(codec, container)); + } + }; + } + private static > Value.Immutable entryToValue( final Map.Entry, Object> entry ) { diff --git a/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java b/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java index d2ac5ae..aa8f3c9 100644 --- a/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java +++ b/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java @@ -93,8 +93,8 @@ import org.spongepowered.api.event.cause.entity.MovementType; import org.spongepowered.api.event.cause.entity.SpawnType; import org.spongepowered.api.event.cause.entity.damage.DamageEffect; -import org.spongepowered.api.event.cause.entity.damage.DamageModifierType; import org.spongepowered.api.event.cause.entity.damage.DamageScaling; +import org.spongepowered.api.event.cause.entity.damage.DamageStepType; import org.spongepowered.api.event.cause.entity.damage.DamageType; import org.spongepowered.api.fluid.FluidType; import org.spongepowered.api.item.FireworkShape; @@ -170,8 +170,14 @@ import org.spongepowered.api.world.weather.WeatherType; import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import net.hellheim.spongetools.SpongeTools; import net.hellheim.spongetools.custom.item.CustomItemType; +import net.hellheim.spongetools.custom.item.EitherItemType; +import net.hellheim.spongetools.custom.item.data.CustomConsumeEffect; +import net.hellheim.spongetools.custom.model.item.Item; +import net.hellheim.spongetools.custom.model.item.ItemModel; /** * Codecs for all {@link RegistryType}s provided by SpongeAPI. @@ -180,7 +186,15 @@ public final class RegistryCodecs { // SpongeToolsAPI - public static final Codec CUSTOM_ITEM = RegistryCodecs.register(CustomItemType.class, CustomItemType.registry()); + public static final Codec CUSTOM_ITEM_TYPE = RegistryCodecs.register(CustomItemType.class, CustomItemType.registry()); + + public static final Codec EITHER_ITEM_TYPE = RegistryCodecs.register(EitherItemType.class, EitherItemType.registry()); + + public static final Codec ITEM = RegistryCodecs.register(Item.class, Item.registry()); + + public static final Codec ITEM_MODEL = RegistryCodecs.register(ItemModel.class, ItemModel.registry()); + + public static final Codec> CUSTOM_CONSUME_EFFECT_TYPE = RegistryCodecs.of(SpongeTools.Registries.CONSUME_EFFECT_TYPE); // SpongeAPI @@ -324,7 +338,7 @@ public final class RegistryCodecs { public static final Codec CURRENCY = RegistryCodecs.register(Currency.class, RegistryTypes.CURRENCY); - public static final Codec DAMAGE_MODIFIER_TYPE = RegistryCodecs.register(DamageModifierType.class, RegistryTypes.DAMAGE_MODIFIER_TYPE); + public static final Codec DAMAGE_STEP_TYPE = RegistryCodecs.register(DamageStepType.class, RegistryTypes.DAMAGE_STEP_TYPE); public static final Codec DAMAGE_TYPE = RegistryCodecs.register(DamageType.class, RegistryTypes.DAMAGE_TYPE); @@ -508,7 +522,7 @@ public final class RegistryCodecs { public static final Codec WEATHER_TYPE = RegistryCodecs.register(WeatherType.class, RegistryTypes.WEATHER_TYPE); - public static final Codec WOLF_VARIANT = RegistryCodecs.register(WolfVariant.class, RegistryTypes.WOLF_VAIRANT); + public static final Codec WOLF_VARIANT = RegistryCodecs.register(WolfVariant.class, RegistryTypes.WOLF_VARIANT); public static final Codec WORLD_ARCHETYPE_TYPE = RegistryCodecs.register(WorldArchetypeType.class, RegistryTypes.WORLD_ARCHETYPE_TYPE); diff --git a/src/main/java/net/hellheim/spongetools/codec/list/StringRepresentableCodecs.java b/src/main/java/net/hellheim/spongetools/codec/list/StringRepresentableCodecs.java index cb30112..844012d 100644 --- a/src/main/java/net/hellheim/spongetools/codec/list/StringRepresentableCodecs.java +++ b/src/main/java/net/hellheim/spongetools/codec/list/StringRepresentableCodecs.java @@ -3,6 +3,7 @@ import org.spongepowered.api.Sponge; import org.spongepowered.api.data.type.DyeColor; import org.spongepowered.api.data.type.HandPreference; +import org.spongepowered.api.entity.display.ItemDisplayType; import com.mojang.serialization.Codec; @@ -12,6 +13,8 @@ public final class StringRepresentableCodecs { public static final Codec HAND_PREFERENCE = StringRepresentableCodecs.factory().handPreference(); + public static final Codec ITEM_DISPLAY_TYPE = StringRepresentableCodecs.factory().itemDisplayType(); + private static Factory factory() { return Sponge.game().factoryProvider().provide(Factory.class); } @@ -21,6 +24,8 @@ public static interface Factory { Codec dyeColor(); Codec handPreference(); + + Codec itemDisplayType(); } private StringRepresentableCodecs() { diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java new file mode 100644 index 0000000..3ebca91 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java @@ -0,0 +1,33 @@ +package net.hellheim.spongetools.custom.behaviour; + +import java.util.Optional; + +import com.mojang.serialization.MapCodec; + +/** + * Represents some action a {@link BehaviourHolder} can do. + */ +public interface Behaviour { + + interface Extendable> extends Behaviour { + } + + /** + * Callbacks are used to add additional behaviour on top of the default one. + * + * @param The return type of this callback + */ + interface Callback { + } + + /** + * TODO + * @param The return type of this callback + */ + interface SerializableCallback extends Callback { + + default Optional>> codec() { + return Optional.empty(); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java new file mode 100644 index 0000000..9d3739a --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java @@ -0,0 +1,54 @@ +package net.hellheim.spongetools.custom.behaviour; + +import java.util.NoSuchElementException; +import java.util.Optional; + +/** + * Represents something that can have {@link Behaviour}s. + */ +public interface BehaviourHolder { + + /** + * Returns whether the given type is registered for this {@link BehaviourHolder}. + * + * @param type The type of the behaviour + * @return True if this holder supports the given type + */ + default boolean supports(final BehaviourType type) { + return BehaviourManager.get().supports(this.unwrap(), type); + } + + /** + * Returns the actual behaviour this {@link BehaviourHolder} will use, if present. + * If no behaviour callbacks are registered, this would be the "vanilla" behaviour. + * + * @param type The type of the behaviour + * @return The behaviour, if present + */ + default Optional get(final BehaviourType type) { + return BehaviourManager.get().get(this.unwrap(), type); + } + + /** + * Returns the actual behaviour this {@link BehaviourHolder} will use. + * If no custom behaviour is registered, this would be the "vanilla" behaviour. + * + * @param type The type of the behaviour + * @return The behaviour + * @throws NoSuchElementException if the type is not present on this {@link BehaviourHolder} + */ + default B require(final BehaviourType type) { + return this.get(type).orElseThrow(() -> new NoSuchElementException(String.format( + "No behaviour of type %s is present for holder %s", + type, this.unwrap() + ))); + } + + private Object unwrap() { + Object actualHolder = this; + while (actualHolder instanceof final BehaviourHolderProxy proxy) { + actualHolder = proxy.owner(); + } + return actualHolder; + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java new file mode 100644 index 0000000..571ea6b --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java @@ -0,0 +1,17 @@ +package net.hellheim.spongetools.custom.behaviour; + +/** + * Represents the wrapper around the actual behaviour holder + * that does not directly implement {@link BehaviourHolder}. + * + * @param The type of the actual behaviour holder + */ +public interface BehaviourHolderProxy extends BehaviourHolder { + + /** + * Returns the owner of this extension. + * + * @return The owner of this extension + */ + H owner(); +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java new file mode 100644 index 0000000..f5b4c1c --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java @@ -0,0 +1,43 @@ +package net.hellheim.spongetools.custom.behaviour; + +import java.util.Optional; +import java.util.function.Function; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.Sponge; + +public interface BehaviourManager { + + static BehaviourManager get() { + return Sponge.game().factoryProvider().provide(BehaviourManager.class); + } + + , B extends Behaviour.Extendable> Function callbackProvider( + BehaviourType type + ); + + , B extends Behaviour.Extendable> BehaviourMerger callbackMerger( + BehaviourType type + ); + + boolean supports(H holder, BehaviourType type); + + Optional get(H holder, BehaviourType type); + + , B extends Behaviour.Extendable> void register( + BehaviourType type, Function callbackProvider + ); + + , B extends Behaviour.Extendable> void register( + BehaviourType type, BehaviourMerger callbackMerger + ); + + BehaviourRegistration create(Class holder); + + interface BehaviourRegistration { + + BehaviourRegistration register( + BehaviourType type, Function behaviourProvider + ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourMerger.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourMerger.java new file mode 100644 index 0000000..2217530 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourMerger.java @@ -0,0 +1,15 @@ +package net.hellheim.spongetools.custom.behaviour; + +@FunctionalInterface +public interface BehaviourMerger> { + + /** + * Wraps the second behaviour around the first behaviour.
+ * Means that first behaviour becomes the "original" for the second one. + * + * @param b1 The "original" behaviour + * @param b2 The "wrapper" behaviour + * @return The merged behaviour + */ + C merge(C b1, C b2); +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java new file mode 100644 index 0000000..72b19e3 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java @@ -0,0 +1,8 @@ +package net.hellheim.spongetools.custom.behaviour; + +public interface BehaviourType { + + static BehaviourType create() { + return new BehaviourType<>() {}; + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java new file mode 100644 index 0000000..cf93724 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java @@ -0,0 +1,19 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import org.spongepowered.api.world.World; +import org.spongepowered.math.vector.Vector3i; + +public interface AnalogSignalPowerBlockStateBehaviour + extends BlockStateBehaviour { + + int apply(World world, Vector3i position); + + @FunctionalInterface + interface Callback extends BlockStateBehaviour.Callback { + + int apply( + BlockStateExtension state, AnalogSignalPowerBlockStateBehaviour origin, + World world, Vector3i position + ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviour.java new file mode 100644 index 0000000..9d19234 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviour.java @@ -0,0 +1,18 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import java.util.Optional; + +import com.mojang.serialization.MapCodec; + +import net.hellheim.spongetools.custom.behaviour.Behaviour; + +public interface BlockStateBehaviour> extends Behaviour.Extendable { + + interface Callback extends Behaviour.SerializableCallback { + + @Override + default Optional>> codec() { + return Optional.empty(); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviours.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviours.java new file mode 100644 index 0000000..189db74 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviours.java @@ -0,0 +1,82 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockTypes; +import org.spongepowered.api.world.volume.game.UpdatableVolume; + +import net.hellheim.spongetools.custom.behaviour.BehaviourType; + +public final class BlockStateBehaviours { + + public static final BehaviourType SPAWN_VALIDATOR = BehaviourType.create(); + + public static final BehaviourType MAP_COLOR = BehaviourType.create(); + + /** + * Used by {@link BlockTypes#PISTON} and {@link BlockTypes#STICKY_PISTON}. + */ + public static final BehaviourType PUSH_REACTION = BehaviourType.create(); + + public static final BehaviourType SIGNAL_CONDUCTOR = BehaviourType.create(); + + /** + * Signal that will power neighbour blocks. + */ + public static final BehaviourType SIGNAL_POWER = BehaviourType.create(); + + /** + * Signal that will go through neighbour blocks.
+ * + * In vanilla this behaviour usually filters result of + * {@link BlockStateExtension#origin(BlockBehaviourType)} + * for {@link #SIGNAL_POWER} behaviour by side.
+ * + * Used by {@link BlockTypes#REPEATER} (horizontally) and other redstone-related blocks (upwards). + */ + public static final BehaviourType DIRECT_SIGNAL_POWER = BehaviourType.create(); + + /** + * Result of this behaviour is usually used by {@link BlockTypes#COMPARATOR}. + */ + public static final BehaviourType ANALOG_SIGNAL_POWER = BehaviourType.create(); + + /** + * Adding this behaviour doesn't make block ticking "naturally".
+ * Ticks must be scheduled through {@link UpdatableVolume#scheduledBlockUpdates()}.
+ * For example, ticks could be scheduled in {@link #PLACE}, {@link #SHAPE_UPDATE} or in {@link #TICK} itself. + */ + public static final BehaviourType TICK = BehaviourType.create(); + + public static final BehaviourType RANDOM_TICK = BehaviourType.create(); + + /** + * Called when block enters the world. + */ + public static final BehaviourType PLACE = BehaviourType.create(); + + /** + * Called when block leaves the world. + */ + public static final BehaviourType REMOVE = BehaviourType.create(); + + /** + * Called when neighbour {@link BlockState}s are changed.
+ * This is usually used to update properties that could + * considered as "shape" depending on neighbour blocks + * and by waterlogged blocks to schedule liquid ticks. + * + * @see #NEIGHBOUR_UPDATE + */ + public static final BehaviourType SHAPE_UPDATE = BehaviourType.create(); + + /** + * Called when neighbour {@link BlockState}s are changed.
+ * This is usually used to update properties that rely on redstone signal + * + * @see #SHAPE_UPDATE + */ + public static final BehaviourType NEIGHBOUR_UPDATE = BehaviourType.create(); + + private BlockStateBehaviours() { + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateExtension.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateExtension.java new file mode 100644 index 0000000..a8616b8 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateExtension.java @@ -0,0 +1,27 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import org.spongepowered.api.Sponge; +import org.spongepowered.api.block.BlockState; + +import net.hellheim.spongetools.custom.behaviour.BehaviourHolderProxy; +import net.hellheim.spongetools.proxy.solid.block.BlockStateProxy; + +/** + * Can be used to override default {@link BlockState} behaviour. + */ +public interface BlockStateExtension extends BehaviourHolderProxy, BlockStateProxy { + + static BlockStateExtension getFor(final BlockState state) { + return Sponge.game().factoryProvider().provide(Factory.class).getFor(state); + } + + @Override + default BlockState getAsBlockState() { + return this.owner(); + } + + interface Factory { + + BlockStateExtension getFor(final BlockState state); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java new file mode 100644 index 0000000..0ef980b --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java @@ -0,0 +1,20 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import org.spongepowered.api.map.color.MapColorType; +import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; +import org.spongepowered.math.vector.Vector3i; + +public interface MapColorBlockStateBehaviour + extends BlockStateBehaviour { + + MapColorType apply(PrimitiveGameVolume volume, Vector3i position); + + @FunctionalInterface + interface Callback extends BlockStateBehaviour.Callback { + + MapColorType apply( + BlockStateExtension state, MapColorBlockStateBehaviour origin, + PrimitiveGameVolume volume, Vector3i position + ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/NeighbourUpdateBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/NeighbourUpdateBlockStateBehaviour.java new file mode 100644 index 0000000..b364d46 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/NeighbourUpdateBlockStateBehaviour.java @@ -0,0 +1,11 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +public interface NeighbourUpdateBlockStateBehaviour + extends BlockStateBehaviour { + + + + interface Callback extends BlockStateBehaviour.Callback { + + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java new file mode 100644 index 0000000..53b3924 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java @@ -0,0 +1,17 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import org.spongepowered.api.data.type.PushReaction; + +public interface PushReactionBlockStateBehaviour + extends BlockStateBehaviour { + + PushReaction apply(); + + @FunctionalInterface + interface Callback extends BlockStateBehaviour.Callback { + + PushReaction apply( + BlockStateExtension state, PushReactionBlockStateBehaviour origin + ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java new file mode 100644 index 0000000..5bbf9bf --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java @@ -0,0 +1,20 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.world.World; +import org.spongepowered.math.vector.Vector3i; + +public interface ReplaceBlockStateBehaviour + extends BlockStateBehaviour { + + void apply(World world, Vector3i position, BlockState otherState, boolean movedByPiston); + + @FunctionalInterface + interface Callback extends BlockStateBehaviour.Callback { + + void apply( + BlockStateExtension state, ReplaceBlockStateBehaviour origin, + World world, Vector3i position, BlockState otherState, boolean movedByPiston + ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java new file mode 100644 index 0000000..c4ea9e4 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java @@ -0,0 +1,29 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.util.RandomProvider; +import org.spongepowered.api.world.volume.game.Region; +import org.spongepowered.api.world.volume.game.UpdatableVolume; +import org.spongepowered.math.vector.Vector3i; + +public interface ShapeUpdateBlockStateBehaviour + extends BlockStateBehaviour { + + BlockState apply( + Region region, UpdatableVolume volume, Vector3i position, + Direction direction, Vector3i neighbourPosition, BlockState neighbourState, + RandomProvider.Source random + ); + + @FunctionalInterface + interface Callback extends BlockStateBehaviour.Callback { + + BlockState apply( + BlockStateExtension state, ShapeUpdateBlockStateBehaviour origin, + Region region, UpdatableVolume volume, Vector3i position, + Direction direction, Vector3i neighbourPosition, BlockState neighbourState, + RandomProvider.Source random + ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java new file mode 100644 index 0000000..4680fe2 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java @@ -0,0 +1,19 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; +import org.spongepowered.math.vector.Vector3i; + +public interface SignalConductorBlockStateBehaviour + extends BlockStateBehaviour { + + boolean apply(PrimitiveGameVolume volume, Vector3i position); + + @FunctionalInterface + interface Callback extends BlockStateBehaviour.Callback { + + boolean apply( + BlockStateExtension state, SignalConductorBlockStateBehaviour origin, + PrimitiveGameVolume volume, Vector3i position + ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java new file mode 100644 index 0000000..2542177 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java @@ -0,0 +1,20 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; +import org.spongepowered.math.vector.Vector3i; + +public interface SignalPowerBlockStateBehaviour + extends BlockStateBehaviour { + + int apply(PrimitiveGameVolume volume, Vector3i position, Direction direction); + + @FunctionalInterface + interface Callback extends BlockStateBehaviour.Callback { + + int apply( + BlockStateExtension state, SignalPowerBlockStateBehaviour origin, + PrimitiveGameVolume volume, Vector3i position, Direction direction + ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java new file mode 100644 index 0000000..ce26777 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java @@ -0,0 +1,20 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import org.spongepowered.api.entity.EntityType; +import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; +import org.spongepowered.math.vector.Vector3i; + +public interface SpawnValidatorBlockStateBehaviour + extends BlockStateBehaviour { + + boolean apply(PrimitiveGameVolume volume, Vector3i position, EntityType entity); + + @FunctionalInterface + interface Callback extends BlockStateBehaviour.Callback { + + boolean apply( + BlockStateExtension state, SpawnValidatorBlockStateBehaviour origin, + PrimitiveGameVolume volume, Vector3i position, EntityType entity + ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java new file mode 100644 index 0000000..bf69dea --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java @@ -0,0 +1,20 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import org.spongepowered.api.util.RandomProvider; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.math.vector.Vector3i; + +public interface TickBlockStateBehaviour + extends BlockStateBehaviour { + + void apply(ServerWorld world, Vector3i position, RandomProvider.Source random); + + @FunctionalInterface + interface Callback extends BlockStateBehaviour.Callback { + + void apply( + BlockStateExtension state, TickBlockStateBehaviour origin, + ServerWorld world, Vector3i position, RandomProvider.Source random + ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java b/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java new file mode 100644 index 0000000..0da70d2 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java @@ -0,0 +1,92 @@ +package net.hellheim.spongetools.custom.block; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.data.type.SlabPortions; +import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.api.state.BooleanStateProperties; +import org.spongepowered.api.state.EnumStateProperties; +import org.spongepowered.api.tag.BlockTypeTags; + +public interface BlockStateProvider/* extends MapCodecProxy*/ { + + @SafeVarargs + static Any any(final Supplier... blocks) { + return new Any(Arrays.stream(blocks).map(Supplier::get).collect(Collectors.toUnmodifiableSet())); + } + + static Any any(final BlockType... blocks) { + return new Any(Set.of(blocks)); + } + + static Any any(final Collection blocks) { + return new Any(Set.copyOf(blocks)); + } + + static Slab slab() { + return Slab.INSTANCE; + } + + + default BlockState provide() throws NoAvailableStateException { + return this.provide($ -> true); + } + + default BlockState provide(final Predicate predicate) throws NoAvailableStateException { + return this.availableStates() + .filter(predicate) + .findAny() + .orElseThrow(this::createException); + } + + default Stream availableStates() { + return this.allStates().filter(BlockStateRegistrar::isAvailable); + } + + Stream allStates(); + + default NoAvailableStateException createException() { + return new NoAvailableStateException(); + } + + + record Any(Set blocks) implements BlockStateProvider { + + public Any(final Set blocks) { + this.blocks = Set.copyOf(blocks); + } + + @Override + public Stream allStates() { + return this.blocks.stream().flatMap(block -> block.validStates().stream()); + } + + @Override + public NoAvailableStateException createException() { + return new NoAvailableStateException(this.blocks.toString()); + } + } + + record Slab() implements BlockStateProvider { + + public static final Slab INSTANCE = new Slab(); + + @Override + public Stream allStates() { + return RegistryTypes.BLOCK_TYPE.get().taggedValues(BlockTypeTags.SLABS).stream() + .flatMap(block -> block.validStates().stream()) + .filter(state -> state + .stateProperty(EnumStateProperties.property_SLAB_TYPE()).orElse(null) == SlabPortions.DOUBLE.get()) + .filter(state -> state + .stateProperty(BooleanStateProperties.property_WATERLOGGED()).orElse(false)); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java b/src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java new file mode 100644 index 0000000..f209f38 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java @@ -0,0 +1,31 @@ +package net.hellheim.spongetools.custom.block; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import org.spongepowered.api.block.BlockState; + +public final class BlockStateRegistrar { + + public static final Set OCCUPIED_STATES = new HashSet<>(); + + public static boolean isOccupied(final BlockState state) { + return BlockStateRegistrar.OCCUPIED_STATES.contains(Objects.requireNonNull(state, "state")); + } + + public static boolean isAvailable(final BlockState state) { + return !BlockStateRegistrar.isOccupied(state); + } + + public static void register(final BlockState state) { + if (BlockStateRegistrar.isOccupied(state)) { + throw new IllegalArgumentException("State already occupied: " + state.asString()); + } + + BlockStateRegistrar.OCCUPIED_STATES.add(state); + } + + private BlockStateRegistrar() { + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java new file mode 100644 index 0000000..6f706f3 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java @@ -0,0 +1,12 @@ +package net.hellheim.spongetools.custom.block; + +import net.hellheim.spongetools.custom.behaviour.block.state.BlockStateExtension; + +public interface CustomBlockType { + + + BlockStateProvider stateProvider(); + + BlockStateExtension stateExtension(); + +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java new file mode 100644 index 0000000..72760a9 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java @@ -0,0 +1,26 @@ +package net.hellheim.spongetools.custom.block; + +import java.util.Objects; + +import net.hellheim.spongetools.custom.behaviour.block.state.BlockStateExtension; + +public class DefaultedCustomBlockType implements CustomBlockType { + + private final BlockStateProvider stateProvider; + private final BlockStateExtension stateExtension; + + public DefaultedCustomBlockType(final BlockStateProvider stateProvider) { + this.stateProvider = Objects.requireNonNull(stateProvider, "stateProvider"); + this.stateExtension = BlockStateExtension.getFor(this.stateProvider.provide()); + } + + @Override + public BlockStateProvider stateProvider() { + return this.stateProvider; + } + + @Override + public BlockStateExtension stateExtension() { + return this.stateExtension; + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/NoAvailableStateException.java b/src/main/java/net/hellheim/spongetools/custom/block/NoAvailableStateException.java new file mode 100644 index 0000000..29dee76 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/block/NoAvailableStateException.java @@ -0,0 +1,14 @@ +package net.hellheim.spongetools.custom.block; + +public class NoAvailableStateException extends IllegalStateException { + + private static final long serialVersionUID = -8505232760736136326L; + + public NoAvailableStateException() { + super(); + } + + public NoAvailableStateException(String message) { + super(message); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemType.java b/src/main/java/net/hellheim/spongetools/custom/item/CustomItemType.java index f496642..97976b0 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/item/CustomItemType.java @@ -19,7 +19,10 @@ import org.spongepowered.api.registry.DefaultedRegistryReference; import org.spongepowered.api.registry.DefaultedRegistryType; +import com.mojang.serialization.Codec; + import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.RegistryCodecs; import net.hellheim.spongetools.custom.model.item.Item; import net.hellheim.spongetools.proxy.solid.item.ItemStackSnapshotProxy; import net.kyori.adventure.text.ComponentLike; @@ -33,19 +36,23 @@ public interface CustomItemType extends ItemStackSnapshotProxy { static DefaultedRegistryType registry() { - return SpongeTools.Registries.CUSTOM_ITEM; + return SpongeTools.Registries.CUSTOM_ITEM_TYPE; + } + + static Codec registryCodec() { + return RegistryCodecs.CUSTOM_ITEM_TYPE; } static Key> dataKey() { - return SpongeTools.Keys.CUSTOM_ITEM; + return SpongeTools.Keys.ITEM_TYPE; } static DataQuery dataQuery() { - return SpongeTools.Queries.CUSTOM_ITEM; + return SpongeTools.Queries.ITEM_TYPE; } static int dataVersion() { - return SpongeTools.Versions.CUSTOM_ITEM; + return SpongeTools.Versions.ITEM_TYPE; } static DataBuilder dataBuilder() { diff --git a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemTypeProperties.java b/src/main/java/net/hellheim/spongetools/custom/item/CustomItemTypeProperties.java index 24d3470..6bcfd02 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemTypeProperties.java +++ b/src/main/java/net/hellheim/spongetools/custom/item/CustomItemTypeProperties.java @@ -62,7 +62,7 @@ public class CustomItemTypeProperties implements protected CustomItemTypeProperties(final Builder builder) { builder.validate(); this.key = builder.key; - this.base = builder.base.asDefaultedReference(Sponge::server); + this.base = builder.base.asScopedReference(); this.model = Optional.ofNullable(builder.model); this.name = TranslationUtil.item(this.key); diff --git a/src/main/java/net/hellheim/spongetools/custom/item/EitherItemType.java b/src/main/java/net/hellheim/spongetools/custom/item/EitherItemType.java index e50e07f..54537bf 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/EitherItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/item/EitherItemType.java @@ -1,5 +1,7 @@ package net.hellheim.spongetools.custom.item; +import java.util.IdentityHashMap; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; @@ -14,11 +16,13 @@ import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.registry.DefaultedRegistryType; import org.spongepowered.api.registry.RegistryTypes; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; +import net.hellheim.spongetools.SpongeTools; import net.hellheim.spongetools.codec.list.RegistryCodecs; import net.hellheim.spongetools.proxy.solid.data.ValueContainerProxy; import net.hellheim.spongetools.proxy.solid.item.IItemProxy; @@ -35,16 +39,27 @@ public sealed abstract class EitherItemType implements ResourceKeyed, ComponentLike, ValueContainerProxy, IconProxy, IItemProxy permits EitherItemType.Common, EitherItemType.Custom { + private static final Map COMMON_MAP = new IdentityHashMap<>(); + private static final Map CUSTOM_MAP = new IdentityHashMap<>(); + public static final Codec CODEC = Codec - .either(RegistryCodecs.ITEM_TYPE, RegistryCodecs.CUSTOM_ITEM) + .either(RegistryCodecs.ITEM_TYPE, RegistryCodecs.CUSTOM_ITEM_TYPE) .xmap(EitherItemType::of, EitherItemType::either); + public static final DefaultedRegistryType registry() { + return SpongeTools.Registries.EITHER_ITEM_TYPE; + } + + public static Codec registryCodec() { + return RegistryCodecs.EITHER_ITEM_TYPE; + } + public static EitherItemType common(final Supplier type) { return EitherItemType.common(type.get()); } public static EitherItemType common(final ItemType type) { - return new EitherItemType.Common(type); + return EitherItemType.COMMON_MAP.computeIfAbsent(type, EitherItemType.Common::new); } public static EitherItemType custom(final Supplier type) { @@ -52,7 +67,7 @@ public static EitherItemType custom(final Supplier typ } public static EitherItemType custom(final CustomItemType type) { - return new EitherItemType.Custom(type); + return EitherItemType.CUSTOM_MAP.computeIfAbsent(type, EitherItemType.Custom::new); } public static EitherItemType of(final ItemStackLike stack) { diff --git a/src/main/java/net/hellheim/spongetools/custom/item/data/CustomConsumeEffect.java b/src/main/java/net/hellheim/spongetools/custom/item/data/CustomConsumeEffect.java new file mode 100644 index 0000000..34144f2 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/item/data/CustomConsumeEffect.java @@ -0,0 +1,61 @@ +package net.hellheim.spongetools.custom.item.data; + +import java.util.function.Function; + +import org.spongepowered.api.data.Key; +import org.spongepowered.api.data.persistence.DataBuilder; +import org.spongepowered.api.data.value.ListValue; +import org.spongepowered.api.entity.living.Living; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; +import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.registry.DefaultedRegistryType; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; + +import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.DataCodecs; +import net.hellheim.spongetools.codec.list.RegistryCodecs; +import net.hellheim.spongetools.object.CodecDataSerializable; +import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; + +public interface CustomConsumeEffect extends MapCodecProxy, CodecDataSerializable { + + Codec CODEC = RegistryCodecs.CUSTOM_CONSUME_EFFECT_TYPE + .dispatch(CustomConsumeEffect::mapCodec, Function.identity()); + + static DefaultedRegistryType> registry() { + return SpongeTools.Registries.CONSUME_EFFECT_TYPE; + } + + static Codec> registryCodec() { + return RegistryCodecs.CUSTOM_CONSUME_EFFECT_TYPE; + } + + static Key> dataKey() { + return SpongeTools.Keys.CONSUME_EFFECTS; + } + + static DataBuilder dataBuilder() { + return DataCodecs.dataBuilder(CODEC); + } + + @Override + default Codec codec() { + return CODEC; + } + + void apply(Living entity, ItemStackSnapshot stack); + + interface PlayerOnly extends CustomConsumeEffect { + + @Override + default void apply(final Living entity, final ItemStackSnapshot stack) { + if (entity instanceof final ServerPlayer player) { + this.apply(player, stack); + } + } + + void apply(ServerPlayer player, ItemStackSnapshot stack); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSection.java b/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSection.java index 34cc469..272ab9a 100644 --- a/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSection.java +++ b/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSection.java @@ -16,14 +16,15 @@ import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.hellheim.spongetools.codec.list.AdventureCodecs; import net.hellheim.spongetools.codec.list.ExtraCodecs; -import net.hellheim.spongetools.proxy.solid.codec.CodecProxy; +import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; import net.kyori.adventure.text.Component; -public interface MetadataSection extends CodecProxy, MetadataSectionLike { +public interface MetadataSection extends MapCodecProxy, MetadataSectionLike { BiMap> ID_MAPPER = HashBiMap.create(); @@ -32,7 +33,7 @@ public interface MetadataSection extends CodecProxy, MetadataSe Codec> LIST_CODEC = MAP_CODEC.xmap( map -> List.copyOf(map.values()), list -> list.stream().collect(Collectors.toUnmodifiableMap( - section -> ID_MAPPER.inverse().get(section.codec()), + section -> ID_MAPPER.inverse().get(section.mapCodec().codec()), Function.identity() )) ); @@ -94,7 +95,7 @@ record Pack(Component description, int format, Optional> : DataResult.error(() -> "min_inclusive must be less than or equal to max_inclusive"); }, Pair::getFirst, Pair::getSecond); - public static final Codec CODEC = RecordCodecBuilder.create( + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( p_337567_ -> p_337567_.group( AdventureCodecs.COMPONENT.fieldOf("description").forGetter(Pack::description), Codec.INT.fieldOf("pack_format").forGetter(Pack::format), @@ -108,14 +109,14 @@ public Pack(final Component description, final int format, final Optional codec() { + public MapCodec mapCodec() { return CODEC; } } record Villager(VillagerHat hat) implements MetadataSection { - public static final Codec CODEC = RecordCodecBuilder.create( + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( VillagerHat.CODEC.optionalFieldOf("hat", VillagerHat.NONE).forGetter(Villager::hat) ).apply(instance, Villager::new)); @@ -125,14 +126,14 @@ public Villager(final VillagerHat hat) { } @Override - public Codec codec() { + public MapCodec mapCodec() { return CODEC; } } record Gui(GuiScaling scaling) implements MetadataSection { - public static final Codec CODEC = RecordCodecBuilder.create( + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( GuiScaling.CODEC.optionalFieldOf("scaling", GuiScaling.DEFAULT).forGetter(Gui::scaling) ).apply(instance, Gui::new) @@ -143,7 +144,7 @@ public Gui(final GuiScaling scaling) { } @Override - public Codec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -152,7 +153,7 @@ record Texture(boolean blur, boolean clamp) implements MetadataSection { public static final boolean DEFAULT_BLUR = false; public static final boolean DEFAULT_CLAMP = false; - public static final Codec CODEC = RecordCodecBuilder.create( + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( Codec.BOOL.optionalFieldOf("blur", Texture.DEFAULT_BLUR).forGetter(Texture::blur), Codec.BOOL.optionalFieldOf("clamp", Texture.DEFAULT_CLAMP).forGetter(Texture::clamp) @@ -164,7 +165,7 @@ public Texture(final boolean blur, final boolean clamp) { } @Override - public Codec codec() { + public MapCodec mapCodec() { return CODEC; } } @@ -177,7 +178,7 @@ record Animation( public static final int DEFAULT_FRAME_TIME = 1; public static final boolean DEFAULT_INTERPOLATE = false; - public static final Codec CODEC = RecordCodecBuilder.create( + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( ExtraCodecs.POSITIVE_INT.optionalFieldOf("width").forGetter(Animation::width), ExtraCodecs.POSITIVE_INT.optionalFieldOf("height").forGetter(Animation::height), @@ -218,7 +219,7 @@ private static void checkFrameTime(final int frameTime) { } @Override - public Codec codec() { + public MapCodec mapCodec() { return CODEC; } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/Item.java b/src/main/java/net/hellheim/spongetools/custom/model/item/Item.java index c9dde75..14756de 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/Item.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/Item.java @@ -8,6 +8,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.RegistryCodecs; public record Item(ItemDefinition definition, boolean handAnimationOnSwap) { @@ -28,6 +29,10 @@ public static DefaultedRegistryType registry() { return SpongeTools.Registries.ITEM; } + public static Codec registryCodec() { + return RegistryCodecs.ITEM; + } + public static Item of(final ItemDefinition definition, final boolean handAnimationOnSwap) { return new Item(definition, handAnimationOnSwap); } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemDisplayContext.java b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemDisplayContext.java deleted file mode 100644 index 80c9b86..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemDisplayContext.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.hellheim.spongetools.custom.model.item; - -import org.spongepowered.api.data.type.StringRepresentable; - -import com.mojang.serialization.Codec; - -import net.hellheim.spongetools.codec.StringRepresentableCodec; - -// TODO Maybe expose as registry? -public enum ItemDisplayContext implements StringRepresentable { - NONE("none"), - THIRD_PERSON_LEFT_HAND("thirdperson_lefthand"), - THIRD_PERSON_RIGHT_HAND("thirdperson_righthand"), - FIRST_PERSON_LEFT_HAND("firstperson_lefthand"), - FIRST_PERSON_RIGHT_HAND("firstperson_righthand"), - HEAD("head"), - GUI("gui"), - GROUND("ground"), - FIXED("fixed"); - - public static final Codec CODEC = StringRepresentableCodec.fromValues(ItemDisplayContext::values); - - private final String name; - - private ItemDisplayContext(String name) { - this.name = name; - } - - @Override - public String serializationString() { - return this.name; - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java index e251968..0fa4e1a 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java @@ -11,6 +11,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.RegistryCodecs; import net.hellheim.spongetools.custom.model.ModelTemplate; import net.hellheim.spongetools.custom.model.TexturedModel; import net.hellheim.spongetools.custom.model.Textures; @@ -35,6 +36,10 @@ public static DefaultedRegistryType registry() { return SpongeTools.Registries.ITEM_MODEL; } + public static Codec registryCodec() { + return RegistryCodecs.ITEM_MODEL; + } + public static ItemModel of(final ModelTemplate parent, final Textures textures) { return ItemModel.of(TexturedModel.of(parent, textures)); } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemTransforms.java b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemTransforms.java index f5813b4..1c4ad84 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemTransforms.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemTransforms.java @@ -3,23 +3,26 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.function.Supplier; +import org.spongepowered.api.entity.display.ItemDisplayType; import org.spongepowered.api.util.CopyableBuilder; import org.spongepowered.api.util.Transform; import com.mojang.serialization.Codec; import net.hellheim.spongetools.codec.list.MathCodecs; +import net.hellheim.spongetools.codec.list.StringRepresentableCodecs; -public record ItemTransforms(Map transforms) { +public record ItemTransforms(Map transforms) { public static final ItemTransforms DEFAULT = new ItemTransforms(Map.of()); public static final Codec CODEC = - Codec.unboundedMap(ItemDisplayContext.CODEC, MathCodecs.TRANSFORM) + Codec.unboundedMap(StringRepresentableCodecs.ITEM_DISPLAY_TYPE, MathCodecs.TRANSFORM) .xmap(ItemTransforms::new, ItemTransforms::transforms); - public ItemTransforms(final Map transforms) { + public ItemTransforms(final Map transforms) { this.transforms = Map.copyOf(transforms); } @@ -31,36 +34,52 @@ public static class Builder implements org.spongepowered.api.util.Builder, CopyableBuilder { - private final Map transforms = new HashMap<>(); + private final Map transforms = new HashMap<>(); - public Builder put(final ItemDisplayContext display, final Transform transform) { + public Builder put(final ItemDisplayType display, final Transform transform) { this.transforms.put( Objects.requireNonNull(display, "display"), Objects.requireNonNull(transform, "transform")); return this; } - public Builder putIfAbsent(final ItemDisplayContext display, final Transform transform) { + public Builder put(final Supplier display, final Transform transform) { + return this.put(display.get(), transform); + } + + public Builder putIfAbsent(final ItemDisplayType display, final Transform transform) { this.transforms.putIfAbsent( Objects.requireNonNull(display, "display"), Objects.requireNonNull(transform, "transform")); return this; } - public Builder putAll(final Map transforms) { + public Builder putIfAbsent(final Supplier display, final Transform transform) { + return this.putIfAbsent(display.get(), transform); + } + + public Builder putAll(final Map transforms) { Objects.requireNonNull(transforms, "transforms").forEach(this::put); return this; } - public Builder putAll(final Transform transform, final ItemDisplayContext... displays) { - for (final ItemDisplayContext display : Objects.requireNonNull(displays, "displays")) { + public Builder putAll(final Transform transform, final ItemDisplayType... displays) { + for (final ItemDisplayType display : Objects.requireNonNull(displays, "displays")) { + this.put(display, transform); + } + return this; + } + + @SuppressWarnings("unchecked") + public Builder putAll(final Transform transform, final Supplier... displays) { + for (final Supplier display : Objects.requireNonNull(displays, "displays")) { this.put(display, transform); } return this; } - public Builder putAll(final Transform transform, final Iterable displays) { - for (final ItemDisplayContext display : Objects.requireNonNull(displays, "displays")) { + public Builder putAll(final Transform transform, final Iterable displays) { + for (final ItemDisplayType display : Objects.requireNonNull(displays, "displays")) { this.put(display, transform); } return this; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java index eba328d..e226084 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java @@ -11,6 +11,7 @@ import org.spongepowered.api.ResourceKey; import org.spongepowered.api.data.type.HandPreference; import org.spongepowered.api.entity.EntityType; +import org.spongepowered.api.entity.display.ItemDisplayType; import org.spongepowered.api.item.recipe.smithing.TrimMaterial; import org.spongepowered.api.registry.RegistryKey; import org.spongepowered.api.registry.RegistryTypes; @@ -28,6 +29,7 @@ import net.hellheim.spongetools.codec.list.ExtraCodecs; import net.hellheim.spongetools.codec.list.RegistryCodecs; import net.hellheim.spongetools.codec.list.SpongeCodecs; +import net.hellheim.spongetools.codec.list.StringRepresentableCodecs; import net.hellheim.spongetools.custom.model.item.enums.ChargeType; import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; @@ -143,10 +145,10 @@ record Trim() implements SelectProperty> { } } - record Display() implements SelectProperty { + record Display() implements SelectProperty { public static final Display INSTANCE = new Display(); public static final MapCodec CODEC = MapCodec.unit(INSTANCE); - public static final MapCodec> SWITCH = SelectProperty.create(CODEC, ItemDisplayContext.CODEC); + public static final MapCodec> SWITCH = SelectProperty.create(CODEC, StringRepresentableCodecs.ITEM_DISPLAY_TYPE); @Override public MapCodec> mapCodec() { diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java b/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java new file mode 100644 index 0000000..048bfff --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java @@ -0,0 +1,58 @@ +package net.hellheim.spongetools.event; + +import java.util.function.Function; + +import org.spongepowered.api.event.lifecycle.LifecycleEvent; + +import net.hellheim.spongetools.custom.behaviour.Behaviour; +import net.hellheim.spongetools.custom.behaviour.BehaviourManager; +import net.hellheim.spongetools.custom.behaviour.BehaviourMerger; +import net.hellheim.spongetools.custom.behaviour.BehaviourType; +import net.hellheim.spongetools.custom.behaviour.BehaviourManager.BehaviourRegistration; + +public interface RegisterBehaviourDataEvent extends LifecycleEvent { + + BehaviourManager manager(); + + default , B extends Behaviour.Extendable> void register( + final BehaviourType type, final Function callbackProvider + ) { + this.manager().register(type, callbackProvider); + } + + default , B extends Behaviour.Extendable> void register( + final BehaviourType type, final BehaviourMerger callbackMerger + ) { + this.manager().register(type, callbackMerger); + } + + default BehaviourRegistration create(final Class holder) { + return this.manager().create(holder); + } + + default , B extends Behaviour.Extendable> void register( + final BehaviourType type, + final Function callbackProvider, final BehaviourMerger callbackMerger + ) { + this.register(type, callbackProvider); + this.register(type, callbackMerger); + } + + default , B extends Behaviour.Extendable> void register( + final Class holder, final BehaviourType type, + final Function callbackProvider, final BehaviourMerger callbackMerger, + final Function behaviourProvider + ) { + this.register(type, callbackProvider, callbackMerger); + this.create(holder).register(type, behaviourProvider); + } + + default , B extends Behaviour.Extendable> void register( + final Class holder, final BehaviourType type, + final BehaviourMerger callbackMerger, + final Function behaviourProvider + ) { + this.register(type, callbackMerger); + this.create(holder).register(type, behaviourProvider); + } +} diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java new file mode 100644 index 0000000..3353a31 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java @@ -0,0 +1,102 @@ +package net.hellheim.spongetools.event; + +import java.util.Arrays; +import java.util.Objects; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.event.lifecycle.LifecycleEvent; + +import com.google.common.collect.Streams; + +import net.hellheim.spongetools.custom.behaviour.BehaviourManager; +import net.hellheim.spongetools.custom.behaviour.BehaviourType; +import net.hellheim.spongetools.custom.behaviour.block.state.BlockStateBehaviour; + +public interface RegisterBlockStateBehaviourEvent extends LifecycleEvent { + + BehaviourStep state(BlockState state); + + + default Stream states(final Stream states) { + return states.map(this::state); + } + + default Stream states(final BlockState... states) { + return this.states(Arrays.stream(states)); + } + + @SuppressWarnings("unchecked") + default Stream states(final Supplier... states) { + return this.states(Arrays.stream(states).map(Supplier::get)); + } + + default Stream states(final Iterable states) { + return this.states(Streams.stream(states)); + } + + + default BehaviourStep defaultState(final BlockType type) { + return this.state(type.defaultState()); + } + + default BehaviourStep defaultState(final Supplier type) { + return this.defaultState(type.get()); + } + + + default Stream defaultStates(final Stream types) { + return types.map(this::defaultState); + } + + default Stream defaultStates(final BlockType... types) { + return this.defaultStates(Arrays.stream(types)); + } + + @SuppressWarnings("unchecked") + default Stream defaultStates(final Supplier... types) { + return this.defaultStates(Arrays.stream(types).map(Supplier::get)); + } + + default Stream defaultStates(final Iterable types) { + return this.defaultStates(Streams.stream(types)); + } + + + default Stream allStates(final Stream types) { + return types.flatMap(type -> type.validStates().stream()).map(this::state); + } + + default Stream allStates(final BlockType... types) { + return this.allStates(Arrays.stream(types)); + } + + @SuppressWarnings("unchecked") + default Stream allStates(final Supplier... types) { + return this.allStates(Arrays.stream(types).map(Supplier::get)); + } + + default Stream allStates(final Iterable types) { + return this.allStates(Streams.stream(types)); + } + + + interface BehaviourStep { + + , B extends BlockStateBehaviour> void add(BehaviourType type, C callback); + + default , B extends BlockStateBehaviour> void set( + final BehaviourType type, final R value + ) { + this.add(type, BehaviourManager.get().callbackProvider(type).apply(Objects.requireNonNull(value, "value"))); + } + + default , B extends BlockStateBehaviour> void set( + final BehaviourType type, final Supplier valueSupplier + ) { + this.set(type, Objects.requireNonNull(valueSupplier, "valueSupplier").get()); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/object/CodecDataSerializable.java b/src/main/java/net/hellheim/spongetools/object/CodecDataSerializable.java new file mode 100644 index 0000000..9d7530e --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/object/CodecDataSerializable.java @@ -0,0 +1,22 @@ +package net.hellheim.spongetools.object; + +import org.spongepowered.api.data.persistence.DataContainer; +import org.spongepowered.api.data.persistence.DataSerializable; + +import net.hellheim.spongetools.codec.list.DataCodecs; +import net.hellheim.spongetools.proxy.solid.codec.CodecProxy; + +public interface CodecDataSerializable extends DataSerializable, CodecProxy { + + @Override + default int contentVersion() { + return 0; + } + + @Override + default DataContainer toContainer() { + @SuppressWarnings("unchecked") + final T $this = (T) this; + return DataCodecs.toContainer(this.codec(), $this); + } +} diff --git a/src/main/java/net/hellheim/spongetools/object/DataHolderBuilder.java b/src/main/java/net/hellheim/spongetools/object/DataOperator.java similarity index 97% rename from src/main/java/net/hellheim/spongetools/object/DataHolderBuilder.java rename to src/main/java/net/hellheim/spongetools/object/DataOperator.java index 9139e7a..6121fa8 100644 --- a/src/main/java/net/hellheim/spongetools/object/DataHolderBuilder.java +++ b/src/main/java/net/hellheim/spongetools/object/DataOperator.java @@ -6,7 +6,7 @@ import org.spongepowered.api.data.value.Value; import org.spongepowered.api.data.value.ValueContainer; -public interface DataHolderBuilder> { +public interface DataOperator> { /** * Adds all the {@link Value}s from the {@link ValueContainer} to the builder. diff --git a/src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java b/src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java index b0ec73f..cc2da63 100644 --- a/src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java +++ b/src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java @@ -7,7 +7,7 @@ import org.spongepowered.api.data.Key; import org.spongepowered.api.data.value.Value; -public class ValueSetBuilder implements DataHolderBuilder { +public class ValueSetBuilder implements DataOperator { protected final Set> values = new HashSet<>(); diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/codec/CodecProxy.java b/src/main/java/net/hellheim/spongetools/proxy/solid/codec/CodecProxy.java index 791ca78..a618e38 100644 --- a/src/main/java/net/hellheim/spongetools/proxy/solid/codec/CodecProxy.java +++ b/src/main/java/net/hellheim/spongetools/proxy/solid/codec/CodecProxy.java @@ -5,5 +5,5 @@ public interface CodecProxy extends EncoderProxy, DecoderProxy { @Override - Codec codec(); + Codec codec(); } From c0574f7f488e9aa93a39a5a8586a9b0fe9f654d6 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sun, 27 Apr 2025 17:29:22 +0300 Subject: [PATCH 10/55] continue custom stuff --- .../custom/behaviour/Behaviour.java | 33 ++---- .../custom/behaviour/BehaviourArgs.java | 4 + .../custom/behaviour/BehaviourCallback.java | 15 +++ .../custom/behaviour/BehaviourManager.java | 28 ++++- .../custom/behaviour/BehaviourType.java | 4 +- .../AnalogSignalPowerBlockStateBehaviour.java | 1 + .../state/MapColorBlockStateBehaviour.java | 1 + .../NeighbourUpdateBlockStateBehaviour.java | 11 -- .../PushReactionBlockStateBehaviour.java | 1 + .../state/ReplaceBlockStateBehaviour.java | 1 + .../state/ShapeUpdateBlockStateBehaviour.java | 1 + .../SignalConductorBlockStateBehaviour.java | 1 + .../state/SignalPowerBlockStateBehaviour.java | 1 + .../SignalUpdateBlockStateBehaviour.java | 29 +++++ .../SpawnValidatorBlockStateBehaviour.java | 1 + .../block/state/TickBlockStateBehaviour.java | 1 + .../behaviour/type/BlockStateBehaviour.java | 101 ++++++++++++++++++ .../state => type}/BlockStateBehaviours.java | 29 +++-- .../custom/behaviour/world/SignalBias.java | 23 ++++ .../behaviour/world/SignalOrientation.java | 73 +++++++++++++ .../behaviour/world/WorldExtension.java | 44 ++++++++ .../event/RegisterBehaviourDataEvent.java | 64 +++++++---- .../RegisterBlockStateBehaviourEvent.java | 49 ++++++++- .../hellheim/spongetools/util/GeomUtil.java | 37 +++++++ 24 files changed, 478 insertions(+), 75 deletions(-) create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/NeighbourUpdateBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalUpdateBlockStateBehaviour.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java rename src/main/java/net/hellheim/spongetools/custom/behaviour/{block/state => type}/BlockStateBehaviours.java (62%) create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalBias.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalOrientation.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/world/WorldExtension.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java index 3ebca91..1214301 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java @@ -1,33 +1,14 @@ package net.hellheim.spongetools.custom.behaviour; -import java.util.Optional; - -import com.mojang.serialization.MapCodec; - /** * Represents some action a {@link BehaviourHolder} can do. + * + * @param Behaviour holder + * @param Return type + * @param Behaviour arguments */ -public interface Behaviour { - - interface Extendable> extends Behaviour { - } - - /** - * Callbacks are used to add additional behaviour on top of the default one. - * - * @param The return type of this callback - */ - interface Callback { - } +@FunctionalInterface +public interface Behaviour { - /** - * TODO - * @param The return type of this callback - */ - interface SerializableCallback extends Callback { - - default Optional>> codec() { - return Optional.empty(); - } - } + R call(A args); } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java new file mode 100644 index 0000000..ba426d3 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java @@ -0,0 +1,4 @@ +package net.hellheim.spongetools.custom.behaviour; + +public interface BehaviourArgs { +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java new file mode 100644 index 0000000..584b571 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java @@ -0,0 +1,15 @@ +package net.hellheim.spongetools.custom.behaviour; + +/** + * Callbacks are used to add additional behaviour on top of the default one. + * + * @param Behaviour holder + * @param Return type + * @param Behaviour arguments + * @param Behaviour + */ +@FunctionalInterface +public interface BehaviourCallback> { + + R call(H holder, B origin, A args); +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java index f5b4c1c..e0678e3 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java @@ -16,6 +16,18 @@ , B extends Behaviour.Extendable> Function BehaviourType type ); + , B extends Behaviour.Extendable> Function callbackConverter( + BehaviourType type + ); + + , B extends Behaviour.Extendable> Function callbackConverterBefore( + BehaviourType type + ); + + , B extends Behaviour.Extendable> Function callbackConverterAfter( + BehaviourType type + ); + , B extends Behaviour.Extendable> BehaviourMerger callbackMerger( BehaviourType type ); @@ -24,11 +36,23 @@ , B extends Behaviour.Extendable> BehaviourMe Optional get(H holder, BehaviourType type); - , B extends Behaviour.Extendable> void register( + , B extends Behaviour.Extendable> void registerProvider( BehaviourType type, Function callbackProvider ); - , B extends Behaviour.Extendable> void register( + , B extends Behaviour.Extendable> void registerConverter( + BehaviourType type, Function callbackConverter + ); + + , B extends Behaviour.Extendable> void registerConverterBefore( + BehaviourType type, Function callbackConverterBefore + ); + + , B extends Behaviour.Extendable> void registerConverterAfter( + BehaviourType type, Function callbackConverterAfter + ); + + , B extends Behaviour.Extendable> void registerMerger( BehaviourType type, BehaviourMerger callbackMerger ); diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java index 72b19e3..1d0f9b9 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java @@ -1,8 +1,8 @@ package net.hellheim.spongetools.custom.behaviour; -public interface BehaviourType { +public interface BehaviourType> { - static BehaviourType create() { + static > BehaviourType create() { return new BehaviourType<>() {}; } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java index cf93724..5e1a605 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java @@ -3,6 +3,7 @@ import org.spongepowered.api.world.World; import org.spongepowered.math.vector.Vector3i; +@FunctionalInterface public interface AnalogSignalPowerBlockStateBehaviour extends BlockStateBehaviour { diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java index 0ef980b..750f799 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java @@ -4,6 +4,7 @@ import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; import org.spongepowered.math.vector.Vector3i; +@FunctionalInterface public interface MapColorBlockStateBehaviour extends BlockStateBehaviour { diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/NeighbourUpdateBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/NeighbourUpdateBlockStateBehaviour.java deleted file mode 100644 index b364d46..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/NeighbourUpdateBlockStateBehaviour.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -public interface NeighbourUpdateBlockStateBehaviour - extends BlockStateBehaviour { - - - - interface Callback extends BlockStateBehaviour.Callback { - - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java index 53b3924..de49180 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java @@ -2,6 +2,7 @@ import org.spongepowered.api.data.type.PushReaction; +@FunctionalInterface public interface PushReactionBlockStateBehaviour extends BlockStateBehaviour { diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java index 5bbf9bf..4cb7890 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java @@ -4,6 +4,7 @@ import org.spongepowered.api.world.World; import org.spongepowered.math.vector.Vector3i; +@FunctionalInterface public interface ReplaceBlockStateBehaviour extends BlockStateBehaviour { diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java index c4ea9e4..f243dec 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java @@ -7,6 +7,7 @@ import org.spongepowered.api.world.volume.game.UpdatableVolume; import org.spongepowered.math.vector.Vector3i; +@FunctionalInterface public interface ShapeUpdateBlockStateBehaviour extends BlockStateBehaviour { diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java index 4680fe2..a018759 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java @@ -3,6 +3,7 @@ import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; import org.spongepowered.math.vector.Vector3i; +@FunctionalInterface public interface SignalConductorBlockStateBehaviour extends BlockStateBehaviour { diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java index 2542177..4b8a924 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java @@ -4,6 +4,7 @@ import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; import org.spongepowered.math.vector.Vector3i; +@FunctionalInterface public interface SignalPowerBlockStateBehaviour extends BlockStateBehaviour { diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalUpdateBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalUpdateBlockStateBehaviour.java new file mode 100644 index 0000000..d86c47e --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalUpdateBlockStateBehaviour.java @@ -0,0 +1,29 @@ +package net.hellheim.spongetools.custom.behaviour.block.state; + +import java.util.Optional; + +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.world.World; +import org.spongepowered.math.vector.Vector3i; + +import net.hellheim.spongetools.custom.behaviour.world.SignalOrientation; + +@FunctionalInterface +public interface SignalUpdateBlockStateBehaviour + extends BlockStateBehaviour { + + void apply( + World world, Vector3i position, BlockType notifier, + Optional orientation, boolean movedByPiston + ); + + @FunctionalInterface + interface Callback extends BlockStateBehaviour.Callback { + + void apply( + BlockStateExtension state, SignalUpdateBlockStateBehaviour origin, + World world, Vector3i position, BlockType notifier, + Optional orientation, boolean movedByPiston + ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java index ce26777..b572c2a 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java @@ -4,6 +4,7 @@ import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; import org.spongepowered.math.vector.Vector3i; +@FunctionalInterface public interface SpawnValidatorBlockStateBehaviour extends BlockStateBehaviour { diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java index bf69dea..31a3561 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java @@ -4,6 +4,7 @@ import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.math.vector.Vector3i; +@FunctionalInterface public interface TickBlockStateBehaviour extends BlockStateBehaviour { diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java new file mode 100644 index 0000000..b682502 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java @@ -0,0 +1,101 @@ +package net.hellheim.spongetools.custom.behaviour.type; + +import java.util.Objects; + +import org.spongepowered.api.entity.EntityType; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.util.RandomProvider; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; +import org.spongepowered.math.vector.Vector3i; + +import net.hellheim.spongetools.custom.behaviour.Behaviour; +import net.hellheim.spongetools.custom.behaviour.BehaviourArgs; +import net.hellheim.spongetools.custom.behaviour.block.state.BlockStateExtension; + +public interface BlockStateBehaviour extends Behaviour { + + interface SpawnValidator extends BlockStateBehaviour { + + default boolean call(final PrimitiveGameVolume volume, final Vector3i position, final EntityType entity) { + return this.call(new Args(volume, position, entity)); + } + + record Args(PrimitiveGameVolume volume, Vector3i position, EntityType entity) implements BehaviourArgs { + + public Args(final PrimitiveGameVolume volume, final Vector3i position, final EntityType entity) { + this.volume = Objects.requireNonNull(volume, "volume"); + this.position = Objects.requireNonNull(position, "position"); + this.entity = Objects.requireNonNull(entity, "entity"); + } + + public Args withVolume(final PrimitiveGameVolume volume) { + return new Args(volume, this.position, this.entity); + } + + public Args withPosition(final Vector3i position) { + return new Args(this.volume, position, this.entity); + } + + public Args withEntity(final EntityType entity) { + return new Args(this.volume, this.position, entity); + } + } + } + + interface SignalPower extends BlockStateBehaviour { + + default int call(final PrimitiveGameVolume volume, final Vector3i position, final Direction direction) { + return this.call(new Args(volume, position, direction)); + } + + record Args(PrimitiveGameVolume volume, Vector3i position, Direction direction) implements BehaviourArgs { + + public Args(final PrimitiveGameVolume volume, final Vector3i position, final Direction direction) { + this.volume = Objects.requireNonNull(volume, "volume"); + this.position = Objects.requireNonNull(position, "position"); + this.direction = Objects.requireNonNull(direction, "direction"); + } + + public Args withVolume(final PrimitiveGameVolume volume) { + return new Args(volume, this.position, this.direction); + } + + public Args withPosition(final Vector3i position) { + return new Args(this.volume, position, this.direction); + } + + public Args withDirection(final Direction direction) { + return new Args(this.volume, this.position, direction); + } + } + } + + interface Tick extends BlockStateBehaviour { + + default void call(final ServerWorld world, final Vector3i position, final RandomProvider.Source random) { + this.call(new Args(world, position, random)); + } + + record Args(ServerWorld world, Vector3i position, RandomProvider.Source random) implements BehaviourArgs { + + public Args(final ServerWorld world, final Vector3i position, final RandomProvider.Source random) { + this.world = Objects.requireNonNull(world, "world"); + this.position = Objects.requireNonNull(position, "position"); + this.random = Objects.requireNonNull(random, "random"); + } + + public Args withWorld(final ServerWorld world) { + return new Args(world, this.position, this.random); + } + + public Args withPosition(final Vector3i position) { + return new Args(this.world, position, this.random); + } + + public Args withRandom(final RandomProvider.Source random) { + return new Args(this.world, this.position, random); + } + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviours.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java similarity index 62% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviours.java rename to src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java index 189db74..896524a 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviours.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java @@ -1,10 +1,21 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; +package net.hellheim.spongetools.custom.behaviour.type; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockTypes; import org.spongepowered.api.world.volume.game.UpdatableVolume; import net.hellheim.spongetools.custom.behaviour.BehaviourType; +import net.hellheim.spongetools.custom.behaviour.block.state.AnalogSignalPowerBlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.block.state.BlockStateExtension; +import net.hellheim.spongetools.custom.behaviour.block.state.MapColorBlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.block.state.PushReactionBlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.block.state.ReplaceBlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.block.state.ShapeUpdateBlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.block.state.SignalConductorBlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.block.state.SignalPowerBlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.block.state.SignalUpdateBlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.block.state.SpawnValidatorBlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.block.state.TickBlockStateBehaviour; public final class BlockStateBehaviours { @@ -50,32 +61,32 @@ public final class BlockStateBehaviours { public static final BehaviourType RANDOM_TICK = BehaviourType.create(); /** - * Called when block enters the world. + * Called when {@link BlockState} enters the world. */ public static final BehaviourType PLACE = BehaviourType.create(); /** - * Called when block leaves the world. + * Called when {@link BlockState} leaves the world. */ public static final BehaviourType REMOVE = BehaviourType.create(); /** * Called when neighbour {@link BlockState}s are changed.
- * This is usually used to update properties that could - * considered as "shape" depending on neighbour blocks - * and by waterlogged blocks to schedule liquid ticks. + * This is usually used to update properties that could be + * considered as "shape" depending on neighbour blocks and + * by waterlogged blocks to schedule liquid ticks. * - * @see #NEIGHBOUR_UPDATE + * @see #SIGNAL_UPDATE */ public static final BehaviourType SHAPE_UPDATE = BehaviourType.create(); /** - * Called when neighbour {@link BlockState}s are changed.
+ * Called when neighbour {@link BlockState}s are changed (mostly due to signal changes).
* This is usually used to update properties that rely on redstone signal * * @see #SHAPE_UPDATE */ - public static final BehaviourType NEIGHBOUR_UPDATE = BehaviourType.create(); + public static final BehaviourType SIGNAL_UPDATE = BehaviourType.create(); private BlockStateBehaviours() { } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalBias.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalBias.java new file mode 100644 index 0000000..b1a0e51 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalBias.java @@ -0,0 +1,23 @@ +package net.hellheim.spongetools.custom.behaviour.world; + +import org.spongepowered.api.Sponge; + +public interface SignalBias { + + static SignalBias left() { + return Sponge.game().factoryProvider().provide(Factory.class).left(); + } + + static SignalBias right() { + return Sponge.game().factoryProvider().provide(Factory.class).right(); + } + + SignalBias opposite(); + + interface Factory { + + SignalBias left(); + + SignalBias right(); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalOrientation.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalOrientation.java new file mode 100644 index 0000000..66daa04 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalOrientation.java @@ -0,0 +1,73 @@ +package net.hellheim.spongetools.custom.behaviour.world; + +import java.util.Optional; +import java.util.stream.Stream; + +import org.spongepowered.api.Sponge; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.util.RandomProvider; +import org.spongepowered.api.world.World; + +public interface SignalOrientation { + + static SignalOrientation of(final Direction up, final Direction front, final SignalBias bias) { + return SignalOrientation.factory().of(up, front, bias); + } + + static SignalOrientation random(final RandomProvider.Source random) { + return SignalOrientation.factory().random(random); + } + + static SignalOrientation random(final RandomProvider provider) { + return SignalOrientation.random(provider.random()); + } + + static SignalOrientation randomWith(final World world, final Optional up, final Optional front) { + return SignalOrientation.factory().randomWith(world, up, front); + } + + static SignalOrientation randomWith(final World world, final Direction up, final Direction front) { + return SignalOrientation.randomWith(world, Optional.of(up), Optional.of(front)); + } + + static SignalOrientation randomWithUp(final World world, final Direction up) { + return SignalOrientation.randomWith(world, Optional.of(up), Optional.empty()); + } + + static SignalOrientation randomWithFront(final World world, final Direction front) { + return SignalOrientation.randomWith(world, Optional.empty(), Optional.of(front)); + } + + private static Factory factory() { + return Sponge.game().factoryProvider().provide(Factory.class); + } + + Direction up(); + + Direction front(); + + Direction side(); + + SignalBias bias(); + + SignalOrientation withUp(Direction direction); + + SignalOrientation withFront(Direction direction); + + SignalOrientation withBias(SignalBias bias); + + Stream allDirections(); + + Stream horizontalDirections(); + + Stream verticalDirections(); + + interface Factory { + + SignalOrientation of(Direction up, Direction front, SignalBias bias); + + SignalOrientation random(RandomProvider.Source random); + + SignalOrientation randomWith(World world, Optional up, Optional front); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/world/WorldExtension.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/world/WorldExtension.java new file mode 100644 index 0000000..f890839 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/world/WorldExtension.java @@ -0,0 +1,44 @@ +package net.hellheim.spongetools.custom.behaviour.world; + +import java.util.Objects; + +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.world.World; +import org.spongepowered.math.vector.Vector3i; + +public interface WorldExtension> { + + static > WorldExtension getFor(final W world) { + @SuppressWarnings("unchecked") + final WorldExtension extension = (WorldExtension) world; + return extension; + } + + default W owner() { + @SuppressWarnings("unchecked") + final W world = (W) this; + return world; + } + + void updateAt(int x , int y, int z, BlockType notifier); + + default void updateAt(final Vector3i position, final BlockType notifier) { + Objects.requireNonNull(position, "position"); + this.updateAt(position.x(), position.y(), position.z(), notifier); + } + + void updateAround(int x, int y, int z, BlockType notifier); + + default void updateAround(final Vector3i position, final BlockType notifier) { + Objects.requireNonNull(position, "position"); + this.updateAround(position.x(), position.y(), position.z(), notifier); + } + + void updateAroundExcept(int x, int y, int z, BlockType notifier, Direction direction); + + default void updateAroundExcept(final Vector3i position, final BlockType notifier, final Direction direction) { + Objects.requireNonNull(position, "position"); + this.updateAroundExcept(position.x(), position.y(), position.z(), notifier, direction); + } +} diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java b/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java index 048bfff..95f776e 100644 --- a/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java +++ b/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java @@ -14,16 +14,34 @@ public interface RegisterBehaviourDataEvent extends LifecycleEvent { BehaviourManager manager(); - default , B extends Behaviour.Extendable> void register( + default , B extends Behaviour.Extendable> void registerProvider( final BehaviourType type, final Function callbackProvider ) { - this.manager().register(type, callbackProvider); + this.manager().registerProvider(type, callbackProvider); + } + + default , B extends Behaviour.Extendable> void registerConverter( + final BehaviourType type, final Function callbackConverter + ) { + this.manager().registerConverter(type, callbackConverter); + } + + default , B extends Behaviour.Extendable> void registerConverterBefore( + final BehaviourType type, final Function callbackConverterBefore + ) { + this.manager().registerConverterBefore(type, callbackConverterBefore); } - default , B extends Behaviour.Extendable> void register( + default , B extends Behaviour.Extendable> void registerConverterAfter( + final BehaviourType type, final Function callbackConverterAfter + ) { + this.manager().registerConverterAfter(type, callbackConverterAfter); + } + + default , B extends Behaviour.Extendable> void registerMerger( final BehaviourType type, final BehaviourMerger callbackMerger ) { - this.manager().register(type, callbackMerger); + this.manager().registerMerger(type, callbackMerger); } default BehaviourRegistration create(final Class holder) { @@ -32,27 +50,29 @@ default BehaviourRegistration create(final Class holder) { default , B extends Behaviour.Extendable> void register( final BehaviourType type, - final Function callbackProvider, final BehaviourMerger callbackMerger + final Function callbackProvider, + final Function callbackConverter, + final Function callbackConverterBefore, + final Function callbackConverterAfter, + final BehaviourMerger callbackMerger ) { - this.register(type, callbackProvider); - this.register(type, callbackMerger); + this.registerProvider(type, callbackProvider); + this.registerConverter(type, callbackConverter); + this.registerConverterBefore(type, callbackConverterBefore); + this.registerConverterAfter(type, callbackConverterAfter); + this.registerMerger(type, callbackMerger); } - default , B extends Behaviour.Extendable> void register( - final Class holder, final BehaviourType type, - final Function callbackProvider, final BehaviourMerger callbackMerger, - final Function behaviourProvider - ) { - this.register(type, callbackProvider, callbackMerger); - this.create(holder).register(type, behaviourProvider); - } - - default , B extends Behaviour.Extendable> void register( - final Class holder, final BehaviourType type, - final BehaviourMerger callbackMerger, - final Function behaviourProvider + default , B extends Behaviour.Extendable> void register( + final BehaviourType type, + final Function callbackConverter, + final Function callbackConverterBefore, + final Function callbackConverterAfter, + final BehaviourMerger callbackMerger ) { - this.register(type, callbackMerger); - this.create(holder).register(type, behaviourProvider); + this.registerConverter(type, callbackConverter); + this.registerConverterBefore(type, callbackConverterBefore); + this.registerConverterAfter(type, callbackConverterAfter); + this.registerMerger(type, callbackMerger); } } diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java index 3353a31..0a92f4f 100644 --- a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java +++ b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java @@ -85,18 +85,61 @@ default Stream allStates(final Iterable type interface BehaviourStep { - , B extends BlockStateBehaviour> void add(BehaviourType type, C callback); + BehaviourManager manager(); + + , B extends BlockStateBehaviour> void append(BehaviourType type, C callback); + + , B extends BlockStateBehaviour> void prepend(BehaviourType type, C callback); + + , B extends BlockStateBehaviour> void set(BehaviourType type, C callback); + + default , B extends BlockStateBehaviour> void appendBefore( + final BehaviourType type, final B behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + this.append(type, this.manager().callbackConverterBefore(type).apply(behaviour)); + } + + default , B extends BlockStateBehaviour> void appendAfter( + final BehaviourType type, final B behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + this.append(type, this.manager().callbackConverterAfter(type).apply(behaviour)); + } + + default , B extends BlockStateBehaviour> void prependBefore( + final BehaviourType type, final B behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + this.prepend(type, this.manager().callbackConverterBefore(type).apply(behaviour)); + } + + default , B extends BlockStateBehaviour> void prependAfter( + final BehaviourType type, final B behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + this.prepend(type, this.manager().callbackConverterAfter(type).apply(behaviour)); + } + + default , B extends BlockStateBehaviour> void setBehaviour( + final BehaviourType type, final B behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + this.set(type, this.manager().callbackConverter(type).apply(behaviour)); + } default , B extends BlockStateBehaviour> void set( final BehaviourType type, final R value ) { - this.add(type, BehaviourManager.get().callbackProvider(type).apply(Objects.requireNonNull(value, "value"))); + Objects.requireNonNull(value, "value"); + this.set(type, this.manager().callbackProvider(type).apply(value)); } default , B extends BlockStateBehaviour> void set( final BehaviourType type, final Supplier valueSupplier ) { - this.set(type, Objects.requireNonNull(valueSupplier, "valueSupplier").get()); + Objects.requireNonNull(valueSupplier, "valueSupplier"); + this.set(type, valueSupplier.get()); } } } diff --git a/src/main/java/net/hellheim/spongetools/util/GeomUtil.java b/src/main/java/net/hellheim/spongetools/util/GeomUtil.java index 2e2ad30..df30f2d 100644 --- a/src/main/java/net/hellheim/spongetools/util/GeomUtil.java +++ b/src/main/java/net/hellheim/spongetools/util/GeomUtil.java @@ -1,11 +1,13 @@ package net.hellheim.spongetools.util; +import java.util.Arrays; import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.stream.Collectors; import org.spongepowered.api.util.Axis; import org.spongepowered.api.util.Direction; @@ -34,6 +36,16 @@ public final class GeomUtil { private static final List ROTATION_VALUES = List.of(ROT_0, ROT_90, ROT_180, ROT_270); + private static final List DIR_CARDINAL = Arrays.stream(Direction.values()) + .filter(Direction::isCardinal) + .collect(Collectors.toUnmodifiableList()); + private static final List DIR_ORDINAL = Arrays.stream(Direction.values()) + .filter(Direction::isOrdinal) + .collect(Collectors.toUnmodifiableList()); + private static final List DIR_SECONDARY_ORDINAL = Arrays.stream(Direction.values()) + .filter(Direction::isSecondaryOrdinal) + .collect(Collectors.toUnmodifiableList()); + public static boolean is(final Supplier r1, final Rotation r2) { return GeomUtil.is(r1.get(), r2); } @@ -94,6 +106,18 @@ public static List rotations() { return ROTATION_VALUES; } + public static List cardinalDirections() { + return DIR_CARDINAL; + } + + public static List ordinalDirections() { + return DIR_ORDINAL; + } + + public static List secondaryOrdinalDirections() { + return DIR_SECONDARY_ORDINAL; + } + public static Optional rotation(final Direction from, final Direction to) { if (!GeomUtil.isHorizontal(from)) { throw new IllegalArgumentException("'from' direction must be horizontal"); @@ -341,6 +365,19 @@ public static void forEachInCircle(final int x0, final int y0, final int radius, } } + public static void forEachCardinalNeighbour(final Vector3i pos, final IntTriConsumer action) { + GeomUtil.forEachCardinalNeighbour(pos.x(), pos.y(), pos.z(), action); + } + + public static void forEachCardinalNeighbour(final int x, final int y, final int z, final IntTriConsumer action) { + action.accept(x, y, z + 1); + action.accept(x, y, z - 1); + action.accept(x, y + 1, z); + action.accept(x, y - 1, z); + action.accept(x + 1, y, z); + action.accept(x - 1, y, z); + } + private GeomUtil() { } } From dcb1794578b3cc48b66b0a8fefc27c8ebd819f59 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sun, 27 Apr 2025 21:42:37 +0300 Subject: [PATCH 11/55] continue custom stuff --- .../custom/behaviour/Behaviour.java | 3 +- .../custom/behaviour/BehaviourArgs.java | 52 ++++ .../custom/behaviour/BehaviourCallback.java | 5 +- .../custom/behaviour/BehaviourHolder.java | 4 +- .../custom/behaviour/BehaviourManager.java | 46 +--- .../custom/behaviour/BehaviourMerger.java | 15 -- .../custom/behaviour/BehaviourType.java | 4 +- .../custom/behaviour/ModifiableBehaviour.java | 235 +++++++++++++++++ .../AnalogSignalPowerBlockStateBehaviour.java | 20 -- .../block/state/BlockStateBehaviour.java | 18 -- .../state/MapColorBlockStateBehaviour.java | 21 -- .../PushReactionBlockStateBehaviour.java | 18 -- .../state/ReplaceBlockStateBehaviour.java | 21 -- .../state/ShapeUpdateBlockStateBehaviour.java | 30 --- .../SignalConductorBlockStateBehaviour.java | 20 -- .../state/SignalPowerBlockStateBehaviour.java | 21 -- .../SignalUpdateBlockStateBehaviour.java | 29 --- .../SpawnValidatorBlockStateBehaviour.java | 21 -- .../block/state/TickBlockStateBehaviour.java | 21 -- .../behaviour/type/BlockStateBehaviour.java | 236 ++++++++++++++---- .../behaviour/type/BlockStateBehaviours.java | 38 ++- .../state => type}/BlockStateExtension.java | 2 +- .../custom/block/CustomBlockType.java | 2 +- .../block/DefaultedCustomBlockType.java | 2 +- .../event/RegisterBehaviourDataEvent.java | 63 ----- .../RegisterBlockStateBehaviourEvent.java | 65 +---- 26 files changed, 501 insertions(+), 511 deletions(-) delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourMerger.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviour.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalUpdateBlockStateBehaviour.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java rename src/main/java/net/hellheim/spongetools/custom/behaviour/{block/state => type}/BlockStateExtension.java (91%) diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java index 1214301..277f02d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java @@ -3,12 +3,11 @@ /** * Represents some action a {@link BehaviourHolder} can do. * - * @param Behaviour holder * @param Return type * @param
Behaviour arguments */ @FunctionalInterface -public interface Behaviour { +public interface Behaviour { R call(A args); } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java index ba426d3..4d0dd2d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java @@ -1,4 +1,56 @@ package net.hellheim.spongetools.custom.behaviour; +import java.util.Objects; + +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.util.RandomProvider; +import org.spongepowered.api.world.volume.Volume; +import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.math.vector.Vector3i; + public interface BehaviourArgs { + + interface Randomized> extends BehaviourArgs { + + RandomProvider.Source random(); + + A withRandom(RandomProvider.Source random); + + default A withRandom(final RandomProvider randomProvider) { + return this.withRandom(Objects.requireNonNull(randomProvider, "randomProvider").random()); + } + } + + interface Directional> extends BehaviourArgs { + + Direction direction(); + + A withDirection(Direction direction); + } + + interface Positional> extends BehaviourArgs { + + Vector3i position(); + + A withPosition(Vector3i position); + + default A withPosition(final Vector3d position) { + return this.withPosition(position.toInt()); + } + + default A withPosition(final int x, final int y, final int z) { + return this.withPosition(new Vector3i(x, y, z)); + } + + default A withPosition(final double x, final double y, final double z) { + return this.withPosition(new Vector3i(x, y, z)); + } + } + + interface Volumed> extends BehaviourArgs { + + V volume(); + + A withVolume(V volume); + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java index 584b571..5f3322d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java @@ -6,10 +6,9 @@ * @param Behaviour holder * @param Return type * @param Behaviour arguments - * @param Behaviour */ @FunctionalInterface -public interface BehaviourCallback> { +public interface BehaviourCallback { - R call(H holder, B origin, A args); + R call(H holder, Behaviour origin, A args); } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java index 9d3739a..b797a08 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java @@ -25,7 +25,7 @@ default boolean supports(final BehaviourType type) { * @param type The type of the behaviour * @return The behaviour, if present */ - default Optional get(final BehaviourType type) { + default > Optional get(final BehaviourType type) { return BehaviourManager.get().get(this.unwrap(), type); } @@ -37,7 +37,7 @@ default Optional get(final BehaviourType type) { * @return The behaviour * @throws NoSuchElementException if the type is not present on this {@link BehaviourHolder} */ - default B require(final BehaviourType type) { + default > B require(final BehaviourType type) { return this.get(type).orElseThrow(() -> new NoSuchElementException(String.format( "No behaviour of type %s is present for holder %s", type, this.unwrap() diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java index e0678e3..5e6efdb 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java @@ -12,55 +12,15 @@ static BehaviourManager get() { return Sponge.game().factoryProvider().provide(BehaviourManager.class); } - , B extends Behaviour.Extendable> Function callbackProvider( - BehaviourType type - ); + boolean supports(H holder, BehaviourType type); - , B extends Behaviour.Extendable> Function callbackConverter( - BehaviourType type - ); - - , B extends Behaviour.Extendable> Function callbackConverterBefore( - BehaviourType type - ); - - , B extends Behaviour.Extendable> Function callbackConverterAfter( - BehaviourType type - ); - - , B extends Behaviour.Extendable> BehaviourMerger callbackMerger( - BehaviourType type - ); - - boolean supports(H holder, BehaviourType type); - - Optional get(H holder, BehaviourType type); - - , B extends Behaviour.Extendable> void registerProvider( - BehaviourType type, Function callbackProvider - ); - - , B extends Behaviour.Extendable> void registerConverter( - BehaviourType type, Function callbackConverter - ); - - , B extends Behaviour.Extendable> void registerConverterBefore( - BehaviourType type, Function callbackConverterBefore - ); - - , B extends Behaviour.Extendable> void registerConverterAfter( - BehaviourType type, Function callbackConverterAfter - ); - - , B extends Behaviour.Extendable> void registerMerger( - BehaviourType type, BehaviourMerger callbackMerger - ); + > Optional get(H holder, BehaviourType type); BehaviourRegistration create(Class holder); interface BehaviourRegistration { - BehaviourRegistration register( + > BehaviourRegistration register( BehaviourType type, Function behaviourProvider ); } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourMerger.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourMerger.java deleted file mode 100644 index 2217530..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourMerger.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour; - -@FunctionalInterface -public interface BehaviourMerger> { - - /** - * Wraps the second behaviour around the first behaviour.
- * Means that first behaviour becomes the "original" for the second one. - * - * @param b1 The "original" behaviour - * @param b2 The "wrapper" behaviour - * @return The merged behaviour - */ - C merge(C b1, C b2); -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java index 1d0f9b9..84c0735 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java @@ -1,8 +1,8 @@ package net.hellheim.spongetools.custom.behaviour; -public interface BehaviourType> { +public interface BehaviourType> { - static > BehaviourType create() { + static > BehaviourType create() { return new BehaviourType<>() {}; } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java new file mode 100644 index 0000000..1cda7b8 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java @@ -0,0 +1,235 @@ +package net.hellheim.spongetools.custom.behaviour; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.BinaryOperator; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * + * @param Behaviour holder + */ +public interface ModifiableBehaviour { + + BehaviourManager manager(); + + H owner(); + + /** + * Returns the current behaviour callback for the given type, if present. + * + * @param Behaviour return type + * @param
Behaviour arguments + * @param type The behaviour type + * @return The current behaviour callback for the given type, if present + */ + Optional> get(BehaviourType> type); + + /** + * Sets the given behaviour callback for the given type.
+ * Overrides any previously registered callbacks. + * + * @param Behaviour return type + * @param
Behaviour arguments + * @param type The behaviour type + * @param callback The behaviour callback + * @return This modifiable behaviour, for chaining + */ + ModifiableBehaviour set(BehaviourType> type, BehaviourCallback callback); + + default ModifiableBehaviour set( + final BehaviourType> type, final Function behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + return this.set(type, (holder, origin, args) -> behaviour.apply(args)); + } + + default ModifiableBehaviour set( + final BehaviourType> type, final Consumer behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + return this.set(type, (holder, origin, args) -> { + behaviour.accept(args); + return null; + }); + } + + /** + * Sets the given value as a result of the callback for the given type. + * + * @param Behaviour return type + * @param Behaviour arguments + * @param type The behaviour type + * @param value The value to return + * @return This modifiable behaviour, for chaining + */ + default ModifiableBehaviour setValue( + final BehaviourType> type, final R value + ) { + Objects.requireNonNull(value, "value"); + return this.set(type, (holder, origin, args) -> value); + } + + /** + * Sets the given value as a result of the callback for the given type. + * + * @param Behaviour return type + * @param Behaviour arguments + * @param type The behaviour type + * @param value The value to return + * @return This modifiable behaviour, for chaining + */ + default ModifiableBehaviour setValue( + final BehaviourType> type, final Supplier valueSupplier + ) { + Objects.requireNonNull(valueSupplier, "valueSupplier"); + return this.setValue(type, valueSupplier.get()); + } + + default > ModifiableBehaviour setBehaviour( + final BehaviourType type, final B behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + return this.set(type, (holder, origin, args) -> behaviour.call(args)); + } + + /** + * Wraps the given callback around the current callback.
+ * Means that the current callback becomes the "original" for the given one.
+ * If current callback is not present, simply sets the given callback. + * + * @param Behaviour return type + * @param
Behaviour arguments + * @param type The behaviour type + * @param callback The behaviour callback + * @return This modifiable behaviour, for chaining + */ + default ModifiableBehaviour append( + final BehaviourType> type, final BehaviourCallback callback + ) { + Objects.requireNonNull(callback, "callback"); + return this.set(type, this.get(type) + .>map(old -> (holder, origin, args) -> + callback.call(holder, (newArgs) -> old.call(holder, origin, newArgs), args)) + .orElse(callback)); + } + + /** + * Wraps the current callback around the given callback.
+ * Means that the given callback becomes the "original" for the current one.
+ * If current callback is not present, simply sets the given callback. + * + * @param Behaviour return type + * @param
Behaviour arguments + * @param type The behaviour type + * @param callback The behaviour callback + * @return This modifiable behaviour, for chaining + */ + default ModifiableBehaviour prepend( + final BehaviourType> type, final BehaviourCallback callback + ) { + Objects.requireNonNull(callback, "callback"); + return this.set(type, this.get(type) + .>map(old -> (holder, origin, args) -> + old.call(holder, (newArgs) -> callback.call(holder, origin, newArgs), args)) + .orElse(callback)); + } + + + + default ModifiableBehaviour appendAfter( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.append(type, (holder, origin, args) -> { + final R result = origin.call(args); + action.accept(args); + return result; + }); + } + + default ModifiableBehaviour appendAfter( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.append(type, (holder, origin, args) -> { + final R oldResult = origin.call(args); + final R newResult = behaviour.apply(args); + return resultMerger.apply(oldResult, newResult); + }); + } + + default ModifiableBehaviour appendBefore( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.append(type, (holder, origin, args) -> { + action.accept(args); + final R result = origin.call(args); + return result; + }); + } + + default ModifiableBehaviour appendBefore( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.append(type, (holder, origin, args) -> { + final R newResult = behaviour.apply(args); + final R oldResult = origin.call(args); + return resultMerger.apply(oldResult, newResult); + }); + } + + + + default ModifiableBehaviour prependAfter( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.prepend(type, (holder, origin, args) -> { + final R result = origin.call(args); + action.accept(args); + return result; + }); + } + + default ModifiableBehaviour prependAfter( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.prepend(type, (holder, origin, args) -> { + final R oldResult = origin.call(args); + final R newResult = behaviour.apply(args); + return resultMerger.apply(oldResult, newResult); + }); + } + + default ModifiableBehaviour prependBefore( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.prepend(type, (holder, origin, args) -> { + action.accept(args); + final R result = origin.call(args); + return result; + }); + } + + default ModifiableBehaviour prependBefore( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.prepend(type, (holder, origin, args) -> { + final R newResult = behaviour.apply(args); + final R oldResult = origin.call(args); + return resultMerger.apply(oldResult, newResult); + }); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java deleted file mode 100644 index 5e1a605..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/AnalogSignalPowerBlockStateBehaviour.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -import org.spongepowered.api.world.World; -import org.spongepowered.math.vector.Vector3i; - -@FunctionalInterface -public interface AnalogSignalPowerBlockStateBehaviour - extends BlockStateBehaviour { - - int apply(World world, Vector3i position); - - @FunctionalInterface - interface Callback extends BlockStateBehaviour.Callback { - - int apply( - BlockStateExtension state, AnalogSignalPowerBlockStateBehaviour origin, - World world, Vector3i position - ); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviour.java deleted file mode 100644 index 9d19234..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateBehaviour.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -import java.util.Optional; - -import com.mojang.serialization.MapCodec; - -import net.hellheim.spongetools.custom.behaviour.Behaviour; - -public interface BlockStateBehaviour> extends Behaviour.Extendable { - - interface Callback extends Behaviour.SerializableCallback { - - @Override - default Optional>> codec() { - return Optional.empty(); - } - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java deleted file mode 100644 index 750f799..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/MapColorBlockStateBehaviour.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -import org.spongepowered.api.map.color.MapColorType; -import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; -import org.spongepowered.math.vector.Vector3i; - -@FunctionalInterface -public interface MapColorBlockStateBehaviour - extends BlockStateBehaviour { - - MapColorType apply(PrimitiveGameVolume volume, Vector3i position); - - @FunctionalInterface - interface Callback extends BlockStateBehaviour.Callback { - - MapColorType apply( - BlockStateExtension state, MapColorBlockStateBehaviour origin, - PrimitiveGameVolume volume, Vector3i position - ); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java deleted file mode 100644 index de49180..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/PushReactionBlockStateBehaviour.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -import org.spongepowered.api.data.type.PushReaction; - -@FunctionalInterface -public interface PushReactionBlockStateBehaviour - extends BlockStateBehaviour { - - PushReaction apply(); - - @FunctionalInterface - interface Callback extends BlockStateBehaviour.Callback { - - PushReaction apply( - BlockStateExtension state, PushReactionBlockStateBehaviour origin - ); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java deleted file mode 100644 index 4cb7890..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ReplaceBlockStateBehaviour.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -import org.spongepowered.api.block.BlockState; -import org.spongepowered.api.world.World; -import org.spongepowered.math.vector.Vector3i; - -@FunctionalInterface -public interface ReplaceBlockStateBehaviour - extends BlockStateBehaviour { - - void apply(World world, Vector3i position, BlockState otherState, boolean movedByPiston); - - @FunctionalInterface - interface Callback extends BlockStateBehaviour.Callback { - - void apply( - BlockStateExtension state, ReplaceBlockStateBehaviour origin, - World world, Vector3i position, BlockState otherState, boolean movedByPiston - ); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java deleted file mode 100644 index f243dec..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/ShapeUpdateBlockStateBehaviour.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -import org.spongepowered.api.block.BlockState; -import org.spongepowered.api.util.Direction; -import org.spongepowered.api.util.RandomProvider; -import org.spongepowered.api.world.volume.game.Region; -import org.spongepowered.api.world.volume.game.UpdatableVolume; -import org.spongepowered.math.vector.Vector3i; - -@FunctionalInterface -public interface ShapeUpdateBlockStateBehaviour - extends BlockStateBehaviour { - - BlockState apply( - Region region, UpdatableVolume volume, Vector3i position, - Direction direction, Vector3i neighbourPosition, BlockState neighbourState, - RandomProvider.Source random - ); - - @FunctionalInterface - interface Callback extends BlockStateBehaviour.Callback { - - BlockState apply( - BlockStateExtension state, ShapeUpdateBlockStateBehaviour origin, - Region region, UpdatableVolume volume, Vector3i position, - Direction direction, Vector3i neighbourPosition, BlockState neighbourState, - RandomProvider.Source random - ); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java deleted file mode 100644 index a018759..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalConductorBlockStateBehaviour.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; -import org.spongepowered.math.vector.Vector3i; - -@FunctionalInterface -public interface SignalConductorBlockStateBehaviour - extends BlockStateBehaviour { - - boolean apply(PrimitiveGameVolume volume, Vector3i position); - - @FunctionalInterface - interface Callback extends BlockStateBehaviour.Callback { - - boolean apply( - BlockStateExtension state, SignalConductorBlockStateBehaviour origin, - PrimitiveGameVolume volume, Vector3i position - ); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java deleted file mode 100644 index 4b8a924..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalPowerBlockStateBehaviour.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -import org.spongepowered.api.util.Direction; -import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; -import org.spongepowered.math.vector.Vector3i; - -@FunctionalInterface -public interface SignalPowerBlockStateBehaviour - extends BlockStateBehaviour { - - int apply(PrimitiveGameVolume volume, Vector3i position, Direction direction); - - @FunctionalInterface - interface Callback extends BlockStateBehaviour.Callback { - - int apply( - BlockStateExtension state, SignalPowerBlockStateBehaviour origin, - PrimitiveGameVolume volume, Vector3i position, Direction direction - ); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalUpdateBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalUpdateBlockStateBehaviour.java deleted file mode 100644 index d86c47e..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SignalUpdateBlockStateBehaviour.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -import java.util.Optional; - -import org.spongepowered.api.block.BlockType; -import org.spongepowered.api.world.World; -import org.spongepowered.math.vector.Vector3i; - -import net.hellheim.spongetools.custom.behaviour.world.SignalOrientation; - -@FunctionalInterface -public interface SignalUpdateBlockStateBehaviour - extends BlockStateBehaviour { - - void apply( - World world, Vector3i position, BlockType notifier, - Optional orientation, boolean movedByPiston - ); - - @FunctionalInterface - interface Callback extends BlockStateBehaviour.Callback { - - void apply( - BlockStateExtension state, SignalUpdateBlockStateBehaviour origin, - World world, Vector3i position, BlockType notifier, - Optional orientation, boolean movedByPiston - ); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java deleted file mode 100644 index b572c2a..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/SpawnValidatorBlockStateBehaviour.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -import org.spongepowered.api.entity.EntityType; -import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; -import org.spongepowered.math.vector.Vector3i; - -@FunctionalInterface -public interface SpawnValidatorBlockStateBehaviour - extends BlockStateBehaviour { - - boolean apply(PrimitiveGameVolume volume, Vector3i position, EntityType entity); - - @FunctionalInterface - interface Callback extends BlockStateBehaviour.Callback { - - boolean apply( - BlockStateExtension state, SpawnValidatorBlockStateBehaviour origin, - PrimitiveGameVolume volume, Vector3i position, EntityType entity - ); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java deleted file mode 100644 index 31a3561..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/TickBlockStateBehaviour.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; - -import org.spongepowered.api.util.RandomProvider; -import org.spongepowered.api.world.server.ServerWorld; -import org.spongepowered.math.vector.Vector3i; - -@FunctionalInterface -public interface TickBlockStateBehaviour - extends BlockStateBehaviour { - - void apply(ServerWorld world, Vector3i position, RandomProvider.Source random); - - @FunctionalInterface - interface Callback extends BlockStateBehaviour.Callback { - - void apply( - BlockStateExtension state, TickBlockStateBehaviour origin, - ServerWorld world, Vector3i position, RandomProvider.Source random - ); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java index b682502..11345d8 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java @@ -1,101 +1,233 @@ package net.hellheim.spongetools.custom.behaviour.type; import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.data.type.PushReaction; import org.spongepowered.api.entity.EntityType; +import org.spongepowered.api.map.color.MapColorType; import org.spongepowered.api.util.Direction; import org.spongepowered.api.util.RandomProvider; +import org.spongepowered.api.world.World; import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; +import org.spongepowered.api.world.volume.game.Region; +import org.spongepowered.api.world.volume.game.UpdatableVolume; import org.spongepowered.math.vector.Vector3i; import net.hellheim.spongetools.custom.behaviour.Behaviour; import net.hellheim.spongetools.custom.behaviour.BehaviourArgs; -import net.hellheim.spongetools.custom.behaviour.block.state.BlockStateExtension; +import net.hellheim.spongetools.custom.behaviour.world.SignalOrientation; -public interface BlockStateBehaviour extends Behaviour { +public interface BlockStateBehaviour extends Behaviour { interface SpawnValidator extends BlockStateBehaviour { - default boolean call(final PrimitiveGameVolume volume, final Vector3i position, final EntityType entity) { - return this.call(new Args(volume, position, entity)); + @Override + default Boolean call(final Args args) { + return this.call(args.volume(), args.position(), args.entity()); } - record Args(PrimitiveGameVolume volume, Vector3i position, EntityType entity) implements BehaviourArgs { + boolean call(PrimitiveGameVolume volume, Vector3i position, EntityType entity); + + interface Args extends + BehaviourArgs.Volumed, + BehaviourArgs.Positional { - public Args(final PrimitiveGameVolume volume, final Vector3i position, final EntityType entity) { - this.volume = Objects.requireNonNull(volume, "volume"); - this.position = Objects.requireNonNull(position, "position"); - this.entity = Objects.requireNonNull(entity, "entity"); - } + EntityType entity(); - public Args withVolume(final PrimitiveGameVolume volume) { - return new Args(volume, this.position, this.entity); - } + Args withEntity(EntityType entity); + } + } + + interface MapColor extends BlockStateBehaviour { + + @Override + default MapColorType call(final Args args) { + return this.call(args.volume(), args.position()); + } + + MapColorType call(PrimitiveGameVolume volume, Vector3i position); + + interface Args extends + BehaviourArgs.Volumed, + BehaviourArgs.Positional { + } + } + + interface PistonPushReaction extends BlockStateBehaviour { + + @Override + default PushReaction call(final BehaviourArgs args) { + return this.call(); + } + + PushReaction call(); + } + + interface SignalConductor extends BlockStateBehaviour { + + @Override + default Boolean call(final Args args) { + return this.call(args.volume(), args.position()); + } + + boolean call(PrimitiveGameVolume volume, Vector3i position); + + interface Args extends + BehaviourArgs.Volumed, + BehaviourArgs.Positional { + } + } + + interface SignalPower extends BlockStateBehaviour { + + @Override + default Integer call(final Args args) { + return this.call(args.volume(), args.position(), args.direction()); + } + + int call(PrimitiveGameVolume volume, Vector3i position, Direction direction); + + interface Args extends + BehaviourArgs.Volumed, + BehaviourArgs.Positional, + BehaviourArgs.Directional { + } + } + + interface AnalogSignalPower extends BlockStateBehaviour { + + @Override + default Integer call(final Args args) { + return this.call(args.volume(), args.position()); + } + + int call(World volume, Vector3i position); + + interface Args extends + BehaviourArgs.Volumed, Args>, + BehaviourArgs.Positional { + } + } + + interface Tick extends BlockStateBehaviour { + + @Override + default Void call(final Args args) { + this.call(args.volume(), args.position(), args.random()); + return null; + } + + void call(ServerWorld world, Vector3i position, RandomProvider.Source random); + + interface Args extends + BehaviourArgs.Volumed, + BehaviourArgs.Positional, + BehaviourArgs.Randomized { + } + } + + interface Replace extends BlockStateBehaviour { + + @Override + default Void call(final Args args) { + this.call(args.volume(), args.position(), args.otherState(), args.movedByPiston()); + return null; + } + + void call(World world, Vector3i position, BlockState otherState, boolean movedByPiston); + + interface Args extends + BehaviourArgs.Volumed, Args>, + BehaviourArgs.Positional { - public Args withPosition(final Vector3i position) { - return new Args(this.volume, position, this.entity); - } + BlockState otherState(); - public Args withEntity(final EntityType entity) { - return new Args(this.volume, this.position, entity); - } + boolean movedByPiston(); + + Args withOtherState(BlockState otherState); + + Args withMovedByPiston(boolean movedByPiston); } } - interface SignalPower extends BlockStateBehaviour { + interface ShapeUpdate extends BlockStateBehaviour { - default int call(final PrimitiveGameVolume volume, final Vector3i position, final Direction direction) { - return this.call(new Args(volume, position, direction)); + @Override + default BlockState call(final Args args) { + return this.call(args.volume(), args.updates(), args.position(), args.direction(), args.neighbourPosition(), args.neighbourState(), args.random()); } - record Args(PrimitiveGameVolume volume, Vector3i position, Direction direction) implements BehaviourArgs { + BlockState call( + Region volume, UpdatableVolume updates, Vector3i position, + Direction direction, Vector3i neighbourPosition, BlockState neighbourState, + RandomProvider.Source random + ); + + interface Args extends + BehaviourArgs.Volumed, Args>, + BehaviourArgs.Positional, + BehaviourArgs.Directional, + BehaviourArgs.Randomized { - public Args(final PrimitiveGameVolume volume, final Vector3i position, final Direction direction) { - this.volume = Objects.requireNonNull(volume, "volume"); - this.position = Objects.requireNonNull(position, "position"); - this.direction = Objects.requireNonNull(direction, "direction"); - } + UpdatableVolume updates(); - public Args withVolume(final PrimitiveGameVolume volume) { - return new Args(volume, this.position, this.direction); - } + Vector3i neighbourPosition(); - public Args withPosition(final Vector3i position) { - return new Args(this.volume, position, this.direction); - } + BlockState neighbourState(); - public Args withDirection(final Direction direction) { - return new Args(this.volume, this.position, direction); - } + Args withUpdates(UpdatableVolume updates); + + Args withNeighbourPosition(Vector3i neighbourPosition); + + Args withNeighbourState(BlockState neighbourState); } } - interface Tick extends BlockStateBehaviour { + interface SignalUpdate extends BlockStateBehaviour { - default void call(final ServerWorld world, final Vector3i position, final RandomProvider.Source random) { - this.call(new Args(world, position, random)); + @Override + default Void call(final Args args) { + this.call(args.volume(), args.position(), args.notifier(), args.orientation(), args.movedByPiston()); + return null; } - record Args(ServerWorld world, Vector3i position, RandomProvider.Source random) implements BehaviourArgs { + void call( + World volume, Vector3i position, BlockType notifier, + Optional orientation, boolean movedByPiston + ); + + interface Args extends + BehaviourArgs.Volumed, Args>, + BehaviourArgs.Positional { - public Args(final ServerWorld world, final Vector3i position, final RandomProvider.Source random) { - this.world = Objects.requireNonNull(world, "world"); - this.position = Objects.requireNonNull(position, "position"); - this.random = Objects.requireNonNull(random, "random"); - } + BlockType notifier(); + + Optional orientation(); - public Args withWorld(final ServerWorld world) { - return new Args(world, this.position, this.random); + boolean movedByPiston(); + + Args withNotifier(BlockType notifier); + + default Args withNotifier(Supplier notifierSupplier) { + return this.withNotifier(Objects.requireNonNull(notifierSupplier, "notifierSupplier").get()); } - public Args withPosition(final Vector3i position) { - return new Args(this.world, position, this.random); + Args withOrientation(Optional orientation); + + default Args withOrientation(final SignalOrientation orientation) { + return this.withOrientation(Optional.of(Objects.requireNonNull(orientation, "orientation"))); } - public Args withRandom(final RandomProvider.Source random) { - return new Args(this.world, this.position, random); + default Args withoutOrientation() { + return this.withOrientation(Optional.empty()); } + + Args withMovedByPiston(boolean movedByPiston); } } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java index 896524a..3f69fe7 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java @@ -5,35 +5,25 @@ import org.spongepowered.api.world.volume.game.UpdatableVolume; import net.hellheim.spongetools.custom.behaviour.BehaviourType; -import net.hellheim.spongetools.custom.behaviour.block.state.AnalogSignalPowerBlockStateBehaviour; -import net.hellheim.spongetools.custom.behaviour.block.state.BlockStateExtension; -import net.hellheim.spongetools.custom.behaviour.block.state.MapColorBlockStateBehaviour; -import net.hellheim.spongetools.custom.behaviour.block.state.PushReactionBlockStateBehaviour; -import net.hellheim.spongetools.custom.behaviour.block.state.ReplaceBlockStateBehaviour; -import net.hellheim.spongetools.custom.behaviour.block.state.ShapeUpdateBlockStateBehaviour; -import net.hellheim.spongetools.custom.behaviour.block.state.SignalConductorBlockStateBehaviour; -import net.hellheim.spongetools.custom.behaviour.block.state.SignalPowerBlockStateBehaviour; -import net.hellheim.spongetools.custom.behaviour.block.state.SignalUpdateBlockStateBehaviour; -import net.hellheim.spongetools.custom.behaviour.block.state.SpawnValidatorBlockStateBehaviour; -import net.hellheim.spongetools.custom.behaviour.block.state.TickBlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.*; public final class BlockStateBehaviours { - public static final BehaviourType SPAWN_VALIDATOR = BehaviourType.create(); + public static final BehaviourType SPAWN_VALIDATOR = BehaviourType.create(); - public static final BehaviourType MAP_COLOR = BehaviourType.create(); + public static final BehaviourType MAP_COLOR = BehaviourType.create(); /** * Used by {@link BlockTypes#PISTON} and {@link BlockTypes#STICKY_PISTON}. */ - public static final BehaviourType PUSH_REACTION = BehaviourType.create(); + public static final BehaviourType PUSH_REACTION = BehaviourType.create(); - public static final BehaviourType SIGNAL_CONDUCTOR = BehaviourType.create(); + public static final BehaviourType SIGNAL_CONDUCTOR = BehaviourType.create(); /** * Signal that will power neighbour blocks. */ - public static final BehaviourType SIGNAL_POWER = BehaviourType.create(); + public static final BehaviourType SIGNAL_POWER = BehaviourType.create(); /** * Signal that will go through neighbour blocks.
@@ -44,31 +34,31 @@ public final class BlockStateBehaviours { * * Used by {@link BlockTypes#REPEATER} (horizontally) and other redstone-related blocks (upwards). */ - public static final BehaviourType DIRECT_SIGNAL_POWER = BehaviourType.create(); + public static final BehaviourType DIRECT_SIGNAL_POWER = BehaviourType.create(); /** * Result of this behaviour is usually used by {@link BlockTypes#COMPARATOR}. */ - public static final BehaviourType ANALOG_SIGNAL_POWER = BehaviourType.create(); + public static final BehaviourType ANALOG_SIGNAL_POWER = BehaviourType.create(); /** * Adding this behaviour doesn't make block ticking "naturally".
* Ticks must be scheduled through {@link UpdatableVolume#scheduledBlockUpdates()}.
* For example, ticks could be scheduled in {@link #PLACE}, {@link #SHAPE_UPDATE} or in {@link #TICK} itself. */ - public static final BehaviourType TICK = BehaviourType.create(); + public static final BehaviourType TICK = BehaviourType.create(); - public static final BehaviourType RANDOM_TICK = BehaviourType.create(); + public static final BehaviourType RANDOM_TICK = BehaviourType.create(); /** * Called when {@link BlockState} enters the world. */ - public static final BehaviourType PLACE = BehaviourType.create(); + public static final BehaviourType PLACE = BehaviourType.create(); /** * Called when {@link BlockState} leaves the world. */ - public static final BehaviourType REMOVE = BehaviourType.create(); + public static final BehaviourType REMOVE = BehaviourType.create(); /** * Called when neighbour {@link BlockState}s are changed.
@@ -78,7 +68,7 @@ public final class BlockStateBehaviours { * * @see #SIGNAL_UPDATE */ - public static final BehaviourType SHAPE_UPDATE = BehaviourType.create(); + public static final BehaviourType SHAPE_UPDATE = BehaviourType.create(); /** * Called when neighbour {@link BlockState}s are changed (mostly due to signal changes).
@@ -86,7 +76,7 @@ public final class BlockStateBehaviours { * * @see #SHAPE_UPDATE */ - public static final BehaviourType SIGNAL_UPDATE = BehaviourType.create(); + public static final BehaviourType SIGNAL_UPDATE = BehaviourType.create(); private BlockStateBehaviours() { } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateExtension.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java similarity index 91% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateExtension.java rename to src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java index a8616b8..f4191b0 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/block/state/BlockStateExtension.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.behaviour.block.state; +package net.hellheim.spongetools.custom.behaviour.type; import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; diff --git a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java index 6f706f3..dcdecff 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java +++ b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java @@ -1,6 +1,6 @@ package net.hellheim.spongetools.custom.block; -import net.hellheim.spongetools.custom.behaviour.block.state.BlockStateExtension; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; public interface CustomBlockType { diff --git a/src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java index 72760a9..f97eac8 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java +++ b/src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java @@ -2,7 +2,7 @@ import java.util.Objects; -import net.hellheim.spongetools.custom.behaviour.block.state.BlockStateExtension; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; public class DefaultedCustomBlockType implements CustomBlockType { diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java b/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java index 95f776e..548bb95 100644 --- a/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java +++ b/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java @@ -1,78 +1,15 @@ package net.hellheim.spongetools.event; -import java.util.function.Function; - import org.spongepowered.api.event.lifecycle.LifecycleEvent; -import net.hellheim.spongetools.custom.behaviour.Behaviour; import net.hellheim.spongetools.custom.behaviour.BehaviourManager; -import net.hellheim.spongetools.custom.behaviour.BehaviourMerger; -import net.hellheim.spongetools.custom.behaviour.BehaviourType; import net.hellheim.spongetools.custom.behaviour.BehaviourManager.BehaviourRegistration; public interface RegisterBehaviourDataEvent extends LifecycleEvent { BehaviourManager manager(); - default , B extends Behaviour.Extendable> void registerProvider( - final BehaviourType type, final Function callbackProvider - ) { - this.manager().registerProvider(type, callbackProvider); - } - - default , B extends Behaviour.Extendable> void registerConverter( - final BehaviourType type, final Function callbackConverter - ) { - this.manager().registerConverter(type, callbackConverter); - } - - default , B extends Behaviour.Extendable> void registerConverterBefore( - final BehaviourType type, final Function callbackConverterBefore - ) { - this.manager().registerConverterBefore(type, callbackConverterBefore); - } - - default , B extends Behaviour.Extendable> void registerConverterAfter( - final BehaviourType type, final Function callbackConverterAfter - ) { - this.manager().registerConverterAfter(type, callbackConverterAfter); - } - - default , B extends Behaviour.Extendable> void registerMerger( - final BehaviourType type, final BehaviourMerger callbackMerger - ) { - this.manager().registerMerger(type, callbackMerger); - } - default BehaviourRegistration create(final Class holder) { return this.manager().create(holder); } - - default , B extends Behaviour.Extendable> void register( - final BehaviourType type, - final Function callbackProvider, - final Function callbackConverter, - final Function callbackConverterBefore, - final Function callbackConverterAfter, - final BehaviourMerger callbackMerger - ) { - this.registerProvider(type, callbackProvider); - this.registerConverter(type, callbackConverter); - this.registerConverterBefore(type, callbackConverterBefore); - this.registerConverterAfter(type, callbackConverterAfter); - this.registerMerger(type, callbackMerger); - } - - default , B extends Behaviour.Extendable> void register( - final BehaviourType type, - final Function callbackConverter, - final Function callbackConverterBefore, - final Function callbackConverterAfter, - final BehaviourMerger callbackMerger - ) { - this.registerConverter(type, callbackConverter); - this.registerConverterBefore(type, callbackConverterBefore); - this.registerConverterAfter(type, callbackConverterAfter); - this.registerMerger(type, callbackMerger); - } } diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java index 0a92f4f..c3849c8 100644 --- a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java +++ b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java @@ -1,7 +1,6 @@ package net.hellheim.spongetools.event; import java.util.Arrays; -import java.util.Objects; import java.util.function.Supplier; import java.util.stream.Stream; @@ -11,9 +10,8 @@ import com.google.common.collect.Streams; -import net.hellheim.spongetools.custom.behaviour.BehaviourManager; -import net.hellheim.spongetools.custom.behaviour.BehaviourType; -import net.hellheim.spongetools.custom.behaviour.block.state.BlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.ModifiableBehaviour; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; public interface RegisterBlockStateBehaviourEvent extends LifecycleEvent { @@ -83,63 +81,6 @@ default Stream allStates(final Iterable type } - interface BehaviourStep { - - BehaviourManager manager(); - - , B extends BlockStateBehaviour> void append(BehaviourType type, C callback); - - , B extends BlockStateBehaviour> void prepend(BehaviourType type, C callback); - - , B extends BlockStateBehaviour> void set(BehaviourType type, C callback); - - default , B extends BlockStateBehaviour> void appendBefore( - final BehaviourType type, final B behaviour - ) { - Objects.requireNonNull(behaviour, "behaviour"); - this.append(type, this.manager().callbackConverterBefore(type).apply(behaviour)); - } - - default , B extends BlockStateBehaviour> void appendAfter( - final BehaviourType type, final B behaviour - ) { - Objects.requireNonNull(behaviour, "behaviour"); - this.append(type, this.manager().callbackConverterAfter(type).apply(behaviour)); - } - - default , B extends BlockStateBehaviour> void prependBefore( - final BehaviourType type, final B behaviour - ) { - Objects.requireNonNull(behaviour, "behaviour"); - this.prepend(type, this.manager().callbackConverterBefore(type).apply(behaviour)); - } - - default , B extends BlockStateBehaviour> void prependAfter( - final BehaviourType type, final B behaviour - ) { - Objects.requireNonNull(behaviour, "behaviour"); - this.prepend(type, this.manager().callbackConverterAfter(type).apply(behaviour)); - } - - default , B extends BlockStateBehaviour> void setBehaviour( - final BehaviourType type, final B behaviour - ) { - Objects.requireNonNull(behaviour, "behaviour"); - this.set(type, this.manager().callbackConverter(type).apply(behaviour)); - } - - default , B extends BlockStateBehaviour> void set( - final BehaviourType type, final R value - ) { - Objects.requireNonNull(value, "value"); - this.set(type, this.manager().callbackProvider(type).apply(value)); - } - - default , B extends BlockStateBehaviour> void set( - final BehaviourType type, final Supplier valueSupplier - ) { - Objects.requireNonNull(valueSupplier, "valueSupplier"); - this.set(type, valueSupplier.get()); - } + interface BehaviourStep extends ModifiableBehaviour { } } From 18c80eec337369a65b52cb84976ea728cd770d8a Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Mon, 28 Apr 2025 00:48:19 +0300 Subject: [PATCH 12/55] try split behavioir into action & product --- .../custom/behaviour/Behaviour.java | 17 +++-- .../custom/behaviour/BehaviourCallback.java | 15 ++++- .../custom/behaviour/BehaviourHolder.java | 4 +- .../custom/behaviour/BehaviourManager.java | 4 +- .../custom/behaviour/ModifiableBehaviour.java | 66 +++++++++++-------- 5 files changed, 69 insertions(+), 37 deletions(-) diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java index 277f02d..28b5562 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java @@ -1,13 +1,22 @@ package net.hellheim.spongetools.custom.behaviour; /** - * Represents some action a {@link BehaviourHolder} can do. + * Represents something a {@link BehaviourHolder} can do. * * @param Return type * @param
Behaviour arguments */ -@FunctionalInterface -public interface Behaviour { +public interface Behaviour { - R call(A args); + @FunctionalInterface + interface Action extends Behaviour { + + void call(A args); + } + + @FunctionalInterface + interface Product extends Behaviour { + + R call(A args); + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java index 5f3322d..b03f1e3 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java @@ -7,8 +7,17 @@ * @param Return type * @param Behaviour arguments */ -@FunctionalInterface -public interface BehaviourCallback { +public interface BehaviourCallback { - R call(H holder, Behaviour origin, A args); + @FunctionalInterface + interface Action extends BehaviourCallback { + + void call(H holder, Behaviour.Action origin, A args); + } + + @FunctionalInterface + interface Product extends BehaviourCallback { + + R call(H holder, Behaviour.Product origin, A args); + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java index b797a08..9d3739a 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java @@ -25,7 +25,7 @@ default boolean supports(final BehaviourType type) { * @param type The type of the behaviour * @return The behaviour, if present */ - default > Optional get(final BehaviourType type) { + default Optional get(final BehaviourType type) { return BehaviourManager.get().get(this.unwrap(), type); } @@ -37,7 +37,7 @@ default boolean supports(final BehaviourType type) { * @return The behaviour * @throws NoSuchElementException if the type is not present on this {@link BehaviourHolder} */ - default > B require(final BehaviourType type) { + default B require(final BehaviourType type) { return this.get(type).orElseThrow(() -> new NoSuchElementException(String.format( "No behaviour of type %s is present for holder %s", type, this.unwrap() diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java index 5e6efdb..48b57e5 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java @@ -14,13 +14,13 @@ static BehaviourManager get() { boolean supports(H holder, BehaviourType type); - > Optional get(H holder, BehaviourType type); + Optional get(H holder, BehaviourType type); BehaviourRegistration create(Class holder); interface BehaviourRegistration { - > BehaviourRegistration register( + BehaviourRegistration register( BehaviourType type, Function behaviourProvider ); } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java index 1cda7b8..7d76bb0 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java @@ -25,7 +25,11 @@ public interface ModifiableBehaviour { * @param type The behaviour type * @return The current behaviour callback for the given type, if present */ - Optional> get(BehaviourType> type); + Optional> getAction(BehaviourType> type); + + Optional> getProduct(BehaviourType> type); + + ModifiableBehaviour set(BehaviourType> type, BehaviourCallback.Action callback); /** * Sets the given behaviour callback for the given type.
@@ -37,23 +41,20 @@ public interface ModifiableBehaviour { * @param callback The behaviour callback * @return This modifiable behaviour, for chaining */ - ModifiableBehaviour set(BehaviourType> type, BehaviourCallback callback); + ModifiableBehaviour set(BehaviourType> type, BehaviourCallback.Product callback); - default ModifiableBehaviour set( - final BehaviourType> type, final Function behaviour + default
> ModifiableBehaviour set( + final BehaviourType> type, final Behaviour.Action behaviour ) { Objects.requireNonNull(behaviour, "behaviour"); - return this.set(type, (holder, origin, args) -> behaviour.apply(args)); + return this.set(type, (holder, origin, args) -> behaviour.call(args)); } - default ModifiableBehaviour set( - final BehaviourType> type, final Consumer behaviour + default ModifiableBehaviour set( + final BehaviourType> type, final Behaviour.Product behaviour ) { Objects.requireNonNull(behaviour, "behaviour"); - return this.set(type, (holder, origin, args) -> { - behaviour.accept(args); - return null; - }); + return this.set(type, (holder, origin, args) -> behaviour.call(args)); } /** @@ -66,7 +67,7 @@ default ModifiableBehaviour set( * @return This modifiable behaviour, for chaining */ default ModifiableBehaviour setValue( - final BehaviourType> type, final R value + final BehaviourType> type, final R value ) { Objects.requireNonNull(value, "value"); return this.set(type, (holder, origin, args) -> value); @@ -82,19 +83,12 @@ default ModifiableBehaviour setValue( * @return This modifiable behaviour, for chaining */ default ModifiableBehaviour setValue( - final BehaviourType> type, final Supplier valueSupplier + final BehaviourType> type, final Supplier valueSupplier ) { Objects.requireNonNull(valueSupplier, "valueSupplier"); return this.setValue(type, valueSupplier.get()); } - default > ModifiableBehaviour setBehaviour( - final BehaviourType type, final B behaviour - ) { - Objects.requireNonNull(behaviour, "behaviour"); - return this.set(type, (holder, origin, args) -> behaviour.call(args)); - } - /** * Wraps the given callback around the current callback.
* Means that the current callback becomes the "original" for the given one.
@@ -106,12 +100,22 @@ default > ModifiableBehavi * @param callback The behaviour callback * @return This modifiable behaviour, for chaining */ + default
ModifiableBehaviour append( + final BehaviourType> type, final BehaviourCallback.Action callback + ) { + Objects.requireNonNull(callback, "callback"); + return this.set(type, this.getAction(type) + .>map(old -> (holder, origin, args) -> + callback.call(holder, (newArgs) -> old.call(holder, origin, newArgs), args)) + .orElse(callback)); + } + default ModifiableBehaviour append( - final BehaviourType> type, final BehaviourCallback callback + final BehaviourType> type, final BehaviourCallback.Product callback ) { Objects.requireNonNull(callback, "callback"); - return this.set(type, this.get(type) - .>map(old -> (holder, origin, args) -> + return this.set(type, this.getProduct(type) + .>map(old -> (holder, origin, args) -> callback.call(holder, (newArgs) -> old.call(holder, origin, newArgs), args)) .orElse(callback)); } @@ -127,12 +131,22 @@ default ModifiableBehaviour append( * @param callback The behaviour callback * @return This modifiable behaviour, for chaining */ + default ModifiableBehaviour prepend( + final BehaviourType> type, final BehaviourCallback.Action callback + ) { + Objects.requireNonNull(callback, "callback"); + return this.set(type, this.getAction(type) + .>map(old -> (holder, origin, args) -> + old.call(holder, (newArgs) -> callback.call(holder, origin, newArgs), args)) + .orElse(callback)); + } + default ModifiableBehaviour prepend( - final BehaviourType> type, final BehaviourCallback callback + final BehaviourType> type, final BehaviourCallback.Product callback ) { Objects.requireNonNull(callback, "callback"); - return this.set(type, this.get(type) - .>map(old -> (holder, origin, args) -> + return this.set(type, this.getProduct(type) + .>map(old -> (holder, origin, args) -> old.call(holder, (newArgs) -> callback.call(holder, origin, newArgs), args)) .orElse(callback)); } From b43ae58343860609157ea11038bfb15778fe5f9e Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Mon, 28 Apr 2025 00:48:22 +0300 Subject: [PATCH 13/55] Revert "try split behavioir into action & product" This reverts commit 18c80eec337369a65b52cb84976ea728cd770d8a. --- .../custom/behaviour/Behaviour.java | 17 ++--- .../custom/behaviour/BehaviourCallback.java | 15 +---- .../custom/behaviour/BehaviourHolder.java | 4 +- .../custom/behaviour/BehaviourManager.java | 4 +- .../custom/behaviour/ModifiableBehaviour.java | 66 ++++++++----------- 5 files changed, 37 insertions(+), 69 deletions(-) diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java index 28b5562..277f02d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java @@ -1,22 +1,13 @@ package net.hellheim.spongetools.custom.behaviour; /** - * Represents something a {@link BehaviourHolder} can do. + * Represents some action a {@link BehaviourHolder} can do. * * @param Return type * @param Behaviour arguments */ -public interface Behaviour { +@FunctionalInterface +public interface Behaviour { - @FunctionalInterface - interface Action extends Behaviour { - - void call(A args); - } - - @FunctionalInterface - interface Product extends Behaviour { - - R call(A args); - } + R call(A args); } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java index b03f1e3..5f3322d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java @@ -7,17 +7,8 @@ * @param Return type * @param Behaviour arguments */ -public interface BehaviourCallback { +@FunctionalInterface +public interface BehaviourCallback { - @FunctionalInterface - interface Action extends BehaviourCallback { - - void call(H holder, Behaviour.Action origin, A args); - } - - @FunctionalInterface - interface Product extends BehaviourCallback { - - R call(H holder, Behaviour.Product origin, A args); - } + R call(H holder, Behaviour origin, A args); } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java index 9d3739a..b797a08 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java @@ -25,7 +25,7 @@ default boolean supports(final BehaviourType type) { * @param type The type of the behaviour * @return The behaviour, if present */ - default Optional get(final BehaviourType type) { + default > Optional get(final BehaviourType type) { return BehaviourManager.get().get(this.unwrap(), type); } @@ -37,7 +37,7 @@ default Optional get(final BehaviourType type) { * @return The behaviour * @throws NoSuchElementException if the type is not present on this {@link BehaviourHolder} */ - default B require(final BehaviourType type) { + default > B require(final BehaviourType type) { return this.get(type).orElseThrow(() -> new NoSuchElementException(String.format( "No behaviour of type %s is present for holder %s", type, this.unwrap() diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java index 48b57e5..5e6efdb 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java @@ -14,13 +14,13 @@ static BehaviourManager get() { boolean supports(H holder, BehaviourType type); - Optional get(H holder, BehaviourType type); + > Optional get(H holder, BehaviourType type); BehaviourRegistration create(Class holder); interface BehaviourRegistration { - BehaviourRegistration register( + > BehaviourRegistration register( BehaviourType type, Function behaviourProvider ); } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java index 7d76bb0..1cda7b8 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java @@ -25,11 +25,7 @@ public interface ModifiableBehaviour { * @param type The behaviour type * @return The current behaviour callback for the given type, if present */ - Optional> getAction(BehaviourType> type); - - Optional> getProduct(BehaviourType> type); - - ModifiableBehaviour set(BehaviourType> type, BehaviourCallback.Action callback); + Optional> get(BehaviourType> type); /** * Sets the given behaviour callback for the given type.
@@ -41,20 +37,23 @@ public interface ModifiableBehaviour { * @param callback The behaviour callback * @return This modifiable behaviour, for chaining */ - ModifiableBehaviour set(BehaviourType> type, BehaviourCallback.Product callback); + ModifiableBehaviour set(BehaviourType> type, BehaviourCallback callback); - default
> ModifiableBehaviour set( - final BehaviourType> type, final Behaviour.Action behaviour + default ModifiableBehaviour set( + final BehaviourType> type, final Function behaviour ) { Objects.requireNonNull(behaviour, "behaviour"); - return this.set(type, (holder, origin, args) -> behaviour.call(args)); + return this.set(type, (holder, origin, args) -> behaviour.apply(args)); } - default ModifiableBehaviour set( - final BehaviourType> type, final Behaviour.Product behaviour + default ModifiableBehaviour set( + final BehaviourType> type, final Consumer behaviour ) { Objects.requireNonNull(behaviour, "behaviour"); - return this.set(type, (holder, origin, args) -> behaviour.call(args)); + return this.set(type, (holder, origin, args) -> { + behaviour.accept(args); + return null; + }); } /** @@ -67,7 +66,7 @@ default ModifiableBehaviour set( * @return This modifiable behaviour, for chaining */ default ModifiableBehaviour setValue( - final BehaviourType> type, final R value + final BehaviourType> type, final R value ) { Objects.requireNonNull(value, "value"); return this.set(type, (holder, origin, args) -> value); @@ -83,12 +82,19 @@ default ModifiableBehaviour setValue( * @return This modifiable behaviour, for chaining */ default ModifiableBehaviour setValue( - final BehaviourType> type, final Supplier valueSupplier + final BehaviourType> type, final Supplier valueSupplier ) { Objects.requireNonNull(valueSupplier, "valueSupplier"); return this.setValue(type, valueSupplier.get()); } + default > ModifiableBehaviour setBehaviour( + final BehaviourType type, final B behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + return this.set(type, (holder, origin, args) -> behaviour.call(args)); + } + /** * Wraps the given callback around the current callback.
* Means that the current callback becomes the "original" for the given one.
@@ -100,22 +106,12 @@ default ModifiableBehaviour setValue( * @param callback The behaviour callback * @return This modifiable behaviour, for chaining */ - default
ModifiableBehaviour append( - final BehaviourType> type, final BehaviourCallback.Action callback - ) { - Objects.requireNonNull(callback, "callback"); - return this.set(type, this.getAction(type) - .>map(old -> (holder, origin, args) -> - callback.call(holder, (newArgs) -> old.call(holder, origin, newArgs), args)) - .orElse(callback)); - } - default ModifiableBehaviour append( - final BehaviourType> type, final BehaviourCallback.Product callback + final BehaviourType> type, final BehaviourCallback callback ) { Objects.requireNonNull(callback, "callback"); - return this.set(type, this.getProduct(type) - .>map(old -> (holder, origin, args) -> + return this.set(type, this.get(type) + .>map(old -> (holder, origin, args) -> callback.call(holder, (newArgs) -> old.call(holder, origin, newArgs), args)) .orElse(callback)); } @@ -131,22 +127,12 @@ default ModifiableBehaviour append( * @param callback The behaviour callback * @return This modifiable behaviour, for chaining */ - default ModifiableBehaviour prepend( - final BehaviourType> type, final BehaviourCallback.Action callback - ) { - Objects.requireNonNull(callback, "callback"); - return this.set(type, this.getAction(type) - .>map(old -> (holder, origin, args) -> - old.call(holder, (newArgs) -> callback.call(holder, origin, newArgs), args)) - .orElse(callback)); - } - default ModifiableBehaviour prepend( - final BehaviourType> type, final BehaviourCallback.Product callback + final BehaviourType> type, final BehaviourCallback callback ) { Objects.requireNonNull(callback, "callback"); - return this.set(type, this.getProduct(type) - .>map(old -> (holder, origin, args) -> + return this.set(type, this.get(type) + .>map(old -> (holder, origin, args) -> old.call(holder, (newArgs) -> callback.call(holder, origin, newArgs), args)) .orElse(callback)); } From 6b95dea52e5b2eb9a2e27bb6b04d3b523265744e Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Tue, 29 Apr 2025 06:03:38 +0300 Subject: [PATCH 14/55] continue custom stuff --- .../custom/behaviour/BehaviourArgs.java | 21 +- .../custom/behaviour/BehaviourHolder.java | 233 ++++++++++++++++- .../behaviour/BehaviourHolderProxy.java | 7 + .../custom/behaviour/ModifiableBehaviour.java | 235 ------------------ .../behaviour/type/BlockStateBehaviour.java | 83 ++++++- .../behaviour/type/BlockStateBehaviours.java | 39 ++- .../{world => type}/WorldExtension.java | 2 +- .../custom/behaviour/util/HitResult.java | 133 ++++++++++ .../behaviour/util/InteractionResult.java | 94 +++++++ .../custom/behaviour/util/SignalBias.java | 23 ++ .../{world => util}/SignalOrientation.java | 2 +- .../custom/behaviour/util/SwingType.java | 25 ++ .../custom/behaviour/util/UseContext.java | 108 ++++++++ .../custom/behaviour/world/SignalBias.java | 23 -- .../custom/model/item/ItemModel.java | 2 +- .../model/item/RangeSelectProperty.java | 4 +- .../custom/model/item/SelectProperty.java | 2 +- .../custom/model/item/SpecialModel.java | 2 +- .../{item/enums => util}/ChargeType.java | 2 +- .../{item/enums => util}/CompassTarget.java | 2 +- .../model/{item/enums => util}/GuiLight.java | 2 +- .../model/{item/enums => util}/SkullType.java | 2 +- .../{item/enums => util}/TimeSource.java | 2 +- .../model/{item/enums => util}/WoodTypes.java | 2 +- .../RegisterBlockStateBehaviourEvent.java | 4 +- 25 files changed, 767 insertions(+), 287 deletions(-) delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java rename src/main/java/net/hellheim/spongetools/custom/behaviour/{world => type}/WorldExtension.java (96%) create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/util/HitResult.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalBias.java rename src/main/java/net/hellheim/spongetools/custom/behaviour/{world => util}/SignalOrientation.java (97%) create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/util/SwingType.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/util/UseContext.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalBias.java rename src/main/java/net/hellheim/spongetools/custom/model/{item/enums => util}/ChargeType.java (91%) rename src/main/java/net/hellheim/spongetools/custom/model/{item/enums => util}/CompassTarget.java (91%) rename src/main/java/net/hellheim/spongetools/custom/model/{item/enums => util}/GuiLight.java (90%) rename src/main/java/net/hellheim/spongetools/custom/model/{item/enums => util}/SkullType.java (92%) rename src/main/java/net/hellheim/spongetools/custom/model/{item/enums => util}/TimeSource.java (91%) rename src/main/java/net/hellheim/spongetools/custom/model/{item/enums => util}/WoodTypes.java (88%) diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java index 4d0dd2d..9257060 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java @@ -2,12 +2,15 @@ import java.util.Objects; +import org.spongepowered.api.entity.Entity; import org.spongepowered.api.util.Direction; import org.spongepowered.api.util.RandomProvider; import org.spongepowered.api.world.volume.Volume; import org.spongepowered.math.vector.Vector3d; import org.spongepowered.math.vector.Vector3i; +import net.hellheim.spongetools.custom.behaviour.util.HitResult; + public interface BehaviourArgs { interface Randomized> extends BehaviourArgs { @@ -17,7 +20,8 @@ interface Randomized> extends BehaviourArgs { A withRandom(RandomProvider.Source random); default A withRandom(final RandomProvider randomProvider) { - return this.withRandom(Objects.requireNonNull(randomProvider, "randomProvider").random()); + Objects.requireNonNull(randomProvider, "randomProvider"); + return this.withRandom(randomProvider.random()); } } @@ -35,6 +39,7 @@ interface Positional> extends BehaviourArgs { A withPosition(Vector3i position); default A withPosition(final Vector3d position) { + Objects.requireNonNull(position, "position"); return this.withPosition(position.toInt()); } @@ -53,4 +58,18 @@ interface Volumed> extends BehaviourAr A withVolume(V volume); } + + interface EntitySource> { + + E entity(); + + A withEntity(E entity); + } + + interface RayTraced> { + + H hit(); + + A withHit(H hit); + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java index b797a08..b64eea0 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java @@ -1,7 +1,14 @@ package net.hellheim.spongetools.custom.behaviour; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Optional; +import java.util.function.BinaryOperator; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.checkerframework.checker.nullness.qual.Nullable; /** * Represents something that can have {@link Behaviour}s. @@ -35,7 +42,7 @@ default boolean supports(final BehaviourType type) { * * @param type The type of the behaviour * @return The behaviour - * @throws NoSuchElementException if the type is not present on this {@link BehaviourHolder} + * @throws NoSuchElementException if the behaviour is not present on this {@link BehaviourHolder} */ default > B require(final BehaviourType type) { return this.get(type).orElseThrow(() -> new NoSuchElementException(String.format( @@ -51,4 +58,228 @@ private Object unwrap() { } return actualHolder; } + + /** + * + * @param The type of the actual behaviour holder + */ + interface Mutable> extends BehaviourHolder { + + /** + * Returns the current behaviour callback for the given type, if present. + * + * @param Behaviour return type + * @param Behaviour arguments + * @param type The behaviour type + * @return The current behaviour callback for the given type, if present + */ + Optional> callback(BehaviourType> type); + + /** + * Sets the given behaviour callback for the given type.
+ * Overrides any previously registered callbacks. + * + * @param Behaviour return type + * @param
Behaviour arguments + * @param type The behaviour type + * @param callback The behaviour callback + * @return This modifiable behaviour, for chaining + */ + M offer(BehaviourType> type, BehaviourCallback callback); + + default M offer( + final BehaviourType> type, final Function behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + return this.offer(type, (holder, origin, args) -> behaviour.apply(args)); + } + + default M offer( + final BehaviourType> type, final Consumer behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + return this.offer(type, (holder, origin, args) -> { + behaviour.accept(args); + return null; + }); + } + + /** + * Sets the given value as a result of the callback for the given type. + * + * @param Behaviour return type + * @param Behaviour arguments + * @param type The behaviour type + * @param value The value to return + * @return This modifiable behaviour, for chaining + */ + default M set( + final BehaviourType> type, final R value + ) { + Objects.requireNonNull(value, "value"); + return this.offer(type, (holder, origin, args) -> value); + } + + /** + * Sets the given value as a result of the callback for the given type. + * + * @param Behaviour return type + * @param Behaviour arguments + * @param type The behaviour type + * @param value The value to return + * @return This modifiable behaviour, for chaining + */ + default M set( + final BehaviourType> type, final Supplier valueSupplier + ) { + Objects.requireNonNull(valueSupplier, "valueSupplier"); + return this.set(type, valueSupplier.get()); + } + + default M transform( + final BehaviourType> type, + final Function<@Nullable BehaviourCallback, BehaviourCallback> function + ) { + Objects.requireNonNull(function, "function"); + return this.offer(type, function.apply(this.callback(type).orElse(null))); + } + + /** + * Wraps the given callback around the current callback.
+ * Means that the current callback becomes the "original" for the given one.
+ * If current callback is not present, simply sets the given callback. + * + * @param Behaviour return type + * @param
Behaviour arguments + * @param type The behaviour type + * @param callback The behaviour callback + * @return This modifiable behaviour, for chaining + */ + default M append( + final BehaviourType> type, final BehaviourCallback callback + ) { + Objects.requireNonNull(callback, "callback"); + return this.transform(type, old -> old == null + ? callback + : (holder, origin, args) -> + callback.call(holder, (newArgs) -> old.call(holder, origin, newArgs), args)); + } + + /** + * Wraps the current callback around the given callback.
+ * Means that the given callback becomes the "original" for the current one.
+ * If current callback is not present, simply sets the given callback. + * + * @param Behaviour return type + * @param
Behaviour arguments + * @param type The behaviour type + * @param callback The behaviour callback + * @return This modifiable behaviour, for chaining + */ + default M prepend( + final BehaviourType> type, final BehaviourCallback callback + ) { + Objects.requireNonNull(callback, "callback"); + return this.transform(type, old -> old == null + ? callback + : (holder, origin, args) -> + old.call(holder, (newArgs) -> callback.call(holder, origin, newArgs), args)); + } + + + + default M appendAfter( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.append(type, (holder, origin, args) -> { + final R result = origin.call(args); + action.accept(args); + return result; + }); + } + + default M appendAfter( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.append(type, (holder, origin, args) -> { + final R oldResult = origin.call(args); + final R newResult = behaviour.apply(args); + return resultMerger.apply(oldResult, newResult); + }); + } + + default M appendBefore( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.append(type, (holder, origin, args) -> { + action.accept(args); + final R result = origin.call(args); + return result; + }); + } + + default M appendBefore( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.append(type, (holder, origin, args) -> { + final R newResult = behaviour.apply(args); + final R oldResult = origin.call(args); + return resultMerger.apply(oldResult, newResult); + }); + } + + + + default M prependAfter( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.prepend(type, (holder, origin, args) -> { + final R result = origin.call(args); + action.accept(args); + return result; + }); + } + + default M prependAfter( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.prepend(type, (holder, origin, args) -> { + final R oldResult = origin.call(args); + final R newResult = behaviour.apply(args); + return resultMerger.apply(oldResult, newResult); + }); + } + + default M prependBefore( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.prepend(type, (holder, origin, args) -> { + action.accept(args); + final R result = origin.call(args); + return result; + }); + } + + default M prependBefore( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.prepend(type, (holder, origin, args) -> { + final R newResult = behaviour.apply(args); + final R oldResult = origin.call(args); + return resultMerger.apply(oldResult, newResult); + }); + } + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java index 571ea6b..5caa817 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java @@ -14,4 +14,11 @@ public interface BehaviourHolderProxy extends BehaviourHolder { * @return The owner of this extension */ H owner(); + + /** + * + * @param The type of the actual behaviour holder + */ + interface Mutable> extends BehaviourHolder.Mutable, BehaviourHolderProxy { + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java deleted file mode 100644 index 1cda7b8..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/ModifiableBehaviour.java +++ /dev/null @@ -1,235 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour; - -import java.util.Objects; -import java.util.Optional; -import java.util.function.BinaryOperator; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * - * @param Behaviour holder - */ -public interface ModifiableBehaviour { - - BehaviourManager manager(); - - H owner(); - - /** - * Returns the current behaviour callback for the given type, if present. - * - * @param Behaviour return type - * @param Behaviour arguments - * @param type The behaviour type - * @return The current behaviour callback for the given type, if present - */ - Optional> get(BehaviourType> type); - - /** - * Sets the given behaviour callback for the given type.
- * Overrides any previously registered callbacks. - * - * @param Behaviour return type - * @param
Behaviour arguments - * @param type The behaviour type - * @param callback The behaviour callback - * @return This modifiable behaviour, for chaining - */ - ModifiableBehaviour set(BehaviourType> type, BehaviourCallback callback); - - default ModifiableBehaviour set( - final BehaviourType> type, final Function behaviour - ) { - Objects.requireNonNull(behaviour, "behaviour"); - return this.set(type, (holder, origin, args) -> behaviour.apply(args)); - } - - default ModifiableBehaviour set( - final BehaviourType> type, final Consumer behaviour - ) { - Objects.requireNonNull(behaviour, "behaviour"); - return this.set(type, (holder, origin, args) -> { - behaviour.accept(args); - return null; - }); - } - - /** - * Sets the given value as a result of the callback for the given type. - * - * @param Behaviour return type - * @param Behaviour arguments - * @param type The behaviour type - * @param value The value to return - * @return This modifiable behaviour, for chaining - */ - default ModifiableBehaviour setValue( - final BehaviourType> type, final R value - ) { - Objects.requireNonNull(value, "value"); - return this.set(type, (holder, origin, args) -> value); - } - - /** - * Sets the given value as a result of the callback for the given type. - * - * @param Behaviour return type - * @param Behaviour arguments - * @param type The behaviour type - * @param value The value to return - * @return This modifiable behaviour, for chaining - */ - default ModifiableBehaviour setValue( - final BehaviourType> type, final Supplier valueSupplier - ) { - Objects.requireNonNull(valueSupplier, "valueSupplier"); - return this.setValue(type, valueSupplier.get()); - } - - default > ModifiableBehaviour setBehaviour( - final BehaviourType type, final B behaviour - ) { - Objects.requireNonNull(behaviour, "behaviour"); - return this.set(type, (holder, origin, args) -> behaviour.call(args)); - } - - /** - * Wraps the given callback around the current callback.
- * Means that the current callback becomes the "original" for the given one.
- * If current callback is not present, simply sets the given callback. - * - * @param Behaviour return type - * @param
Behaviour arguments - * @param type The behaviour type - * @param callback The behaviour callback - * @return This modifiable behaviour, for chaining - */ - default ModifiableBehaviour append( - final BehaviourType> type, final BehaviourCallback callback - ) { - Objects.requireNonNull(callback, "callback"); - return this.set(type, this.get(type) - .>map(old -> (holder, origin, args) -> - callback.call(holder, (newArgs) -> old.call(holder, origin, newArgs), args)) - .orElse(callback)); - } - - /** - * Wraps the current callback around the given callback.
- * Means that the given callback becomes the "original" for the current one.
- * If current callback is not present, simply sets the given callback. - * - * @param Behaviour return type - * @param
Behaviour arguments - * @param type The behaviour type - * @param callback The behaviour callback - * @return This modifiable behaviour, for chaining - */ - default ModifiableBehaviour prepend( - final BehaviourType> type, final BehaviourCallback callback - ) { - Objects.requireNonNull(callback, "callback"); - return this.set(type, this.get(type) - .>map(old -> (holder, origin, args) -> - old.call(holder, (newArgs) -> callback.call(holder, origin, newArgs), args)) - .orElse(callback)); - } - - - - default ModifiableBehaviour appendAfter( - final BehaviourType> type, final Consumer action - ) { - Objects.requireNonNull(action, "action"); - return this.append(type, (holder, origin, args) -> { - final R result = origin.call(args); - action.accept(args); - return result; - }); - } - - default ModifiableBehaviour appendAfter( - final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger - ) { - Objects.requireNonNull(behaviour, "behaviour"); - Objects.requireNonNull(resultMerger, "resultMerger"); - return this.append(type, (holder, origin, args) -> { - final R oldResult = origin.call(args); - final R newResult = behaviour.apply(args); - return resultMerger.apply(oldResult, newResult); - }); - } - - default ModifiableBehaviour appendBefore( - final BehaviourType> type, final Consumer action - ) { - Objects.requireNonNull(action, "action"); - return this.append(type, (holder, origin, args) -> { - action.accept(args); - final R result = origin.call(args); - return result; - }); - } - - default ModifiableBehaviour appendBefore( - final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger - ) { - Objects.requireNonNull(behaviour, "behaviour"); - Objects.requireNonNull(resultMerger, "resultMerger"); - return this.append(type, (holder, origin, args) -> { - final R newResult = behaviour.apply(args); - final R oldResult = origin.call(args); - return resultMerger.apply(oldResult, newResult); - }); - } - - - - default ModifiableBehaviour prependAfter( - final BehaviourType> type, final Consumer action - ) { - Objects.requireNonNull(action, "action"); - return this.prepend(type, (holder, origin, args) -> { - final R result = origin.call(args); - action.accept(args); - return result; - }); - } - - default ModifiableBehaviour prependAfter( - final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger - ) { - Objects.requireNonNull(behaviour, "behaviour"); - Objects.requireNonNull(resultMerger, "resultMerger"); - return this.prepend(type, (holder, origin, args) -> { - final R oldResult = origin.call(args); - final R newResult = behaviour.apply(args); - return resultMerger.apply(oldResult, newResult); - }); - } - - default ModifiableBehaviour prependBefore( - final BehaviourType> type, final Consumer action - ) { - Objects.requireNonNull(action, "action"); - return this.prepend(type, (holder, origin, args) -> { - action.accept(args); - final R result = origin.call(args); - return result; - }); - } - - default ModifiableBehaviour prependBefore( - final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger - ) { - Objects.requireNonNull(behaviour, "behaviour"); - Objects.requireNonNull(resultMerger, "resultMerger"); - return this.prepend(type, (holder, origin, args) -> { - final R newResult = behaviour.apply(args); - final R oldResult = origin.call(args); - return resultMerger.apply(oldResult, newResult); - }); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java index 11345d8..36996df 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java @@ -6,8 +6,12 @@ import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.data.type.HandType; import org.spongepowered.api.data.type.PushReaction; import org.spongepowered.api.entity.EntityType; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.map.color.MapColorType; import org.spongepowered.api.util.Direction; import org.spongepowered.api.util.RandomProvider; @@ -20,10 +24,14 @@ import net.hellheim.spongetools.custom.behaviour.Behaviour; import net.hellheim.spongetools.custom.behaviour.BehaviourArgs; -import net.hellheim.spongetools.custom.behaviour.world.SignalOrientation; +import net.hellheim.spongetools.custom.behaviour.util.HitResult; +import net.hellheim.spongetools.custom.behaviour.util.InteractionResult; +import net.hellheim.spongetools.custom.behaviour.util.SignalOrientation; +@FunctionalInterface public interface BlockStateBehaviour extends Behaviour { + @FunctionalInterface interface SpawnValidator extends BlockStateBehaviour { @Override @@ -43,6 +51,7 @@ interface Args extends } } + @FunctionalInterface interface MapColor extends BlockStateBehaviour { @Override @@ -58,6 +67,7 @@ interface Args extends } } + @FunctionalInterface interface PistonPushReaction extends BlockStateBehaviour { @Override @@ -68,6 +78,7 @@ default PushReaction call(final BehaviourArgs args) { PushReaction call(); } + @FunctionalInterface interface SignalConductor extends BlockStateBehaviour { @Override @@ -83,6 +94,7 @@ interface Args extends } } + @FunctionalInterface interface SignalPower extends BlockStateBehaviour { @Override @@ -99,6 +111,7 @@ interface Args extends } } + @FunctionalInterface interface AnalogSignalPower extends BlockStateBehaviour { @Override @@ -114,6 +127,7 @@ interface Args extends } } + @FunctionalInterface interface Tick extends BlockStateBehaviour { @Override @@ -131,6 +145,7 @@ interface Args extends } } + @FunctionalInterface interface Replace extends BlockStateBehaviour { @Override @@ -155,6 +170,7 @@ interface Args extends } } + @FunctionalInterface interface ShapeUpdate extends BlockStateBehaviour { @Override @@ -188,6 +204,7 @@ interface Args extends } } + @FunctionalInterface interface SignalUpdate extends BlockStateBehaviour { @Override @@ -230,4 +247,68 @@ default Args withoutOrientation() { Args withMovedByPiston(boolean movedByPiston); } } + + @FunctionalInterface + interface UseWithItem extends BlockStateBehaviour { + + @Override + default InteractionResult call(final Args args) { + return this.call(args.item(), args.volume(), args.entity(), args.hand(), args.hit()); + } + + InteractionResult call(ItemStackLike item, World volume, Player entity, HandType hand, HitResult.BlockHitResult hit); + + interface Args extends + BehaviourArgs.Volumed, Args>, + BehaviourArgs.EntitySource, + BehaviourArgs.RayTraced { + + HandType hand(); + + ItemStack item(); + + Args withHand(HandType hand); + + default Args withHand(Supplier handSupplier) { + return this.withHand(Objects.requireNonNull(handSupplier, "handSupplier").get()); + } + + Args withItem(ItemStackLike item); + } + } + + @FunctionalInterface + interface UseWithoutItem extends BlockStateBehaviour { + + @Override + default InteractionResult call(final Args args) { + return this.call(args.volume(), args.entity(), args.hit()); + } + + InteractionResult call(World volume, Player entity, HitResult.BlockHitResult hit); + + interface Args extends + BehaviourArgs.Volumed, Args>, + BehaviourArgs.EntitySource, + BehaviourArgs.RayTraced { + } + } + + @FunctionalInterface + interface Attack extends BlockStateBehaviour { + + @Override + default Void call(final Args args) { + this.call(args.volume(), args.position(), args.entity()); + return null; + } + + void call(World volume, Vector3i position, Player entity); + + interface Args extends + BehaviourArgs.Volumed, Args>, + BehaviourArgs.Positional, + BehaviourArgs.EntitySource { + } + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java index 3f69fe7..f8c5e2d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java @@ -1,11 +1,24 @@ package net.hellheim.spongetools.custom.behaviour.type; import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockType; import org.spongepowered.api.block.BlockTypes; import org.spongepowered.api.world.volume.game.UpdatableVolume; import net.hellheim.spongetools.custom.behaviour.BehaviourType; -import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.*; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.AnalogSignalPower; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.Attack; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.MapColor; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.PistonPushReaction; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.Replace; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.ShapeUpdate; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.SignalConductor; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.SignalPower; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.SignalUpdate; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.SpawnValidator; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.Tick; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.UseWithItem; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.UseWithoutItem; public final class BlockStateBehaviours { @@ -23,18 +36,18 @@ public final class BlockStateBehaviours { /** * Signal that will power neighbour blocks. */ - public static final BehaviourType SIGNAL_POWER = BehaviourType.create(); + public static final BehaviourType WEAK_SIGNAL_POWER = BehaviourType.create(); /** * Signal that will go through neighbour blocks.
* * In vanilla this behaviour usually filters result of - * {@link BlockStateExtension#origin(BlockBehaviourType)} - * for {@link #SIGNAL_POWER} behaviour by side.
+ * {@link BlockStateExtension#get(BehaviourType)} + * for {@link #WEAK_SIGNAL_POWER} behaviour by side.
* * Used by {@link BlockTypes#REPEATER} (horizontally) and other redstone-related blocks (upwards). */ - public static final BehaviourType DIRECT_SIGNAL_POWER = BehaviourType.create(); + public static final BehaviourType STRONG_SIGNAL_POWER = BehaviourType.create(); /** * Result of this behaviour is usually used by {@link BlockTypes#COMPARATOR}. @@ -62,22 +75,26 @@ public final class BlockStateBehaviours { /** * Called when neighbour {@link BlockState}s are changed.
+ * * This is usually used to update properties that could be * considered as "shape" depending on neighbour blocks and * by waterlogged blocks to schedule liquid ticks. - * - * @see #SIGNAL_UPDATE */ public static final BehaviourType SHAPE_UPDATE = BehaviourType.create(); /** - * Called when neighbour {@link BlockState}s are changed (mostly due to signal changes).
- * This is usually used to update properties that rely on redstone signal - * - * @see #SHAPE_UPDATE + * Called when {@link BlockState} is updated through + * {@link WorldExtension#updateAt(int, int, int, BlockType)} (mostly by signal-related blocks).
+ * This is usually used to update properties that rely on redstone signal. */ public static final BehaviourType SIGNAL_UPDATE = BehaviourType.create(); + public static final BehaviourType USE_WITH_ITEM = BehaviourType.create(); + + public static final BehaviourType USE_WITHOUT_ITEM = BehaviourType.create(); + + public static final BehaviourType ATTACK = BehaviourType.create(); + private BlockStateBehaviours() { } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/world/WorldExtension.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/WorldExtension.java similarity index 96% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/world/WorldExtension.java rename to src/main/java/net/hellheim/spongetools/custom/behaviour/type/WorldExtension.java index f890839..e25cd45 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/world/WorldExtension.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/WorldExtension.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.behaviour.world; +package net.hellheim.spongetools.custom.behaviour.type; import java.util.Objects; diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/HitResult.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/HitResult.java new file mode 100644 index 0000000..f73a731 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/HitResult.java @@ -0,0 +1,133 @@ +package net.hellheim.spongetools.custom.behaviour.util; + +import java.util.Objects; + +import org.spongepowered.api.Sponge; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.util.CopyableBuilder; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.util.blockray.RayTraceResult; +import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.math.vector.Vector3i; + +/** + * Similar to {@link RayTraceResult} but reflects + * vanilla stuff because they can't be mapped 1 to 1. + */ +public interface HitResult { + + static EntityHitResult entity(final RayTraceResult rayTrace) { + return HitResult.entity(rayTrace.selectedObject(), rayTrace.hitPosition()); + } + + static EntityHitResult entity(final Entity entity) { + return HitResult.entity(entity, entity.position()); + } + + static EntityHitResult entity(final Entity entity, final Vector3d hitPosition) { + Objects.requireNonNull(hitPosition, "hitPosition"); + return HitResult.entity(entity, hitPosition.x(), hitPosition.y(), hitPosition.z()); + } + + static EntityHitResult entity(final Entity entity, final double hitX, final double hitY, final double hitZ) { + return Sponge.game().factoryProvider().provide(Factory.class).entity(entity, hitX, hitY, hitZ); + } + + static BlockHitResult.Builder block() { + return Sponge.game().builderProvider().provide(BlockHitResult.Builder.class); + } + + /** + * Returns the position the ray ended at. + * + * @return The position the ray ended at + */ + Vector3d hitPosition(); + + /** + * Returns whether this hit result is considered as missed.
+ * + * Usually this returns true if this result is {@link BlockHitResult} and + * its {@link BlockHitResult.Builder#miss(boolean)} flag is set to true. + * + * @return True if this hit result is considered as missed + */ + boolean miss(); + + interface EntityHitResult extends HitResult { + + /** + * Returns the entity hit by the ray. + * + * @return The entity hit by the ray + */ + Entity entity(); + } + + interface BlockHitResult extends HitResult { + + /** + * Returns the block position hit by the ray. + * + * @return The block position hit by the ray + */ + Vector3i blockPosition(); + + /** + * Returns the direction the ray hit the block from. + * + * @return The direction the ray hit the block from + */ + Direction direction(); + + /** + * Returns whether the ray ended inside the block it hit. + * + * @return True if the ray ended inside the block it hit + */ + boolean inside(); + + /** + * Returns whether the ray hit the world border. + * + * @return True if the ray hit the world border + */ + boolean worldBorder(); + + default Builder toBuilder() { + return HitResult.block().from(this); + } + + interface Builder extends + org.spongepowered.api.util.Builder, + CopyableBuilder { + + Builder hitPosition(double x, double y, double z); + + default Builder hitPosition(final Vector3d position) { + Objects.requireNonNull(position, "position"); + return this.hitPosition(position.x(), position.y(), position.z()); + } + + Builder blockPosition(int x, int y, int z); + + default Builder blockPosition(final Vector3i position) { + Objects.requireNonNull(position, "position"); + return this.blockPosition(position.x(), position.y(), position.z()); + } + + Builder direction(Direction direction); + + Builder miss(boolean miss); + + Builder inside(boolean inside); + + Builder worldBorder(boolean worldBorder); + } + } + + interface Factory { + + EntityHitResult entity(Entity entity, double hitX, double hitY, double hitZ); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java new file mode 100644 index 0000000..94b29cc --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java @@ -0,0 +1,94 @@ +package net.hellheim.spongetools.custom.behaviour.util; + +import java.util.Optional; + +import org.spongepowered.api.Sponge; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; + +public interface InteractionResult { + + InteractionResult.Success SUCCESS_CLIENT = InteractionResult.factory().successClient(); + + InteractionResult.Success SUCCESS_SERVER = InteractionResult.factory().successServer(); + + InteractionResult.Success CONSUME = InteractionResult.factory().consume(); + + InteractionResult FAIL = InteractionResult.factory().fail(); + + InteractionResult PASS = InteractionResult.factory().pass(); + + InteractionResult TRY_EMPTY_HAND = InteractionResult.factory().tryEmptyHand(); + + static InteractionResult.Success success(final SwingType swing, final boolean isInteraction) { + return InteractionResult.success(swing, isInteraction, Optional.empty()); + } + + static InteractionResult.Success success(final SwingType swing, final boolean isInteraction, final ItemStackLike result) { + return InteractionResult.success(swing, isInteraction, Optional.of(result.asMutableCopy())); + } + + static InteractionResult.Success success( + final SwingType swing, final boolean isInteraction, final Optional result + ) { + return InteractionResult.factory().success(swing, isInteraction, result); + } + + private static Factory factory() { + return Sponge.game().factoryProvider().provide(Factory.class); + } + + interface Success extends InteractionResult { + + SwingType swing(); + + boolean isInteraction(); + + Optional result(); + + default Success withSwing(final SwingType swing) { + return this.swing() == swing + ? this + : InteractionResult.success(swing, this.isInteraction(), this.result()); + } + + default Success withInteraction(final boolean isInteraction) { + return this.isInteraction() == isInteraction + ? this + : InteractionResult.success(this.swing(), isInteraction, this.result()); + } + + default Success withoutResult() { + return this.result().isEmpty() + ? this + : InteractionResult.success(this.swing(), this.isInteraction(), Optional.empty()); + } + + default Success withResult(final ItemStackLike result) { + return InteractionResult.success(null, isInteraction(), Optional.of(result.asMutableCopy())); + } + + default Success withResult(final Optional result) { + return result.isEmpty() + ? this.withoutResult() + : InteractionResult.success(this.swing(), this.isInteraction(), result); + } + } + + interface Factory { + + InteractionResult.Success successClient(); + + InteractionResult.Success successServer(); + + InteractionResult.Success consume(); + + InteractionResult fail(); + + InteractionResult pass(); + + InteractionResult tryEmptyHand(); + + InteractionResult.Success success(SwingType swing, boolean isInteraction, Optional result); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalBias.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalBias.java new file mode 100644 index 0000000..3709aaf --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalBias.java @@ -0,0 +1,23 @@ +package net.hellheim.spongetools.custom.behaviour.util; + +import org.spongepowered.api.Sponge; + +public interface SignalBias { + + SignalBias LEFT = SignalBias.factory().left(); + + SignalBias RIGHT = SignalBias.factory().right(); + + private static Factory factory() { + return Sponge.game().factoryProvider().provide(Factory.class); + } + + SignalBias opposite(); + + interface Factory { + + SignalBias left(); + + SignalBias right(); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalOrientation.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalOrientation.java similarity index 97% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalOrientation.java rename to src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalOrientation.java index 66daa04..b9b0ef5 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalOrientation.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalOrientation.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.behaviour.world; +package net.hellheim.spongetools.custom.behaviour.util; import java.util.Optional; import java.util.stream.Stream; diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SwingType.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SwingType.java new file mode 100644 index 0000000..d2d3d58 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SwingType.java @@ -0,0 +1,25 @@ +package net.hellheim.spongetools.custom.behaviour.util; + +import org.spongepowered.api.Sponge; + +public interface SwingType { + + SwingType NONE = SwingType.factory().none(); + + SwingType SERVER = SwingType.factory().server(); + + SwingType CLIENT = SwingType.factory().client(); + + private static Factory factory() { + return Sponge.game().factoryProvider().provide(Factory.class); + } + + interface Factory { + + SwingType none(); + + SwingType server(); + + SwingType client(); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/UseContext.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/UseContext.java new file mode 100644 index 0000000..fb060f6 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/UseContext.java @@ -0,0 +1,108 @@ +package net.hellheim.spongetools.custom.behaviour.util; + +import java.util.List; +import java.util.Optional; + +import org.spongepowered.api.data.type.HandType; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.world.World; +import org.spongepowered.math.vector.Vector3i; + +/** + * Represents the context of the item usage. + */ +public interface UseContext { + + /** + * Returns the player that used item, if present. + * + * @return The player that used item, if present + */ + Optional player(); + + /** + * Returns the used hand. + * + * @return The used hand + */ + HandType hand(); + + /** + * Returns the hit result of the usage. + * + * @return The hit result of the usage + */ + HitResult.BlockHitResult hit(); + + /** + * Returns the world the item is used in. + * + * @return The world the item is used in + */ + World world(); + + /** + * Returns the used item. This item can be mutated. + * + * @return The used item + */ + ItemStack item(); + + /** + * Returns the position that is considered as true clicked position.
+ * This may differ from the position of the {@link #hit()}. + * + * @return The true clicked block position + */ + Vector3i clickedPosition(); + + /** + * Returns the direction that is considered as true clicked direction.
+ * This may differ from the direction of the {@link #hit()}. + * + * @return The true clicked direction + */ + Direction clickedDirection(); + + /** + * Returns the yaw rotation of the usage.
+ * This may differ from the yaw of the {@link #player()}. + * + * @return The true yaw of the usage + */ + double rotation(); + + /** + * Returns the horizontal direction of the usage. + * + * @return The horizontal direction of the usage + */ + Direction horizontalDirection(); + + /** + * Returns whether the usage has active secondary use. + * + * @return True if the usage has active secondary use + */ + boolean isSecondary(); + + interface BlockPlace extends UseContext { + + boolean canPlace(); + + boolean canReplaceClickedPosition(); + + Direction nearestDirection(); + + Direction nearestVerticalDirection(); + + List nearestDirections(); + } + + interface DirectionaBlockPlace extends BlockPlace { + + Direction baseDirection(); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalBias.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalBias.java deleted file mode 100644 index b1a0e51..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/world/SignalBias.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.hellheim.spongetools.custom.behaviour.world; - -import org.spongepowered.api.Sponge; - -public interface SignalBias { - - static SignalBias left() { - return Sponge.game().factoryProvider().provide(Factory.class).left(); - } - - static SignalBias right() { - return Sponge.game().factoryProvider().provide(Factory.class).right(); - } - - SignalBias opposite(); - - interface Factory { - - SignalBias left(); - - SignalBias right(); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java index 0fa4e1a..424f269 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java @@ -15,7 +15,7 @@ import net.hellheim.spongetools.custom.model.ModelTemplate; import net.hellheim.spongetools.custom.model.TexturedModel; import net.hellheim.spongetools.custom.model.Textures; -import net.hellheim.spongetools.custom.model.item.enums.GuiLight; +import net.hellheim.spongetools.custom.model.util.GuiLight; public record ItemModel(TexturedModel model, ItemTransforms display, GuiLight guiLight) { diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java b/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java index 1f4ac1d..4a83a16 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java @@ -13,8 +13,8 @@ import net.hellheim.spongetools.codec.LateBoundIdMapper; import net.hellheim.spongetools.codec.list.ExtraCodecs; import net.hellheim.spongetools.codec.list.SpongeCodecs; -import net.hellheim.spongetools.custom.model.item.enums.CompassTarget; -import net.hellheim.spongetools.custom.model.item.enums.TimeSource; +import net.hellheim.spongetools.custom.model.util.CompassTarget; +import net.hellheim.spongetools.custom.model.util.TimeSource; import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; public interface RangeSelectProperty extends MapCodecProxy { diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java index e226084..3bb93dd 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java @@ -30,7 +30,7 @@ import net.hellheim.spongetools.codec.list.RegistryCodecs; import net.hellheim.spongetools.codec.list.SpongeCodecs; import net.hellheim.spongetools.codec.list.StringRepresentableCodecs; -import net.hellheim.spongetools.custom.model.item.enums.ChargeType; +import net.hellheim.spongetools.custom.model.util.ChargeType; import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; public interface SelectProperty extends MapCodecProxy> { diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java b/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java index 41c2b57..caf5af5 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java @@ -16,7 +16,7 @@ import net.hellheim.spongetools.codec.LateBoundIdMapper; import net.hellheim.spongetools.codec.list.SpongeCodecs; import net.hellheim.spongetools.codec.list.StringRepresentableCodecs; -import net.hellheim.spongetools.custom.model.item.enums.SkullType; +import net.hellheim.spongetools.custom.model.util.SkullType; import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; public interface SpecialModel extends MapCodecProxy { diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/ChargeType.java b/src/main/java/net/hellheim/spongetools/custom/model/util/ChargeType.java similarity index 91% rename from src/main/java/net/hellheim/spongetools/custom/model/item/enums/ChargeType.java rename to src/main/java/net/hellheim/spongetools/custom/model/util/ChargeType.java index 4d2b287..45dee53 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/ChargeType.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/util/ChargeType.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item.enums; +package net.hellheim.spongetools.custom.model.util; import org.spongepowered.api.data.type.StringRepresentable; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/CompassTarget.java b/src/main/java/net/hellheim/spongetools/custom/model/util/CompassTarget.java similarity index 91% rename from src/main/java/net/hellheim/spongetools/custom/model/item/enums/CompassTarget.java rename to src/main/java/net/hellheim/spongetools/custom/model/util/CompassTarget.java index b70267c..09c0972 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/CompassTarget.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/util/CompassTarget.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item.enums; +package net.hellheim.spongetools.custom.model.util; import org.spongepowered.api.data.type.StringRepresentable; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/GuiLight.java b/src/main/java/net/hellheim/spongetools/custom/model/util/GuiLight.java similarity index 90% rename from src/main/java/net/hellheim/spongetools/custom/model/item/enums/GuiLight.java rename to src/main/java/net/hellheim/spongetools/custom/model/util/GuiLight.java index 31527ec..2698cac 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/GuiLight.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/util/GuiLight.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item.enums; +package net.hellheim.spongetools.custom.model.util; import org.spongepowered.api.data.type.StringRepresentable; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/SkullType.java b/src/main/java/net/hellheim/spongetools/custom/model/util/SkullType.java similarity index 92% rename from src/main/java/net/hellheim/spongetools/custom/model/item/enums/SkullType.java rename to src/main/java/net/hellheim/spongetools/custom/model/util/SkullType.java index cb0036e..728a9b6 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/SkullType.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/util/SkullType.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item.enums; +package net.hellheim.spongetools.custom.model.util; import org.spongepowered.api.data.type.StringRepresentable; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/TimeSource.java b/src/main/java/net/hellheim/spongetools/custom/model/util/TimeSource.java similarity index 91% rename from src/main/java/net/hellheim/spongetools/custom/model/item/enums/TimeSource.java rename to src/main/java/net/hellheim/spongetools/custom/model/util/TimeSource.java index 00e8efe..2c643b6 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/TimeSource.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/util/TimeSource.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item.enums; +package net.hellheim.spongetools.custom.model.util; import org.spongepowered.api.data.type.StringRepresentable; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/WoodTypes.java b/src/main/java/net/hellheim/spongetools/custom/model/util/WoodTypes.java similarity index 88% rename from src/main/java/net/hellheim/spongetools/custom/model/item/enums/WoodTypes.java rename to src/main/java/net/hellheim/spongetools/custom/model/util/WoodTypes.java index 15eda33..a24ec4c 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/enums/WoodTypes.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/util/WoodTypes.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item.enums; +package net.hellheim.spongetools.custom.model.util; public final class WoodTypes { diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java index c3849c8..98e7e17 100644 --- a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java +++ b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java @@ -10,7 +10,7 @@ import com.google.common.collect.Streams; -import net.hellheim.spongetools.custom.behaviour.ModifiableBehaviour; +import net.hellheim.spongetools.custom.behaviour.BehaviourHolderProxy; import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; public interface RegisterBlockStateBehaviourEvent extends LifecycleEvent { @@ -81,6 +81,6 @@ default Stream allStates(final Iterable type } - interface BehaviourStep extends ModifiableBehaviour { + interface BehaviourStep extends BehaviourHolderProxy.Mutable { } } From 381399950a134d425499dbc8d432a158c4026ec8 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sun, 4 May 2025 06:00:41 +0300 Subject: [PATCH 15/55] continue custom stuff --- .../custom/behaviour/Behaviour.java | 103 +++++++ .../custom/behaviour/BehaviourArgs.java | 17 +- .../behaviour/BehaviourCallbackHolder.java | 250 +++++++++++++++++ .../BehaviourCallbackHolderLogic.java | 133 +++++++++ .../BehaviourCallbackHolderProxy.java | 48 ++++ .../custom/behaviour/BehaviourHolder.java | 253 +----------------- .../behaviour/BehaviourHolderProxy.java | 38 +-- .../custom/behaviour/BehaviourManager.java | 8 + .../behaviour/TypedBehaviourCallback.java | 20 ++ .../behaviour/tag/TaggableInstance.java | 29 ++ .../behaviour/type/BlockStateBehaviour.java | 184 +++++++------ .../behaviour/type/BlockStateBehaviours.java | 121 +++++++-- .../behaviour/type/BlockStateExtension.java | 32 ++- .../custom/block/BasicCustomBlockType.java | 48 ++++ .../custom/block/BlockStateProvider.java | 60 +++-- .../custom/block/BlockStateRegistrar.java | 2 +- .../custom/block/CustomBlockType.java | 6 +- .../custom/block/CustomBlockTypeBuilder.java | 39 +++ .../block/CustomBlockTypeProperties.java | 17 ++ .../block/DefaultedCustomBlockType.java | 26 -- .../custom/model/TexturedModel.java | 3 +- .../RegisterBlockStateBehaviourEvent.java | 6 +- 22 files changed, 1024 insertions(+), 419 deletions(-) create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderLogic.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderProxy.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/TypedBehaviourCallback.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/block/BasicCustomBlockType.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeBuilder.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeProperties.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java index 277f02d..a3fcf50 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java @@ -1,5 +1,11 @@ package net.hellheim.spongetools.custom.behaviour; +import java.util.function.BooleanSupplier; +import java.util.function.DoubleSupplier; +import java.util.function.IntSupplier; +import java.util.function.LongSupplier; +import java.util.function.Supplier; + /** * Represents some action a {@link BehaviourHolder} can do. * @@ -10,4 +16,101 @@ public interface Behaviour { R call(A args); + + @FunctionalInterface + interface SimpleAction extends Behaviour, Runnable { + + @Override + default Void call(BehaviourArgs args) { + this.call(); + return null; + } + + @Override + default void run() { + this.call(); + } + + void call(); + } + + @FunctionalInterface + interface SimpleBoolean extends Behaviour, BooleanSupplier { + + @Override + default Boolean call(final BehaviourArgs args) { + return this.call(); + } + + @Override + default boolean getAsBoolean() { + return this.call(); + } + + boolean call(); + } + + @FunctionalInterface + interface SimpleInteger extends Behaviour, IntSupplier { + + @Override + default Integer call(final BehaviourArgs args) { + return this.call(); + } + + @Override + default int getAsInt() { + return this.call(); + }; + + int call(); + } + + @FunctionalInterface + interface SimpleLong extends Behaviour, LongSupplier { + + @Override + default Long call(final BehaviourArgs args) { + return this.call(); + } + + @Override + default long getAsLong() { + return this.call(); + }; + + long call(); + } + + @FunctionalInterface + interface SimpleDouble extends Behaviour, DoubleSupplier { + + @Override + default Double call(final BehaviourArgs args) { + return this.call(); + } + + @Override + default double getAsDouble() { + return this.call(); + } + + double call(); + } + + @FunctionalInterface + interface SimpleObject extends Behaviour, Supplier { + + @Override + default V call(final BehaviourArgs args) { + return this.call(); + } + + @Override + default V get() { + return this.call(); + } + + V call(); + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java index 9257060..8c83fe0 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java @@ -1,8 +1,8 @@ package net.hellheim.spongetools.custom.behaviour; import java.util.Objects; +import java.util.function.Supplier; -import org.spongepowered.api.entity.Entity; import org.spongepowered.api.util.Direction; import org.spongepowered.api.util.RandomProvider; import org.spongepowered.api.world.volume.Volume; @@ -59,17 +59,28 @@ interface Volumed> extends BehaviourAr A withVolume(V volume); } - interface EntitySource> { + interface EntitySource> extends BehaviourArgs { E entity(); A withEntity(E entity); + + default A withEntity(final Supplier entitySupplier) { + return this.withEntity(Objects.requireNonNull(entitySupplier, "entitySupplier").get()); + } } - interface RayTraced> { + interface RayTraced> extends BehaviourArgs { H hit(); A withHit(H hit); } + + interface Contextual> extends BehaviourArgs { + + C context(); + + A withContext(C context); + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java new file mode 100644 index 0000000..0861280 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java @@ -0,0 +1,250 @@ +package net.hellheim.spongetools.custom.behaviour; + +import java.util.Collection; +import java.util.Objects; +import java.util.Optional; +import java.util.function.BinaryOperator; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.checkerframework.checker.nullness.qual.Nullable; + +public interface BehaviourCallbackHolder { + + Collection> callbacks(); + + /** + * Returns the current behaviour callback for the given type, if present. + * + * @param Behaviour return type + * @param
Behaviour arguments + * @param type The behaviour type + * @return The current behaviour callback for the given type, if present + */ + Optional> callback(BehaviourType> type); + + @Nullable BehaviourCallback callbackOrNull(BehaviourType> type); + + interface Mutable> extends BehaviourCallbackHolder { + + /** + * Sets the given behaviour callback for the given type.
+ * Overrides any previously registered callbacks. + * + * @param Behaviour return type + * @param
Behaviour arguments + * @param type The behaviour type + * @param callback The behaviour callback + * @return This modifiable behaviour, for chaining + */ + M offer(BehaviourType> type, BehaviourCallback callback); + + default M offer( + final BehaviourType> type, final Function behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + return this.offer(type, (holder, origin, args) -> behaviour.apply(args)); + } + + default M offer( + final BehaviourType> type, final Consumer behaviour + ) { + Objects.requireNonNull(behaviour, "behaviour"); + return this.offer(type, (holder, origin, args) -> { + behaviour.accept(args); + return null; + }); + } + + default M offer(final TypedBehaviourCallback callback) { + Objects.requireNonNull(callback, "callback"); + return this.offer(callback.type(), callback.callback()); + } + + default M offerAll(final BehaviourCallbackHolder holder) { + Objects.requireNonNull(holder, "holder").callbacks().forEach(this::offer); + @SuppressWarnings("unchecked") + final M $this = (M) this; + return $this; + } + + /** + * Sets the given value as a result of the callback for the given type. + * + * @param Behaviour return type + * @param Behaviour arguments + * @param type The behaviour type + * @param value The value to return + * @return This modifiable behaviour, for chaining + */ + default M set( + final BehaviourType> type, final R value + ) { + Objects.requireNonNull(value, "value"); + return this.offer(type, (holder, origin, args) -> value); + } + + /** + * Sets the given value as a result of the callback for the given type. + * + * @param Behaviour return type + * @param Behaviour arguments + * @param type The behaviour type + * @param value The value to return + * @return This modifiable behaviour, for chaining + */ + default M set( + final BehaviourType> type, final Supplier valueSupplier + ) { + Objects.requireNonNull(valueSupplier, "valueSupplier"); + return this.set(type, valueSupplier.get()); + } + + default M transform( + final BehaviourType> type, + final Function<@Nullable BehaviourCallback, BehaviourCallback> function + ) { + Objects.requireNonNull(function, "function"); + return this.offer(type, function.apply(this.callback(type).orElse(null))); + } + + /** + * Wraps the given callback around the current callback.
+ * Means that the current callback becomes the "original" for the given one.
+ * If current callback is not present, simply sets the given callback. + * + * @param Behaviour return type + * @param
Behaviour arguments + * @param type The behaviour type + * @param callback The behaviour callback + * @return This modifiable behaviour, for chaining + */ + default M append( + final BehaviourType> type, final BehaviourCallback callback + ) { + Objects.requireNonNull(callback, "callback"); + return this.transform(type, old -> old == null + ? callback + : (holder, origin, args) -> + callback.call(holder, (newArgs) -> old.call(holder, origin, newArgs), args)); + } + + /** + * Wraps the current callback around the given callback.
+ * Means that the given callback becomes the "original" for the current one.
+ * If current callback is not present, simply sets the given callback. + * + * @param Behaviour return type + * @param
Behaviour arguments + * @param type The behaviour type + * @param callback The behaviour callback + * @return This modifiable behaviour, for chaining + */ + default M prepend( + final BehaviourType> type, final BehaviourCallback callback + ) { + Objects.requireNonNull(callback, "callback"); + return this.transform(type, old -> old == null + ? callback + : (holder, origin, args) -> + old.call(holder, (newArgs) -> callback.call(holder, origin, newArgs), args)); + } + + + + default M appendAfter( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.append(type, (holder, origin, args) -> { + final R result = origin.call(args); + action.accept(args); + return result; + }); + } + + default M appendAfter( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.append(type, (holder, origin, args) -> { + final R oldResult = origin.call(args); + final R newResult = behaviour.apply(args); + return resultMerger.apply(oldResult, newResult); + }); + } + + default M appendBefore( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.append(type, (holder, origin, args) -> { + action.accept(args); + final R result = origin.call(args); + return result; + }); + } + + default M appendBefore( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.append(type, (holder, origin, args) -> { + final R newResult = behaviour.apply(args); + final R oldResult = origin.call(args); + return resultMerger.apply(oldResult, newResult); + }); + } + + + + default M prependAfter( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.prepend(type, (holder, origin, args) -> { + final R result = origin.call(args); + action.accept(args); + return result; + }); + } + + default M prependAfter( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.prepend(type, (holder, origin, args) -> { + final R oldResult = origin.call(args); + final R newResult = behaviour.apply(args); + return resultMerger.apply(oldResult, newResult); + }); + } + + default M prependBefore( + final BehaviourType> type, final Consumer action + ) { + Objects.requireNonNull(action, "action"); + return this.prepend(type, (holder, origin, args) -> { + action.accept(args); + final R result = origin.call(args); + return result; + }); + } + + default M prependBefore( + final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger + ) { + Objects.requireNonNull(behaviour, "behaviour"); + Objects.requireNonNull(resultMerger, "resultMerger"); + return this.prepend(type, (holder, origin, args) -> { + final R newResult = behaviour.apply(args); + final R oldResult = origin.call(args); + return resultMerger.apply(oldResult, newResult); + }); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderLogic.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderLogic.java new file mode 100644 index 0000000..27175eb --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderLogic.java @@ -0,0 +1,133 @@ +package net.hellheim.spongetools.custom.behaviour; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import org.checkerframework.checker.nullness.qual.Nullable; + +public abstract class BehaviourCallbackHolderLogic implements BehaviourCallbackHolder { + + protected final Map, TypedBehaviourCallback> callbacks; + + protected BehaviourCallbackHolderLogic( + final Map, TypedBehaviourCallback> callbacks + ) { + this.callbacks = callbacks; + } + + public static Mutable mutable() { + return new Mutable<>(); + } + + public static Immutable immutable() { + return new Immutable<>(); + } + + public static Mutable mutableOf( + final Map, TypedBehaviourCallback> callbacks + ) { + return new Mutable<>(callbacks); + } + + public static Immutable immutableOf( + final Map, TypedBehaviourCallback> callbacks + ) { + return new Immutable<>(callbacks); + } + + @Override + public Collection> callbacks() { + return this.callbacks.values(); + } + + @Override + public Optional> callback( + final BehaviourType> type + ) { + return Optional.ofNullable(this.callbackOrNull(type)); + } + + @Override + public @Nullable BehaviourCallback callbackOrNull( + final BehaviourType> type) { + Objects.requireNonNull(type, "type"); + @SuppressWarnings("unchecked") + final var callback = (TypedBehaviourCallback) this.callbacks.get(type); + return callback == null ? null : callback.callback(); + } + + public abstract Mutable asMutable(); + + public abstract Mutable asMutableCopy(); + + public abstract Immutable asImmutable(); + + public static class Mutable + extends BehaviourCallbackHolderLogic + implements BehaviourCallbackHolder.Mutable> { + + private Mutable() { + super(new HashMap<>()); + } + + private Mutable(final Map, TypedBehaviourCallback> callbacks) { + super(new HashMap<>(callbacks)); + } + + @Override + public BehaviourCallbackHolderLogic.Mutable offer( + final BehaviourType> type, + final BehaviourCallback callback + ) { + Objects.requireNonNull(type, "type"); + Objects.requireNonNull(callback, "callback"); + this.callbacks.put(type, TypedBehaviourCallback.of(type, callback)); + return this; + } + + @Override + public BehaviourCallbackHolderLogic.Mutable asMutable() { + return this; + } + + @Override + public BehaviourCallbackHolderLogic.Mutable asMutableCopy() { + return BehaviourCallbackHolderLogic.mutableOf(this.callbacks); + } + + @Override + public BehaviourCallbackHolderLogic.Immutable asImmutable() { + return BehaviourCallbackHolderLogic.immutableOf(this.callbacks); + } + } + + public static class Immutable + extends BehaviourCallbackHolderLogic { + + private Immutable() { + super(Map.of()); + } + + private Immutable(final Map, TypedBehaviourCallback> callbacks) { + super(Map.copyOf(callbacks)); + } + + @Override + public BehaviourCallbackHolderLogic.Mutable asMutable() { + return BehaviourCallbackHolderLogic.mutableOf(this.callbacks); + } + + @Override + public BehaviourCallbackHolderLogic.Mutable asMutableCopy() { + return this.asMutable(); + } + + @Override + public BehaviourCallbackHolderLogic.Immutable asImmutable() { + return this; + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderProxy.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderProxy.java new file mode 100644 index 0000000..a322214 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderProxy.java @@ -0,0 +1,48 @@ +package net.hellheim.spongetools.custom.behaviour; + +import java.util.Collection; +import java.util.Optional; + +import org.checkerframework.checker.nullness.qual.Nullable; + +public interface BehaviourCallbackHolderProxy extends BehaviourCallbackHolder { + + BehaviourCallbackHolder getAsBehaviourCallbackHolder(); + + @Override + default Collection> callbacks() { + return this.getAsBehaviourCallbackHolder().callbacks(); + } + + @Override + default Optional> callback( + final BehaviourType> type + ) { + return this.getAsBehaviourCallbackHolder().callback(type); + } + + @Override + default @Nullable BehaviourCallback callbackOrNull( + final BehaviourType> type + ) { + return this.getAsBehaviourCallbackHolder().callbackOrNull(type); + } + + interface Mutable> extends + BehaviourCallbackHolderProxy, + BehaviourCallbackHolder.Mutable { + + @Override + BehaviourCallbackHolder.Mutable getAsBehaviourCallbackHolder(); + + @Override + default M offer( + final BehaviourType> type, final BehaviourCallback callback + ) { + this.getAsBehaviourCallbackHolder().offer(type, callback); + @SuppressWarnings("unchecked") + final M $this = (M) this; + return $this; + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java index b64eea0..56e9256 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java @@ -1,14 +1,7 @@ package net.hellheim.spongetools.custom.behaviour; import java.util.NoSuchElementException; -import java.util.Objects; import java.util.Optional; -import java.util.function.BinaryOperator; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -import org.checkerframework.checker.nullness.qual.Nullable; /** * Represents something that can have {@link Behaviour}s. @@ -21,9 +14,7 @@ public interface BehaviourHolder { * @param type The type of the behaviour * @return True if this holder supports the given type */ - default boolean supports(final BehaviourType type) { - return BehaviourManager.get().supports(this.unwrap(), type); - } + boolean supports(BehaviourType type); /** * Returns the actual behaviour this {@link BehaviourHolder} will use, if present. @@ -32,9 +23,7 @@ default boolean supports(final BehaviourType type) { * @param type The type of the behaviour * @return The behaviour, if present */ - default > Optional get(final BehaviourType type) { - return BehaviourManager.get().get(this.unwrap(), type); - } + > Optional get(BehaviourType type); /** * Returns the actual behaviour this {@link BehaviourHolder} will use. @@ -44,242 +33,8 @@ default boolean supports(final BehaviourType type) { * @return The behaviour * @throws NoSuchElementException if the behaviour is not present on this {@link BehaviourHolder} */ - default > B require(final BehaviourType type) { - return this.get(type).orElseThrow(() -> new NoSuchElementException(String.format( - "No behaviour of type %s is present for holder %s", - type, this.unwrap() - ))); - } + > B require(final BehaviourType type); - private Object unwrap() { - Object actualHolder = this; - while (actualHolder instanceof final BehaviourHolderProxy proxy) { - actualHolder = proxy.owner(); - } - return actualHolder; - } - - /** - * - * @param The type of the actual behaviour holder - */ - interface Mutable> extends BehaviourHolder { - - /** - * Returns the current behaviour callback for the given type, if present. - * - * @param Behaviour return type - * @param Behaviour arguments - * @param type The behaviour type - * @return The current behaviour callback for the given type, if present - */ - Optional> callback(BehaviourType> type); - - /** - * Sets the given behaviour callback for the given type.
- * Overrides any previously registered callbacks. - * - * @param Behaviour return type - * @param
Behaviour arguments - * @param type The behaviour type - * @param callback The behaviour callback - * @return This modifiable behaviour, for chaining - */ - M offer(BehaviourType> type, BehaviourCallback callback); - - default M offer( - final BehaviourType> type, final Function behaviour - ) { - Objects.requireNonNull(behaviour, "behaviour"); - return this.offer(type, (holder, origin, args) -> behaviour.apply(args)); - } - - default M offer( - final BehaviourType> type, final Consumer behaviour - ) { - Objects.requireNonNull(behaviour, "behaviour"); - return this.offer(type, (holder, origin, args) -> { - behaviour.accept(args); - return null; - }); - } - - /** - * Sets the given value as a result of the callback for the given type. - * - * @param Behaviour return type - * @param Behaviour arguments - * @param type The behaviour type - * @param value The value to return - * @return This modifiable behaviour, for chaining - */ - default M set( - final BehaviourType> type, final R value - ) { - Objects.requireNonNull(value, "value"); - return this.offer(type, (holder, origin, args) -> value); - } - - /** - * Sets the given value as a result of the callback for the given type. - * - * @param Behaviour return type - * @param Behaviour arguments - * @param type The behaviour type - * @param value The value to return - * @return This modifiable behaviour, for chaining - */ - default M set( - final BehaviourType> type, final Supplier valueSupplier - ) { - Objects.requireNonNull(valueSupplier, "valueSupplier"); - return this.set(type, valueSupplier.get()); - } - - default M transform( - final BehaviourType> type, - final Function<@Nullable BehaviourCallback, BehaviourCallback> function - ) { - Objects.requireNonNull(function, "function"); - return this.offer(type, function.apply(this.callback(type).orElse(null))); - } - - /** - * Wraps the given callback around the current callback.
- * Means that the current callback becomes the "original" for the given one.
- * If current callback is not present, simply sets the given callback. - * - * @param Behaviour return type - * @param
Behaviour arguments - * @param type The behaviour type - * @param callback The behaviour callback - * @return This modifiable behaviour, for chaining - */ - default M append( - final BehaviourType> type, final BehaviourCallback callback - ) { - Objects.requireNonNull(callback, "callback"); - return this.transform(type, old -> old == null - ? callback - : (holder, origin, args) -> - callback.call(holder, (newArgs) -> old.call(holder, origin, newArgs), args)); - } - - /** - * Wraps the current callback around the given callback.
- * Means that the given callback becomes the "original" for the current one.
- * If current callback is not present, simply sets the given callback. - * - * @param Behaviour return type - * @param
Behaviour arguments - * @param type The behaviour type - * @param callback The behaviour callback - * @return This modifiable behaviour, for chaining - */ - default M prepend( - final BehaviourType> type, final BehaviourCallback callback - ) { - Objects.requireNonNull(callback, "callback"); - return this.transform(type, old -> old == null - ? callback - : (holder, origin, args) -> - old.call(holder, (newArgs) -> callback.call(holder, origin, newArgs), args)); - } - - - - default M appendAfter( - final BehaviourType> type, final Consumer action - ) { - Objects.requireNonNull(action, "action"); - return this.append(type, (holder, origin, args) -> { - final R result = origin.call(args); - action.accept(args); - return result; - }); - } - - default M appendAfter( - final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger - ) { - Objects.requireNonNull(behaviour, "behaviour"); - Objects.requireNonNull(resultMerger, "resultMerger"); - return this.append(type, (holder, origin, args) -> { - final R oldResult = origin.call(args); - final R newResult = behaviour.apply(args); - return resultMerger.apply(oldResult, newResult); - }); - } - - default M appendBefore( - final BehaviourType> type, final Consumer action - ) { - Objects.requireNonNull(action, "action"); - return this.append(type, (holder, origin, args) -> { - action.accept(args); - final R result = origin.call(args); - return result; - }); - } - - default M appendBefore( - final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger - ) { - Objects.requireNonNull(behaviour, "behaviour"); - Objects.requireNonNull(resultMerger, "resultMerger"); - return this.append(type, (holder, origin, args) -> { - final R newResult = behaviour.apply(args); - final R oldResult = origin.call(args); - return resultMerger.apply(oldResult, newResult); - }); - } - - - - default M prependAfter( - final BehaviourType> type, final Consumer action - ) { - Objects.requireNonNull(action, "action"); - return this.prepend(type, (holder, origin, args) -> { - final R result = origin.call(args); - action.accept(args); - return result; - }); - } - - default M prependAfter( - final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger - ) { - Objects.requireNonNull(behaviour, "behaviour"); - Objects.requireNonNull(resultMerger, "resultMerger"); - return this.prepend(type, (holder, origin, args) -> { - final R oldResult = origin.call(args); - final R newResult = behaviour.apply(args); - return resultMerger.apply(oldResult, newResult); - }); - } - - default M prependBefore( - final BehaviourType> type, final Consumer action - ) { - Objects.requireNonNull(action, "action"); - return this.prepend(type, (holder, origin, args) -> { - action.accept(args); - final R result = origin.call(args); - return result; - }); - } - - default M prependBefore( - final BehaviourType> type, final Function behaviour, final BinaryOperator resultMerger - ) { - Objects.requireNonNull(behaviour, "behaviour"); - Objects.requireNonNull(resultMerger, "resultMerger"); - return this.prepend(type, (holder, origin, args) -> { - final R newResult = behaviour.apply(args); - final R oldResult = origin.call(args); - return resultMerger.apply(oldResult, newResult); - }); - } + interface Mutable> extends BehaviourHolder, BehaviourCallbackHolder.Mutable { } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java index 5caa817..3885dcf 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java @@ -1,24 +1,26 @@ package net.hellheim.spongetools.custom.behaviour; -/** - * Represents the wrapper around the actual behaviour holder - * that does not directly implement {@link BehaviourHolder}. - * - * @param The type of the actual behaviour holder - */ -public interface BehaviourHolderProxy extends BehaviourHolder { +import java.util.Optional; + +public interface BehaviourHolderProxy extends BehaviourHolder { + + BehaviourHolder getAsBehaviourHolder(); + + @Override + default boolean supports(final BehaviourType type) { + return this.getAsBehaviourHolder().supports(type); + } - /** - * Returns the owner of this extension. - * - * @return The owner of this extension - */ - H owner(); + @Override + default > Optional get(final BehaviourType type) { + return this.getAsBehaviourHolder().get(type); + } + + @Override + default > B require(final BehaviourType type) { + return this.getAsBehaviourHolder().require(type); + } - /** - * - * @param The type of the actual behaviour holder - */ - interface Mutable> extends BehaviourHolder.Mutable, BehaviourHolderProxy { + interface Mutable> extends BehaviourHolder.Mutable, BehaviourHolderProxy { } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java index 5e6efdb..fac906d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java @@ -1,5 +1,6 @@ package net.hellheim.spongetools.custom.behaviour; +import java.util.NoSuchElementException; import java.util.Optional; import java.util.function.Function; @@ -16,6 +17,13 @@ static BehaviourManager get() { > Optional get(H holder, BehaviourType type); + default > B require(final H holder, final BehaviourType type) { + return this.get(holder, type).orElseThrow(() -> new NoSuchElementException(String.format( + "No behaviour of type %s is present for holder %s", + type, holder + ))); + } + BehaviourRegistration create(Class holder); interface BehaviourRegistration { diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/TypedBehaviourCallback.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/TypedBehaviourCallback.java new file mode 100644 index 0000000..e5310ae --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/TypedBehaviourCallback.java @@ -0,0 +1,20 @@ +package net.hellheim.spongetools.custom.behaviour; + +import java.util.Objects; + +public record TypedBehaviourCallback( + BehaviourType> type, BehaviourCallback callback) { + + public TypedBehaviourCallback( + final BehaviourType> type, final BehaviourCallback callback + ) { + this.type = Objects.requireNonNull(type, "type"); + this.callback = Objects.requireNonNull(callback, "callback"); + } + + public static TypedBehaviourCallback of( + final BehaviourType> type, final BehaviourCallback callback + ) { + return new TypedBehaviourCallback<>(type, callback); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java new file mode 100644 index 0000000..a532730 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java @@ -0,0 +1,29 @@ +package net.hellheim.spongetools.custom.behaviour.tag; + +import java.util.stream.Stream; + +import org.spongepowered.api.tag.Tag; +import org.spongepowered.api.tag.Taggable; + +// TODO +public interface TaggableInstance> { + + T taggedType(); + + Stream> tags(); + + boolean is(Tag tag); + + interface Defaulted> extends TaggableInstance { + + @Override + default Stream> tags() { + return this.taggedType().tags().stream(); + } + + @Override + default boolean is(final Tag tag) { + return this.taggedType().is(tag); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java index 36996df..158dda1 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java @@ -2,21 +2,22 @@ import java.util.Objects; import java.util.Optional; +import java.util.function.BiConsumer; import java.util.function.Supplier; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; import org.spongepowered.api.data.type.HandType; -import org.spongepowered.api.data.type.PushReaction; -import org.spongepowered.api.entity.EntityType; import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.fluid.FluidType; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackLike; -import org.spongepowered.api.map.color.MapColorType; import org.spongepowered.api.util.Direction; import org.spongepowered.api.util.RandomProvider; import org.spongepowered.api.world.World; +import org.spongepowered.api.world.explosion.Explosion; import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.api.world.volume.Volume; import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; import org.spongepowered.api.world.volume.game.Region; import org.spongepowered.api.world.volume.game.UpdatableVolume; @@ -27,70 +28,41 @@ import net.hellheim.spongetools.custom.behaviour.util.HitResult; import net.hellheim.spongetools.custom.behaviour.util.InteractionResult; import net.hellheim.spongetools.custom.behaviour.util.SignalOrientation; +import net.hellheim.spongetools.custom.behaviour.util.UseContext; @FunctionalInterface public interface BlockStateBehaviour extends Behaviour { @FunctionalInterface - interface SpawnValidator extends BlockStateBehaviour { + interface Locatable extends BlockStateBehaviour> { @Override - default Boolean call(final Args args) { - return this.call(args.volume(), args.position(), args.entity()); - } - - boolean call(PrimitiveGameVolume volume, Vector3i position, EntityType entity); - - interface Args extends - BehaviourArgs.Volumed, - BehaviourArgs.Positional { - - EntityType entity(); - - Args withEntity(EntityType entity); - } - } - - @FunctionalInterface - interface MapColor extends BlockStateBehaviour { - - @Override - default MapColorType call(final Args args) { + default R call(final Args args) { return this.call(args.volume(), args.position()); } - MapColorType call(PrimitiveGameVolume volume, Vector3i position); + R call(V volume, Vector3i position); - interface Args extends - BehaviourArgs.Volumed, - BehaviourArgs.Positional { + interface Args extends + BehaviourArgs.Volumed>, + BehaviourArgs.Positional> { } } @FunctionalInterface - interface PistonPushReaction extends BlockStateBehaviour { - - @Override - default PushReaction call(final BehaviourArgs args) { - return this.call(); - } - - PushReaction call(); - } - - @FunctionalInterface - interface SignalConductor extends BlockStateBehaviour { + interface LocatableEntity extends BlockStateBehaviour> { @Override - default Boolean call(final Args args) { - return this.call(args.volume(), args.position()); + default R call(final Args args) { + return this.call(args.volume(), args.position(), args.entity()); } - boolean call(PrimitiveGameVolume volume, Vector3i position); + R call(V volume, Vector3i position, E entity); - interface Args extends - BehaviourArgs.Volumed, - BehaviourArgs.Positional { + interface Args extends + BehaviourArgs.Volumed>, + BehaviourArgs.Positional>, + BehaviourArgs.EntitySource>{ } } @@ -111,22 +83,6 @@ interface Args extends } } - @FunctionalInterface - interface AnalogSignalPower extends BlockStateBehaviour { - - @Override - default Integer call(final Args args) { - return this.call(args.volume(), args.position()); - } - - int call(World volume, Vector3i position); - - interface Args extends - BehaviourArgs.Volumed, Args>, - BehaviourArgs.Positional { - } - } - @FunctionalInterface interface Tick extends BlockStateBehaviour { @@ -136,7 +92,7 @@ default Void call(final Args args) { return null; } - void call(ServerWorld world, Vector3i position, RandomProvider.Source random); + void call(ServerWorld volume, Vector3i position, RandomProvider.Source random); interface Args extends BehaviourArgs.Volumed, @@ -154,7 +110,7 @@ default Void call(final Args args) { return null; } - void call(World world, Vector3i position, BlockState otherState, boolean movedByPiston); + void call(World volume, Vector3i position, BlockState otherState, boolean movedByPiston); interface Args extends BehaviourArgs.Volumed, Args>, @@ -170,6 +126,31 @@ interface Args extends } } + @FunctionalInterface + interface ExplosionHit extends BlockStateBehaviour { + + @Override + default Void call(final Args args) { + this.call(args.volume(), args.position(), args.explosion(), args.drop()); + return null; + } + + void call(ServerWorld volume, Vector3i position, Explosion explosion, BiConsumer drop); + + interface Args extends + BehaviourArgs.Volumed, + BehaviourArgs.Positional { + + Explosion explosion(); + + BiConsumer drop(); + + Args withExplosion(Explosion explosion); + + Args withDrop(BiConsumer drop); + } + } + @FunctionalInterface interface ShapeUpdate extends BlockStateBehaviour { @@ -253,10 +234,10 @@ interface UseWithItem extends BlockStateBehaviour volume, Player entity, HandType hand, HitResult.BlockHitResult hit); + InteractionResult call(World volume, Player entity, HitResult.BlockHitResult hit, HandType hand, ItemStackLike item); interface Args extends BehaviourArgs.Volumed, Args>, @@ -295,20 +276,71 @@ interface Args extends } @FunctionalInterface - interface Attack extends BlockStateBehaviour { + interface ReplaceableByFluid extends BlockStateBehaviour { @Override - default Void call(final Args args) { - this.call(args.volume(), args.position(), args.entity()); - return null; + default Boolean call(final Args args) { + return this.call(args.fluid()); } - void call(World volume, Vector3i position, Player entity); + default boolean call(final Supplier fluidSupplier) { + return this.call(Objects.requireNonNull(fluidSupplier, "fluidSupplier").get()); + } - interface Args extends - BehaviourArgs.Volumed, Args>, - BehaviourArgs.Positional, - BehaviourArgs.EntitySource { + boolean call(FluidType fluid); + + interface Args extends BehaviourArgs { + + FluidType fluid(); + + Args withFluid(FluidType fluid); + + default Args withFluid(final Supplier fluidSupplier) { + return this.withFluid(Objects.requireNonNull(fluidSupplier, "fluidSupplier").get()); + } + } + } + + @FunctionalInterface + interface ReplaceableByBlock extends BlockStateBehaviour { + + @Override + default Boolean call(final Args args) { + return this.call(args.context()); + } + + boolean call(UseContext.BlockPlace context); + + interface Args extends + BehaviourArgs.Contextual { + } + } + + @FunctionalInterface + interface CloneItem extends BlockStateBehaviour { + + @Override + default ItemStack call(final Args args) { + return this.call(args.volume(), args.position(), args.data()); + } + + ItemStack call(Region volume, Vector3i position, boolean data); + + interface Args extends + BehaviourArgs.Volumed, Args>, + BehaviourArgs.Positional { + + boolean data(); + + Args withData(boolean data); + + default Args withData() { + return this.withData(true); + } + + default Args withoutData() { + return this.withData(false); + } } } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java index f8c5e2d..9bfb8a6 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java @@ -3,66 +3,102 @@ import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; import org.spongepowered.api.block.BlockTypes; +import org.spongepowered.api.data.type.InstrumentType; +import org.spongepowered.api.data.type.PushReaction; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.entity.EntityType; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.map.color.MapColorType; +import org.spongepowered.api.util.AABB; +import org.spongepowered.api.world.World; +import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; +import org.spongepowered.api.world.volume.game.Region; import org.spongepowered.api.world.volume.game.UpdatableVolume; +import net.hellheim.spongetools.custom.behaviour.Behaviour.SimpleBoolean; +import net.hellheim.spongetools.custom.behaviour.Behaviour.SimpleObject; import net.hellheim.spongetools.custom.behaviour.BehaviourType; -import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.AnalogSignalPower; -import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.Attack; -import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.MapColor; -import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.PistonPushReaction; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.CloneItem; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.ExplosionHit; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.Locatable; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.LocatableEntity; import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.Replace; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.ReplaceableByBlock; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.ReplaceableByFluid; import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.ShapeUpdate; -import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.SignalConductor; import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.SignalPower; import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.SignalUpdate; -import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.SpawnValidator; import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.Tick; import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.UseWithItem; import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.UseWithoutItem; public final class BlockStateBehaviours { - public static final BehaviourType SPAWN_VALIDATOR = BehaviourType.create(); + public static final BehaviourType>> SPAWN_VALIDATOR = BehaviourType.create(); - public static final BehaviourType MAP_COLOR = BehaviourType.create(); + public static final BehaviourType> MAP_COLOR = BehaviourType.create(); - /** - * Used by {@link BlockTypes#PISTON} and {@link BlockTypes#STICKY_PISTON}. - */ - public static final BehaviourType PUSH_REACTION = BehaviourType.create(); - - public static final BehaviourType SIGNAL_CONDUCTOR = BehaviourType.create(); + public static final BehaviourType> SIGNAL_CONDUCTOR = BehaviourType.create(); /** * Signal that will power neighbour blocks. */ - public static final BehaviourType WEAK_SIGNAL_POWER = BehaviourType.create(); + public static final BehaviourType WEAK_SIGNAL = BehaviourType.create(); /** * Signal that will go through neighbour blocks.
* * In vanilla this behaviour usually filters result of * {@link BlockStateExtension#get(BehaviourType)} - * for {@link #WEAK_SIGNAL_POWER} behaviour by side.
+ * for {@link #WEAK_SIGNAL} behaviour by side.
* * Used by {@link BlockTypes#REPEATER} (horizontally) and other redstone-related blocks (upwards). */ - public static final BehaviourType STRONG_SIGNAL_POWER = BehaviourType.create(); + public static final BehaviourType STRONG_SIGNAL = BehaviourType.create(); /** * Result of this behaviour is usually used by {@link BlockTypes#COMPARATOR}. */ - public static final BehaviourType ANALOG_SIGNAL_POWER = BehaviourType.create(); + public static final BehaviourType>> ANALOG_SIGNAL = BehaviourType.create(); + + /** + * The strength of the block for destruction.
+ * The bigger this value, the longer it will take for block to be destroyed.
+ * Special value of -1 makes block unbreakable and not movable by piston. + */ + public static final BehaviourType> DESTRUCTION_STRENGTH = BehaviourType.create(); + + /** + * The increment of the destruction progress per tick.
+ * Value greater than or equal to 1 makes block break instantly. + */ + public static final BehaviourType> DESTRUCTION_INCREMENT = BehaviourType.create(); /** * Adding this behaviour doesn't make block ticking "naturally".
* Ticks must be scheduled through {@link UpdatableVolume#scheduledBlockUpdates()}.
- * For example, ticks could be scheduled in {@link #PLACE}, {@link #SHAPE_UPDATE} or in {@link #TICK} itself. + * For example, ticks could be scheduled in {@link #PLACE}, {@link #SHAPE_UPDATE} or in {@link #BASE_TICK} itself. */ - public static final BehaviourType TICK = BehaviourType.create(); + public static final BehaviourType BASE_TICK = BehaviourType.create(); + /** + * Adding this behaviour doesn't make block randomly ticking "naturally".
+ * + * @see #HAS_RANDOM_TICK + */ public static final BehaviourType RANDOM_TICK = BehaviourType.create(); + /** + * Used to decide whether block should recieve natural random ticks. + */ + public static final BehaviourType HAS_RANDOM_TICK = BehaviourType.create(); + + /** + * Called when {@link Entity}'s {@link AABB} collides with the {@link BlockState}. + */ + public static final BehaviourType, Entity>> ENTITY_INSIDE = BehaviourType.create(); + /** * Called when {@link BlockState} enters the world. */ @@ -73,6 +109,11 @@ public final class BlockStateBehaviours { */ public static final BehaviourType REMOVE = BehaviourType.create(); + /** + * Called when {@link BlockState} is interacted with by the explosion. + */ + public static final BehaviourType EXPLOSION = BehaviourType.create(); + /** * Called when neighbour {@link BlockState}s are changed.
* @@ -93,7 +134,45 @@ public final class BlockStateBehaviours { public static final BehaviourType USE_WITHOUT_ITEM = BehaviourType.create(); - public static final BehaviourType ATTACK = BehaviourType.create(); + public static final BehaviourType, Player>> ATTACK = BehaviourType.create(); + + /** + * Used by {@link BlockTypes#PISTON} and {@link BlockTypes#STICKY_PISTON}. + */ + public static final BehaviourType> PUSH_REACTION = BehaviourType.create(); + + /** + * Used by {@link BlockTypes#NOTE_BLOCK}. + */ + public static final BehaviourType> INSTRUMENT = BehaviourType.create(); + + public static final BehaviourType REQUIRE_TOOL = BehaviourType.create(); + + public static final BehaviourType REPLACEABLE = BehaviourType.create(); + + public static final BehaviourType REPLACEABLE_BY_FLUID = BehaviourType.create(); + + public static final BehaviourType REPLACEABLE_BY_BLOCK = BehaviourType.create(); + + /** + * Used to decide whether entities will suffocate in the block. + */ + public static final BehaviourType> SUFFOCATION = BehaviourType.create(); + + /** + * If this behaviour returns true, {@link #SHAPE_UPDATE} would be called + * for this block with each neighbour around it when generated in the world. + */ + public static final BehaviourType> POST_PROCESSING = BehaviourType.create(); + + public static final BehaviourType>> CAN_SURVIVE = BehaviourType.create(); + + /** + * The item representation of the block.
+ * Usually it's asked when player uses the middle mouse button.
+ * If block doesn't have an item representation, this behaviour would return {@link ItemStack#empty()}. + */ + public static final BehaviourType CLONE_ITEM = BehaviourType.create(); private BlockStateBehaviours() { } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java index f4191b0..4ac14d5 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java @@ -1,23 +1,49 @@ package net.hellheim.spongetools.custom.behaviour.type; +import java.util.Optional; + import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; -import net.hellheim.spongetools.custom.behaviour.BehaviourHolderProxy; +import net.hellheim.spongetools.custom.behaviour.Behaviour; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; +import net.hellheim.spongetools.custom.behaviour.BehaviourHolder; +import net.hellheim.spongetools.custom.behaviour.BehaviourManager; +import net.hellheim.spongetools.custom.behaviour.BehaviourType; import net.hellheim.spongetools.proxy.solid.block.BlockStateProxy; /** * Can be used to override default {@link BlockState} behaviour. */ -public interface BlockStateExtension extends BehaviourHolderProxy, BlockStateProxy { +public interface BlockStateExtension extends + BehaviourHolder, + BehaviourCallbackHolder, + BlockStateProxy { static BlockStateExtension getFor(final BlockState state) { return Sponge.game().factoryProvider().provide(Factory.class).getFor(state); } + BlockState state(); + @Override default BlockState getAsBlockState() { - return this.owner(); + return this.state(); + } + + @Override + default boolean supports(final BehaviourType type) { + return BehaviourManager.get().supports(this.state(), type); + } + + @Override + default > Optional get(final BehaviourType type) { + return BehaviourManager.get().get(this.state(), type); + } + + @Override + default > B require(final BehaviourType type) { + return BehaviourManager.get().require(this.state(), type); } interface Factory { diff --git a/src/main/java/net/hellheim/spongetools/custom/block/BasicCustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/block/BasicCustomBlockType.java new file mode 100644 index 0000000..7441332 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/block/BasicCustomBlockType.java @@ -0,0 +1,48 @@ +package net.hellheim.spongetools.custom.block; + +import org.spongepowered.api.block.BlockState; + +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderLogic; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderProxy; +import net.hellheim.spongetools.custom.behaviour.BehaviourHolder; +import net.hellheim.spongetools.custom.behaviour.BehaviourHolderProxy; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; + +public class BasicCustomBlockType implements + CustomBlockType, + BehaviourHolderProxy, + BehaviourCallbackHolderProxy { + + private final BehaviourCallbackHolderLogic callbacks; + private final BlockStateProvider stateProvider; + private final BlockState state; + private final BlockStateExtension stateExtension; + + public BasicCustomBlockType(final CustomBlockTypeBuilder builder) { + this.callbacks = builder.callbacks.asImmutable(); + this.stateProvider = builder.stateProvider; + this.state = this.stateProvider.provide(); + this.stateExtension = BlockStateExtension.getFor(this.state); + } + + @Override + public BlockStateProvider stateProvider() { + return this.stateProvider; + } + + @Override + public BlockStateExtension stateExtension() { + return this.stateExtension; + } + + @Override + public BehaviourHolder getAsBehaviourHolder() { + return this.stateExtension; + } + + @Override + public BehaviourCallbackHolder getAsBehaviourCallbackHolder() { + return this.callbacks; + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java b/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java index 0da70d2..bb49753 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java +++ b/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.Collection; +import java.util.List; import java.util.Set; import java.util.function.Predicate; import java.util.function.Supplier; @@ -18,17 +19,25 @@ public interface BlockStateProvider/* extends MapCodecProxy*/ { + static Any any(final BlockStateProvider... providers) { + return new Any(List.of(providers)); + } + + static Any any(final Collection providers) { + return new Any(List.copyOf(providers)); + } + @SafeVarargs - static Any any(final Supplier... blocks) { - return new Any(Arrays.stream(blocks).map(Supplier::get).collect(Collectors.toUnmodifiableSet())); + static AnyBlock anyBlock(final Supplier... blocks) { + return new AnyBlock(Arrays.stream(blocks).map(Supplier::get).collect(Collectors.toUnmodifiableSet())); } - static Any any(final BlockType... blocks) { - return new Any(Set.of(blocks)); + static AnyBlock anyBlock(final BlockType... blocks) { + return new AnyBlock(Set.of(blocks)); } - static Any any(final Collection blocks) { - return new Any(Set.copyOf(blocks)); + static AnyBlock anyBlock(final Collection blocks) { + return new AnyBlock(Set.copyOf(blocks)); } static Slab slab() { @@ -36,15 +45,21 @@ static Slab slab() { } - default BlockState provide() throws NoAvailableStateException { + /** + * @throws NoAvailableStateException + */ + default BlockState provide() { return this.provide($ -> true); } - default BlockState provide(final Predicate predicate) throws NoAvailableStateException { + /** + * @throws NoAvailableStateException + */ + default BlockState provide(final Predicate predicate) { return this.availableStates() .filter(predicate) .findAny() - .orElseThrow(this::createException); + .orElseThrow(() -> new NoAvailableStateException(this.toString())); } default Stream availableStates() { @@ -53,14 +68,27 @@ default Stream availableStates() { Stream allStates(); - default NoAvailableStateException createException() { - return new NoAvailableStateException(); - } + record Any(List providers) implements BlockStateProvider { + + public Any(final List providers) { + this.providers = List.copyOf(providers); + } + + @Override + public Stream allStates() { + return this.providers.stream().flatMap(BlockStateProvider::allStates).distinct(); + } + + @Override + public final String toString() { + return this.providers.toString(); + } + } - record Any(Set blocks) implements BlockStateProvider { + record AnyBlock(Set blocks) implements BlockStateProvider { - public Any(final Set blocks) { + public AnyBlock(final Set blocks) { this.blocks = Set.copyOf(blocks); } @@ -70,8 +98,8 @@ public Stream allStates() { } @Override - public NoAvailableStateException createException() { - return new NoAvailableStateException(this.blocks.toString()); + public String toString() { + return this.blocks.toString(); } } diff --git a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java b/src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java index f209f38..3772800 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java +++ b/src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java @@ -8,7 +8,7 @@ public final class BlockStateRegistrar { - public static final Set OCCUPIED_STATES = new HashSet<>(); + private static final Set OCCUPIED_STATES = new HashSet<>(); public static boolean isOccupied(final BlockState state) { return BlockStateRegistrar.OCCUPIED_STATES.contains(Objects.requireNonNull(state, "state")); diff --git a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java index dcdecff..993634f 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java +++ b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java @@ -1,12 +1,12 @@ package net.hellheim.spongetools.custom.block; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; -public interface CustomBlockType { - +public interface CustomBlockType extends + BehaviourCallbackHolder { BlockStateProvider stateProvider(); BlockStateExtension stateExtension(); - } diff --git a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeBuilder.java b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeBuilder.java new file mode 100644 index 0000000..4071ac0 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeBuilder.java @@ -0,0 +1,39 @@ +package net.hellheim.spongetools.custom.block; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderLogic; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderProxy; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; + +public class CustomBlockTypeBuilder> implements + BehaviourCallbackHolderProxy.Mutable { + + protected BehaviourCallbackHolderLogic.Mutable callbacks; + protected @Nullable BlockStateProvider stateProvider; + + public CustomBlockTypeBuilder() { + this.reset(); + } + + @SuppressWarnings("unchecked") + private B cast() { + return (B) this; + } + + @Override + public BehaviourCallbackHolder.Mutable getAsBehaviourCallbackHolder() { + return this.callbacks; + } + + public B reset() { + this.callbacks = BehaviourCallbackHolderLogic.mutable(); + this.stateProvider = null; + return this.cast(); + } + + public CustomBlockType build() { + return new BasicCustomBlockType(this); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeProperties.java b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeProperties.java new file mode 100644 index 0000000..f6baebc --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeProperties.java @@ -0,0 +1,17 @@ +package net.hellheim.spongetools.custom.block; + +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderLogic; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderProxy; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; + +public class CustomBlockTypeProperties implements + BehaviourCallbackHolderProxy { + + private final BehaviourCallbackHolderLogic.Immutable callbacks = null; + + @Override + public BehaviourCallbackHolder getAsBehaviourCallbackHolder() { + return this.callbacks; + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java deleted file mode 100644 index f97eac8..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/block/DefaultedCustomBlockType.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.hellheim.spongetools.custom.block; - -import java.util.Objects; - -import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; - -public class DefaultedCustomBlockType implements CustomBlockType { - - private final BlockStateProvider stateProvider; - private final BlockStateExtension stateExtension; - - public DefaultedCustomBlockType(final BlockStateProvider stateProvider) { - this.stateProvider = Objects.requireNonNull(stateProvider, "stateProvider"); - this.stateExtension = BlockStateExtension.getFor(this.stateProvider.provide()); - } - - @Override - public BlockStateProvider stateProvider() { - return this.stateProvider; - } - - @Override - public BlockStateExtension stateExtension() { - return this.stateExtension; - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/model/TexturedModel.java b/src/main/java/net/hellheim/spongetools/custom/model/TexturedModel.java index 77116c3..cd80557 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/TexturedModel.java +++ b/src/main/java/net/hellheim/spongetools/custom/model/TexturedModel.java @@ -92,7 +92,8 @@ private static TexturedModel of(final Optional optionalKey, final T } for (final ModelTemplate template : templates) { - if (template.slots().equals(textures.slots())) { + if (textures.slots().size() == template.slots().size() + && textures.slots().containsAll(template.slots())) { return new TexturedModel(template, textures); } } diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java index 98e7e17..84dbd1e 100644 --- a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java +++ b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java @@ -10,7 +10,7 @@ import com.google.common.collect.Streams; -import net.hellheim.spongetools.custom.behaviour.BehaviourHolderProxy; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; public interface RegisterBlockStateBehaviourEvent extends LifecycleEvent { @@ -81,6 +81,8 @@ default Stream allStates(final Iterable type } - interface BehaviourStep extends BehaviourHolderProxy.Mutable { + interface BehaviourStep extends BehaviourCallbackHolder.Mutable { + + BlockState state(); } } From 16ec045e48816aab4a7e751eafb93fde241c6f54 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sun, 11 May 2025 04:35:57 +0300 Subject: [PATCH 16/55] continue custom stuff --- .../net/hellheim/spongetools/SpongeTools.java | 4 +- .../codec/list/RegistryCodecs.java | 4 +- .../behaviour/BehaviourCallbackHolder.java | 41 +- .../custom/behaviour/BehaviourManager.java | 73 +- .../behaviour/type/BlockStateBehaviours.java | 2 + .../behaviour/type/BlockStateExtension.java | 15 +- .../behaviour/type/BlockTypeExtension.java | 49 ++ .../behaviour/util/InteractionResult.java | 4 +- .../custom/block/BasicCustomBlockType.java | 29 +- .../custom/block/BlockStateProvider.java | 25 + .../custom/block/CustomBlockType.java | 23 +- .../custom/block/CustomBlockTypeBuilder.java | 96 ++- .../custom/item/CustomItemType.java | 2 +- .../custom/item/CustomItemTypeProperties.java | 6 +- .../custom/item/IDefaultedCustomItemType.java | 2 +- .../event/RegisterBehaviourDataEvent.java | 4 +- .../spongetools/function/QuinFunction.java | 15 + .../solid/block/StateContainerProxy.java | 34 + .../proxy/solid/codec/DynamicOpsProxy.java | 280 +++++++ .../model => resourcepack}/ModelTemplate.java | 2 +- .../ModelTemplateProvider.java | 2 +- .../ModelTemplates.java | 2 +- .../model => resourcepack}/TextureSlot.java | 2 +- .../model => resourcepack}/TextureSlots.java | 2 +- .../model => resourcepack}/TexturedModel.java | 2 +- .../model => resourcepack}/Textures.java | 2 +- .../resourcepack/block/BlockDefinition.java | 168 ++++ .../resourcepack/block/StateCodec.java | 122 +++ .../resourcepack/block/StateCondition.java | 48 ++ .../resourcepack/block/StateDispatch.java | 716 ++++++++++++++++++ .../resourcepack/block/StateOps.java | 38 + .../block/StatePropertyValue.java | 43 ++ .../resourcepack/block/StateSelector.java | 227 ++++++ .../resourcepack/block/Variant.java | 129 ++++ .../resourcepack/block/VariantProperties.java | 31 + .../resourcepack/block/VariantProperty.java | 39 + .../block/VariantPropertyValue.java | 49 ++ .../resourcepack/block/VariantRotation.java | 32 + .../item/ConditionalProperty.java | 2 +- .../model => resourcepack}/item/Item.java | 2 +- .../item/ItemDefinition.java | 2 +- .../item/ItemModel.java | 10 +- .../item/ItemTransforms.java | 2 +- .../item/RangeSelectEntry.java | 2 +- .../item/RangeSelectProperty.java | 6 +- .../item/SelectProperty.java | 4 +- .../item/SelectSwitch.java | 2 +- .../item/SelectSwitchCase.java | 2 +- .../item/SpecialModel.java | 4 +- .../item/TintSource.java | 2 +- .../util/ChargeType.java | 18 +- .../util/CompassTarget.java | 18 +- .../model => resourcepack}/util/GuiLight.java | 14 +- .../util/SkullType.java | 24 +- .../util/TimeSource.java | 16 +- .../util/WoodTypes.java | 2 +- 56 files changed, 2364 insertions(+), 132 deletions(-) create mode 100644 src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockTypeExtension.java create mode 100644 src/main/java/net/hellheim/spongetools/function/QuinFunction.java create mode 100644 src/main/java/net/hellheim/spongetools/proxy/solid/block/StateContainerProxy.java create mode 100644 src/main/java/net/hellheim/spongetools/proxy/solid/codec/DynamicOpsProxy.java rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/ModelTemplate.java (95%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/ModelTemplateProvider.java (99%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/ModelTemplates.java (99%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/TextureSlot.java (95%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/TextureSlots.java (97%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/TexturedModel.java (98%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/Textures.java (99%) create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/VariantPropertyValue.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/VariantRotation.java rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/ConditionalProperty.java (99%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/Item.java (96%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/ItemDefinition.java (99%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/ItemModel.java (94%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/ItemTransforms.java (98%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/RangeSelectEntry.java (92%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/RangeSelectProperty.java (97%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/SelectProperty.java (98%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/SelectSwitch.java (93%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/SelectSwitchCase.java (94%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/SpecialModel.java (98%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/item/TintSource.java (99%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/util/ChargeType.java (63%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/util/CompassTarget.java (61%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/util/GuiLight.java (69%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/util/SkullType.java (55%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/util/TimeSource.java (60%) rename src/main/java/net/hellheim/spongetools/{custom/model => resourcepack}/util/WoodTypes.java (89%) diff --git a/src/main/java/net/hellheim/spongetools/SpongeTools.java b/src/main/java/net/hellheim/spongetools/SpongeTools.java index 9de8b4b..9c7ea02 100644 --- a/src/main/java/net/hellheim/spongetools/SpongeTools.java +++ b/src/main/java/net/hellheim/spongetools/SpongeTools.java @@ -14,8 +14,8 @@ import net.hellheim.spongetools.custom.item.CustomItemType; import net.hellheim.spongetools.custom.item.EitherItemType; import net.hellheim.spongetools.custom.item.data.CustomConsumeEffect; -import net.hellheim.spongetools.custom.model.item.Item; -import net.hellheim.spongetools.custom.model.item.ItemModel; +import net.hellheim.spongetools.resourcepack.item.Item; +import net.hellheim.spongetools.resourcepack.item.ItemModel; public final class SpongeTools { diff --git a/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java b/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java index aa8f3c9..c9d6c24 100644 --- a/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java +++ b/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java @@ -176,8 +176,8 @@ import net.hellheim.spongetools.custom.item.CustomItemType; import net.hellheim.spongetools.custom.item.EitherItemType; import net.hellheim.spongetools.custom.item.data.CustomConsumeEffect; -import net.hellheim.spongetools.custom.model.item.Item; -import net.hellheim.spongetools.custom.model.item.ItemModel; +import net.hellheim.spongetools.resourcepack.item.Item; +import net.hellheim.spongetools.resourcepack.item.ItemModel; /** * Codecs for all {@link RegistryType}s provided by SpongeAPI. diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java index 0861280..5bcf238 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java @@ -26,8 +26,13 @@ public interface BehaviourCallbackHolder { @Nullable BehaviourCallback callbackOrNull(BehaviourType> type); + @SuppressWarnings("unchecked") interface Mutable> extends BehaviourCallbackHolder { + private M cast() { + return (M) this; + } + /** * Sets the given behaviour callback for the given type.
* Overrides any previously registered callbacks. @@ -62,11 +67,39 @@ default M offer(final TypedBehaviourCallback holder) { + default M offerFrom(final BehaviourCallbackHolder holder) { Objects.requireNonNull(holder, "holder").callbacks().forEach(this::offer); - @SuppressWarnings("unchecked") - final M $this = (M) this; - return $this; + return this.cast(); + } + + default M offerFrom( + final BehaviourType> type, + final BehaviourCallbackHolder holder + ) { + Objects.requireNonNull(holder, "holder").callback(type).ifPresent(callback -> this.offer(type, callback)); + return this.cast(); + } + + default M offerFrom( + final BehaviourCallbackHolder holder, + final BehaviourType firstType, + final BehaviourType... otherTypes + ) { + this.offerFrom((BehaviourType>) firstType, holder); + for (final BehaviourType> type : Objects.requireNonNull(otherTypes, "otherTypes")) { + this.offerFrom((BehaviourType>) type, holder); + } + return this.cast(); + } + + default M offerFrom( + final BehaviourCallbackHolder holder, + final Iterable> types + ) { + for (final BehaviourType> type : Objects.requireNonNull(types, "types")) { + this.offerFrom((BehaviourType>) type, holder); + } + return this.cast(); } /** diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java index fac906d..0de7156 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java @@ -1,5 +1,6 @@ package net.hellheim.spongetools.custom.behaviour; +import java.util.Collection; import java.util.NoSuchElementException; import java.util.Optional; import java.util.function.Function; @@ -7,29 +8,83 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.Sponge; +import net.hellheim.spongetools.function.TriConsumer; + public interface BehaviourManager { static BehaviourManager get() { return Sponge.game().factoryProvider().provide(BehaviourManager.class); } - boolean supports(H holder, BehaviourType type); + boolean supportsBehaviour(H holder, BehaviourType type); - > Optional get(H holder, BehaviourType type); + > Optional behaviour(H holder, BehaviourType type); - default > B require(final H holder, final BehaviourType type) { - return this.get(holder, type).orElseThrow(() -> new NoSuchElementException(String.format( - "No behaviour of type %s is present for holder %s", - type, holder - ))); + default > B requireBehaviour( + final H holder, final BehaviourType type + ) { + return this.behaviour(holder, type) + .orElseThrow(() -> new NoSuchElementException(String.format( + "No behaviour of type %s is present for holder %s", + type, holder + ))); } - BehaviourRegistration create(Class holder); + + Collection> callbacks( + H behaviourHolder, Class callbackHolder + ); + + Optional> callback( + H behaviourHolder, Class callbackHolder, BehaviourType> type + ); + + BehaviourRegistration behaviour(Class behaviourHolder); interface BehaviourRegistration { + /** + * Registers behaviour provider + */ > BehaviourRegistration register( - BehaviourType type, Function behaviourProvider + BehaviourType type, + Function behaviourProvider ); + + CallbackRegistration callbacks(Class callbackHolder); + } + + interface CallbackRegistration { + + /** + * Registers behaviour callback provider + */ + CallbackRegistration register( + BehaviourType> type, + Function> callbackProvider + ); + + default
CallbackRegistration registerAction( + final BehaviourType> type, + final Function, A>> actionProvider + ) { + return this.register(type, behaviourHolder -> { + final @Nullable TriConsumer, A> action = actionProvider.apply(behaviourHolder); + return action == null ? null : (callbackHolder, origin, args) -> { + action.accept(callbackHolder, origin, args); + return null; + }; + }); + } + + default CallbackRegistration registerResult( + final BehaviourType> type, + final Function resultProvider + ) { + return this.register(type, behaviourHolder -> { + final @Nullable R result = resultProvider.apply(behaviourHolder); + return result == null ? null : (callbackHolder, origin, args) -> result; + }); + } } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java index 9bfb8a6..a8d9724 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java @@ -91,6 +91,8 @@ public final class BlockStateBehaviours { /** * Used to decide whether block should recieve natural random ticks. + * + * @see #RANDOM_TICK */ public static final BehaviourType HAS_RANDOM_TICK = BehaviourType.create(); diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java index 4ac14d5..e617d99 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java @@ -1,8 +1,8 @@ package net.hellheim.spongetools.custom.behaviour.type; +import java.util.Objects; import java.util.Optional; -import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; import net.hellheim.spongetools.custom.behaviour.Behaviour; @@ -21,7 +21,7 @@ public interface BlockStateExtension extends BlockStateProxy { static BlockStateExtension getFor(final BlockState state) { - return Sponge.game().factoryProvider().provide(Factory.class).getFor(state); + return (BlockStateExtension) Objects.requireNonNull(state, "state"); } BlockState state(); @@ -33,21 +33,16 @@ default BlockState getAsBlockState() { @Override default boolean supports(final BehaviourType type) { - return BehaviourManager.get().supports(this.state(), type); + return BehaviourManager.get().supportsBehaviour(this.state(), type); } @Override default > Optional get(final BehaviourType type) { - return BehaviourManager.get().get(this.state(), type); + return BehaviourManager.get().behaviour(this.state(), type); } @Override default > B require(final BehaviourType type) { - return BehaviourManager.get().require(this.state(), type); - } - - interface Factory { - - BlockStateExtension getFor(final BlockState state); + return BehaviourManager.get().requireBehaviour(this.state(), type); } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockTypeExtension.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockTypeExtension.java new file mode 100644 index 0000000..b093167 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockTypeExtension.java @@ -0,0 +1,49 @@ +package net.hellheim.spongetools.custom.behaviour.type; + +import java.util.Collection; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; + +import org.spongepowered.api.block.BlockType; + +import net.hellheim.spongetools.custom.behaviour.Behaviour; +import net.hellheim.spongetools.custom.behaviour.BehaviourArgs; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallback; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; +import net.hellheim.spongetools.custom.behaviour.BehaviourManager; +import net.hellheim.spongetools.custom.behaviour.BehaviourType; +import net.hellheim.spongetools.custom.behaviour.TypedBehaviourCallback; +import net.hellheim.spongetools.proxy.solid.block.BlockTypeProxy; + +public interface BlockTypeExtension extends + BehaviourCallbackHolder, + BlockTypeProxy { + + static BlockTypeExtension getFor(final BlockType block) { + return (BlockTypeExtension) Objects.requireNonNull(block, "block"); + } + + static BlockTypeExtension getFor(final Supplier blockSupplier) { + return BlockTypeExtension.getFor(Objects.requireNonNull(blockSupplier, "blockSupplier").get()); + } + + BlockType type(); + + @Override + default BlockType getAsBlockType() { + return this.type(); + } + + @Override + default Collection> callbacks() { + return BehaviourManager.get().callbacks(this.type(), BlockStateExtension.class); + } + + @Override + default Optional> callback( + final BehaviourType> type + ) { + return BehaviourManager.get().callback(this.type(), BlockStateExtension.class, type); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java index 94b29cc..6dc01d6 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java @@ -18,7 +18,7 @@ public interface InteractionResult { InteractionResult PASS = InteractionResult.factory().pass(); - InteractionResult TRY_EMPTY_HAND = InteractionResult.factory().tryEmptyHand(); + InteractionResult TRY_WITHOUT_ITEM = InteractionResult.factory().tryWithoutItem(); static InteractionResult.Success success(final SwingType swing, final boolean isInteraction) { return InteractionResult.success(swing, isInteraction, Optional.empty()); @@ -87,7 +87,7 @@ interface Factory { InteractionResult pass(); - InteractionResult tryEmptyHand(); + InteractionResult tryWithoutItem(); InteractionResult.Success success(SwingType swing, boolean isInteraction, Optional result); } diff --git a/src/main/java/net/hellheim/spongetools/custom/block/BasicCustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/block/BasicCustomBlockType.java index 7441332..d2d99ff 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/BasicCustomBlockType.java +++ b/src/main/java/net/hellheim/spongetools/custom/block/BasicCustomBlockType.java @@ -1,5 +1,8 @@ package net.hellheim.spongetools.custom.block; +import java.util.Objects; + +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.spongepowered.api.block.BlockState; import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; @@ -16,14 +19,14 @@ public class BasicCustomBlockType implements private final BehaviourCallbackHolderLogic callbacks; private final BlockStateProvider stateProvider; - private final BlockState state; - private final BlockStateExtension stateExtension; + private @MonotonicNonNull BlockState state; + private @MonotonicNonNull BlockStateExtension stateExtension; public BasicCustomBlockType(final CustomBlockTypeBuilder builder) { + Objects.requireNonNull(builder, "builder").validate(); this.callbacks = builder.callbacks.asImmutable(); this.stateProvider = builder.stateProvider; - this.state = this.stateProvider.provide(); - this.stateExtension = BlockStateExtension.getFor(this.state); + this.bind(this.stateProvider.provide()); } @Override @@ -32,8 +35,22 @@ public BlockStateProvider stateProvider() { } @Override - public BlockStateExtension stateExtension() { - return this.stateExtension; + public BlockState state() { + if (this.state == null) { + throw new IllegalStateException("State is not yet bound"); + } + + return this.state; + } + + @Override + public void bind(final BlockState state) { + if (this.state != null) { + throw new IllegalStateException("State is already bound"); + } + + this.state = Objects.requireNonNull(state, "state"); + this.stateExtension = BlockStateExtension.getFor(state); } @Override diff --git a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java b/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java index bb49753..2b277fb 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java +++ b/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java @@ -27,6 +27,14 @@ static Any any(final Collection providers) { return new Any(List.copyOf(providers)); } + static AnyState anyState(final BlockState... states) { + return new AnyState(Set.of(states)); + } + + static AnyState anyState(final Collection states) { + return new AnyState(Set.copyOf(states)); + } + @SafeVarargs static AnyBlock anyBlock(final Supplier... blocks) { return new AnyBlock(Arrays.stream(blocks).map(Supplier::get).collect(Collectors.toUnmodifiableSet())); @@ -86,6 +94,23 @@ public final String toString() { } } + record AnyState(Set states) implements BlockStateProvider { + + public AnyState(final Set states) { + this.states = Set.copyOf(states); + } + + @Override + public Stream allStates() { + return this.states.stream(); + } + + @Override + public String toString() { + return this.states.toString(); + } + } + record AnyBlock(Set blocks) implements BlockStateProvider { public AnyBlock(final Set blocks) { diff --git a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java index 993634f..623acc6 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java +++ b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java @@ -1,5 +1,7 @@ package net.hellheim.spongetools.custom.block; +import org.spongepowered.api.block.BlockState; + import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; @@ -8,5 +10,24 @@ public interface CustomBlockType extends BlockStateProvider stateProvider(); - BlockStateExtension stateExtension(); + /** + * @return The state bound to this block + * @throws IllegalStateException if state is not yet bound + * @see #bind(BlockState) + */ + BlockState state(); + + // TODO move the algorithm description to somewhere else. + /** + * Binds the state to this {@link CustomBlockType}.
+ * The state is chosen in a way where all registered + * {@link CustomBlockType}s get the appropriate result.
+ * If block is already used in the world, the used state would be provided.
+ * If block is not yet used in the world, the state would be chosen from {@link #stateProvider()}.
+ * If it's not possible to chose the state, TODO something is thrown. + * + * @param state The state to bind to this {@link CustomBlockType} + * @throws IllegalStateException if state is already bound + */ + void bind(BlockState state); } diff --git a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeBuilder.java b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeBuilder.java index 4071ac0..059ac84 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeBuilder.java +++ b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeBuilder.java @@ -1,12 +1,20 @@ package net.hellheim.spongetools.custom.block; +import java.util.Objects; +import java.util.function.Supplier; + import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockType; import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderLogic; import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderProxy; +import net.hellheim.spongetools.custom.behaviour.BehaviourType; import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; +import net.hellheim.spongetools.custom.behaviour.type.BlockTypeExtension; +@SuppressWarnings("unchecked") public class CustomBlockTypeBuilder> implements BehaviourCallbackHolderProxy.Mutable { @@ -17,7 +25,6 @@ public CustomBlockTypeBuilder() { this.reset(); } - @SuppressWarnings("unchecked") private B cast() { return (B) this; } @@ -27,12 +34,99 @@ private B cast() { return this.callbacks; } + // Overloads for #offerFrom + + public B offerFrom(final BlockState state) { + return this.offerFrom(BlockStateExtension.getFor(state)); + } + + public B offerFrom(final BlockType block) { + return this.offerFrom(BlockTypeExtension.getFor(block)); + } + + public B offerFrom(final Supplier blockSupplier) { + return this.offerFrom(BlockTypeExtension.getFor(blockSupplier)); + } + + public B offerFrom( + final BlockState state, + final BehaviourType firstType, + final BehaviourType... otherTypes + ) { + return this.offerFrom(BlockStateExtension.getFor(state), firstType, otherTypes); + } + + public B offerFrom( + final BlockType block, + final BehaviourType firstType, + final BehaviourType... otherTypes + ) { + return this.offerFrom(BlockTypeExtension.getFor(block), firstType, otherTypes); + } + + public B offerFrom( + final Supplier blockSupplier, + final BehaviourType firstType, + final BehaviourType... otherTypes + ) { + return this.offerFrom(BlockTypeExtension.getFor(blockSupplier), firstType, otherTypes); + } + + public B offerFrom( + final BlockState state, + final Iterable> types + ) { + return this.offerFrom(BlockStateExtension.getFor(state), types); + } + + public B offerFrom( + final BlockType block, + final Iterable> types + ) { + return this.offerFrom(BlockTypeExtension.getFor(block), types); + } + + public B offerFrom( + final Supplier blockSupplier, + final Iterable> types + ) { + return this.offerFrom(BlockTypeExtension.getFor(blockSupplier), types); + } + + // StateProvider setters + + public B state(final BlockStateProvider stateProvider) { + this.stateProvider = Objects.requireNonNull(stateProvider, "stateProvider"); + return this.cast(); + } + + public B state(final BlockState state) { + return this.state(BlockStateProvider.anyState(state)); + } + + public B defaultState(final BlockType block) { + return this.state(Objects.requireNonNull(block, "block").defaultState()); + } + + public B defaultState(final Supplier blockSupplier) { + return this.defaultState(Objects.requireNonNull(blockSupplier, "blockSupplier").get()); + } + + public B reset() { this.callbacks = BehaviourCallbackHolderLogic.mutable(); this.stateProvider = null; return this.cast(); } + public B validate() { + if (this.stateProvider == null) { + throw new IllegalArgumentException("stateProvider must be set"); + } + + return this.cast(); + } + public CustomBlockType build() { return new BasicCustomBlockType(this); } diff --git a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemType.java b/src/main/java/net/hellheim/spongetools/custom/item/CustomItemType.java index 97976b0..6bd501d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/item/CustomItemType.java @@ -23,8 +23,8 @@ import net.hellheim.spongetools.SpongeTools; import net.hellheim.spongetools.codec.list.RegistryCodecs; -import net.hellheim.spongetools.custom.model.item.Item; import net.hellheim.spongetools.proxy.solid.item.ItemStackSnapshotProxy; +import net.hellheim.spongetools.resourcepack.item.Item; import net.kyori.adventure.text.ComponentLike; public interface CustomItemType extends diff --git a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemTypeProperties.java b/src/main/java/net/hellheim/spongetools/custom/item/CustomItemTypeProperties.java index 6bcfd02..77a24cd 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemTypeProperties.java +++ b/src/main/java/net/hellheim/spongetools/custom/item/CustomItemTypeProperties.java @@ -26,14 +26,14 @@ import com.mojang.serialization.codecs.RecordCodecBuilder.Mu; import net.hellheim.spongetools.codec.list.SpongeCodecs; -import net.hellheim.spongetools.custom.model.item.Item; -import net.hellheim.spongetools.custom.model.item.ItemDefinition; -import net.hellheim.spongetools.custom.model.item.TintSource; import net.hellheim.spongetools.object.DeferredValueContainer; import net.hellheim.spongetools.object.ItemBuilder; import net.hellheim.spongetools.object.ValueSetBuilder; import net.hellheim.spongetools.proxy.solid.data.ValueContainerProxy; import net.hellheim.spongetools.proxy.solid.item.ItemStackSnapshotProxy; +import net.hellheim.spongetools.resourcepack.item.Item; +import net.hellheim.spongetools.resourcepack.item.ItemDefinition; +import net.hellheim.spongetools.resourcepack.item.TintSource; import net.hellheim.spongetools.util.TranslationUtil; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.ComponentLike; diff --git a/src/main/java/net/hellheim/spongetools/custom/item/IDefaultedCustomItemType.java b/src/main/java/net/hellheim/spongetools/custom/item/IDefaultedCustomItemType.java index 1db10bd..4b4631f 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/IDefaultedCustomItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/item/IDefaultedCustomItemType.java @@ -7,9 +7,9 @@ import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.registry.DefaultedRegistryReference; -import net.hellheim.spongetools.custom.model.item.Item; import net.hellheim.spongetools.object.DeferredValueContainer; import net.hellheim.spongetools.proxy.solid.data.ValueContainerProxy; +import net.hellheim.spongetools.resourcepack.item.Item; import net.kyori.adventure.text.Component; public interface IDefaultedCustomItemType extends CustomItemType, ValueContainerProxy { diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java b/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java index 548bb95..4345d6b 100644 --- a/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java +++ b/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java @@ -9,7 +9,7 @@ public interface RegisterBehaviourDataEvent extends LifecycleEvent { BehaviourManager manager(); - default BehaviourRegistration create(final Class holder) { - return this.manager().create(holder); + default BehaviourRegistration behaviour(final Class holder) { + return this.manager().behaviour(holder); } } diff --git a/src/main/java/net/hellheim/spongetools/function/QuinFunction.java b/src/main/java/net/hellheim/spongetools/function/QuinFunction.java new file mode 100644 index 0000000..2594552 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/function/QuinFunction.java @@ -0,0 +1,15 @@ +package net.hellheim.spongetools.function; + +import java.util.Objects; +import java.util.function.Function; + +@FunctionalInterface +public interface QuinFunction { + + R apply(F f, S s, T t, E e, B b); + + default QuinFunction andThen(final Function after) { + Objects.requireNonNull(after); + return (F f, S s, T t, E e, B b) -> after.apply(apply(f, s, t, e, b)); + } +} diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/block/StateContainerProxy.java b/src/main/java/net/hellheim/spongetools/proxy/solid/block/StateContainerProxy.java new file mode 100644 index 0000000..49dff14 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/proxy/solid/block/StateContainerProxy.java @@ -0,0 +1,34 @@ +package net.hellheim.spongetools.proxy.solid.block; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import org.spongepowered.api.state.State; +import org.spongepowered.api.state.StateContainer; +import org.spongepowered.api.state.StateProperty; + +public interface StateContainerProxy> extends StateContainer { + + StateContainer getAsStateContainer(); + + @Override + default List validStates() { + return this.getAsStateContainer().validStates(); + } + + @Override + default S defaultState() { + return this.getAsStateContainer().defaultState(); + } + + @Override + default Collection> stateProperties() { + return this.getAsStateContainer().stateProperties(); + } + + @Override + default Optional> findStateProperty(final String name) { + return this.getAsStateContainer().findStateProperty(name); + } +} diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/codec/DynamicOpsProxy.java b/src/main/java/net/hellheim/spongetools/proxy/solid/codec/DynamicOpsProxy.java new file mode 100644 index 0000000..ff9d9fe --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/proxy/solid/codec/DynamicOpsProxy.java @@ -0,0 +1,280 @@ +package net.hellheim.spongetools.proxy.solid.codec; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.IntStream; +import java.util.stream.LongStream; +import java.util.stream.Stream; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Decoder; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Encoder; +import com.mojang.serialization.ListBuilder; +import com.mojang.serialization.MapLike; +import com.mojang.serialization.RecordBuilder; + +public interface DynamicOpsProxy extends DynamicOps { + + DynamicOps getAsOps(); + + @Override + default T empty() { + return this.getAsOps().empty(); + } + + @Override + default T emptyMap() { + return this.getAsOps().emptyMap(); + } + + @Override + default T emptyList() { + return this.getAsOps().emptyList(); + } + + @Override + default U convertTo(final DynamicOps outOps, final T input) { + return this.getAsOps().convertTo(outOps, input); + } + + @Override + default DataResult getNumberValue(final T input) { + return this.getAsOps().getNumberValue(input); + } + + @Override + default Number getNumberValue(final T input, final Number defaultValue) { + return this.getAsOps().getNumberValue(input, defaultValue); + } + + @Override + default T createNumeric(final Number i) { + return this.getAsOps().createNumeric(i); + } + + @Override + default T createByte(final byte value) { + return this.getAsOps().createByte(value); + } + + @Override + default T createShort(final short value) { + return this.getAsOps().createShort(value); + } + + @Override + default T createInt(final int value) { + return this.getAsOps().createInt(value); + } + + @Override + default T createLong(final long value) { + return this.getAsOps().createLong(value); + } + + @Override + default T createFloat(final float value) { + return this.getAsOps().createFloat(value); + } + + @Override + default T createDouble(final double value) { + return this.getAsOps().createDouble(value); + } + + @Override + default DataResult getBooleanValue(final T input) { + return this.getAsOps().getBooleanValue(input); + } + + @Override + default T createBoolean(final boolean value) { + return this.getAsOps().createBoolean(value); + } + + @Override + default DataResult getStringValue(final T input) { + return this.getAsOps().getStringValue(input); + } + + @Override + default T createString(final String value) { + return this.getAsOps().createString(value); + } + + @Override + default DataResult mergeToList(final T list, final T value) { + return this.getAsOps().mergeToList(list, value); + } + + @Override + default DataResult mergeToList(final T list, final List values) { + return this.getAsOps().mergeToList(list, values); + } + + @Override + default DataResult mergeToMap(final T map, final T key, final T value) { + return this.getAsOps().mergeToMap(map, key, value); + } + + @Override + default DataResult mergeToMap(final T map, final Map values) { + return this.getAsOps().mergeToMap(map, values); + } + + @Override + default DataResult mergeToMap(final T map, final MapLike values) { + return this.getAsOps().mergeToMap(map, values); + } + + @Override + default DataResult mergeToPrimitive(final T prefix, final T value) { + return this.getAsOps().mergeToPrimitive(prefix, value); + } + + @Override + default DataResult>> getMapValues(final T input) { + return this.getAsOps().getMapValues(input); + } + + @Override + default DataResult>> getMapEntries(final T input) { + return this.getAsOps().getMapEntries(input); + } + + @Override + default T createMap(final Stream> map) { + return this.getAsOps().createMap(map); + } + + @Override + default DataResult> getMap(final T input) { + return this.getAsOps().getMap(input); + } + + @Override + default T createMap(final Map map) { + return this.getAsOps().createMap(map); + } + + @Override + default DataResult> getStream(final T input) { + return this.getAsOps().getStream(input); + } + + @Override + default DataResult>> getList(final T input) { + return this.getAsOps().getList(input); + } + + @Override + default T createList(final Stream input) { + return this.getAsOps().createList(input); + } + + @Override + default DataResult getByteBuffer(final T input) { + return this.getAsOps().getByteBuffer(input); + } + + @Override + default T createByteList(final ByteBuffer input) { + return this.getAsOps().createByteList(input); + } + + @Override + default DataResult getIntStream(final T input) { + return this.getAsOps().getIntStream(input); + } + + @Override + default T createIntList(final IntStream input) { + return this.getAsOps().createIntList(input); + } + + @Override + default DataResult getLongStream(final T input) { + return this.getAsOps().getLongStream(input); + } + + @Override + default T createLongList(final LongStream input) { + return this.getAsOps().createLongList(input); + } + + @Override + default T remove(final T input, final String key) { + return this.getAsOps().remove(input, key); + } + + @Override + default boolean compressMaps() { + return this.getAsOps().compressMaps(); + } + + @Override + default DataResult get(final T input, final String key) { + return this.getAsOps().get(input, key); + } + + @Override + default DataResult getGeneric(final T input, final T key) { + return this.getAsOps().getGeneric(input, key); + } + + @Override + default T set(final T input, final String key, final T value) { + return this.getAsOps().set(input, key, value); + } + + @Override + default T update(final T input, final String key, final Function function) { + return this.getAsOps().update(input, key, function); + } + + @Override + default T updateGeneric(final T input, final T key, final Function function) { + return this.getAsOps().updateGeneric(input, key, function); + } + + @Override + default ListBuilder listBuilder() { + return this.getAsOps().listBuilder(); + } + + @Override + default RecordBuilder mapBuilder() { + return this.getAsOps().mapBuilder(); + } + + @Override + default Function> withEncoder(final Encoder encoder) { + return this.getAsOps().withEncoder(encoder); + } + + @Override + default Function>> withDecoder(final Decoder decoder) { + return this.getAsOps().withDecoder(decoder); + } + + @Override + default Function> withParser(final Decoder decoder) { + return this.getAsOps().withParser(decoder); + } + + @Override + default U convertList(final DynamicOps outOps, final T input) { + return this.getAsOps().convertList(outOps, input); + } + + @Override + default U convertMap(final DynamicOps outOps, final T input) { + return this.getAsOps().convertMap(outOps, input); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/model/ModelTemplate.java b/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplate.java similarity index 95% rename from src/main/java/net/hellheim/spongetools/custom/model/ModelTemplate.java rename to src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplate.java index e18a475..2da4676 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/ModelTemplate.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplate.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model; +package net.hellheim.spongetools.resourcepack; import java.util.Collection; import java.util.List; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/ModelTemplateProvider.java b/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplateProvider.java similarity index 99% rename from src/main/java/net/hellheim/spongetools/custom/model/ModelTemplateProvider.java rename to src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplateProvider.java index 02032f2..eef11ee 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/ModelTemplateProvider.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplateProvider.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model; +package net.hellheim.spongetools.resourcepack; import java.util.List; import java.util.Objects; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/ModelTemplates.java b/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplates.java similarity index 99% rename from src/main/java/net/hellheim/spongetools/custom/model/ModelTemplates.java rename to src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplates.java index e73114a..7ace67d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/ModelTemplates.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplates.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model; +package net.hellheim.spongetools.resourcepack; import java.util.List; import java.util.Optional; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/TextureSlot.java b/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java similarity index 95% rename from src/main/java/net/hellheim/spongetools/custom/model/TextureSlot.java rename to src/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java index 3ebf54a..cc00a41 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/TextureSlot.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model; +package net.hellheim.spongetools.resourcepack; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/TextureSlots.java b/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java similarity index 97% rename from src/main/java/net/hellheim/spongetools/custom/model/TextureSlots.java rename to src/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java index 2a081b4..627ccc1 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/TextureSlots.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model; +package net.hellheim.spongetools.resourcepack; import java.util.Optional; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/TexturedModel.java b/src/main/java/net/hellheim/spongetools/resourcepack/TexturedModel.java similarity index 98% rename from src/main/java/net/hellheim/spongetools/custom/model/TexturedModel.java rename to src/main/java/net/hellheim/spongetools/resourcepack/TexturedModel.java index cd80557..4fb08c0 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/TexturedModel.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/TexturedModel.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model; +package net.hellheim.spongetools.resourcepack; import java.util.Collection; import java.util.List; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/Textures.java b/src/main/java/net/hellheim/spongetools/resourcepack/Textures.java similarity index 99% rename from src/main/java/net/hellheim/spongetools/custom/model/Textures.java rename to src/main/java/net/hellheim/spongetools/resourcepack/Textures.java index 0ab5f30..6317ed4 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/Textures.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/Textures.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model; +package net.hellheim.spongetools.resourcepack; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java new file mode 100644 index 0000000..5218a2e --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java @@ -0,0 +1,168 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.state.StateContainer; +import org.spongepowered.api.state.StateProperty; +import org.spongepowered.api.util.CopyableBuilder; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +public interface BlockDefinition { + + static MultiVariant.Builder multiVariant(final Supplier> containerSupplier) { + return BlockDefinition.multiVariant(Objects.requireNonNull(containerSupplier, "containerSupplier").get()); + } + + static MultiVariant.Builder multiVariant(final StateContainer container) { + return new MultiVariant.Builder(containerSupplier); + } + + final record MultiVariant(StateDispatch dispatch) implements BlockDefinition { + + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + StateDispatch.CODEC.fieldOf("variants").forGetter(null) + ).apply(null, null)).validate(null); + + public MultiVariant(final StateDispatch dispatch) { + this.dispatch = Objects.requireNonNull(dispatch, "dispatch"); + } + + public Builder toBuilder(final StateContainer container) { + return BlockDefinition.multiVariant(container).from(this); + } + + public MultiVariant withDispatch(final UnaryOperator dispatchOperator) { + Objects.requireNonNull(dispatchOperator, "dispatchOperator"); + return new MultiVariant(this.block, dispatchOperator.apply(this.dispatch)); + } + + public static final class Builder implements BlockDefinition.Builder { + + private final StateContainer container; + private final List baseVariants = new ArrayList<>(); + private final List dispatches = new ArrayList<>(); + private final Set> seenProperties = new HashSet<>(); + + private Builder(StateContainer container) { + this.container = Objects.requireNonNull(container, "container"); + this.reset(); + } + + public Builder base(final Variant... variants) { + for (final Variant variant : Objects.requireNonNull(variants, "variants")) { + this.baseVariants.add(Objects.requireNonNull(variant, "variant")); + } + return this; + } + + public Builder base(final Iterable variants) { + for (final Variant variant : Objects.requireNonNull(variants, "variants")) { + this.baseVariants.add(Objects.requireNonNull(variant, "variant")); + } + return this; + } + + public Builder dispatch(final StateDispatch.Builder... builders) { + for (final StateDispatch.Builder builder : Objects.requireNonNull(builders, "builders")) { + this.tryDispatch(Objects.requireNonNull(builder, "builder").build()); + } + return this; + } + + public Builder dispatch(final StateDispatch... dispatches) { + for (final StateDispatch dispatch : Objects.requireNonNull(dispatches, "dispatches")) { + this.tryDispatch(dispatch); + } + return this; + } + + public Builder dispatch(final Iterable dispatches) { + for (final StateDispatch dispatch : Objects.requireNonNull(dispatches, "dispatches")) { + this.tryDispatch(dispatch); + } + return this; + } + + private void tryDispatch(final StateDispatch dispatch) { + Objects.requireNonNull(dispatch, "dispatch"); + for (final StateProperty property : dispatch.properties()) { + if (this.container.findStateProperty(property.name()).orElse(null) != property) { + throw new IllegalStateException("Property " + property + " is not defined for container " + this.container); + } else if (!this.seenProperties.add(property)) { + throw new IllegalStateException("Values of property " + property + " already defined for container " + this.container); + } + } + + this.dispatches.add(dispatch); + } + + @Override + public Builder from(final MultiVariant definition) { + return this.reset().dispatch(Objects.requireNonNull(definition, "definition").dispatch()); + } + + @Override + public Builder reset() { + this.baseVariants.clear(); + this.dispatches.clear(); + this.seenProperties.clear(); + return this; + } + + @Override + public MultiVariant build() { + Stream>> stream = Stream.of(Pair.of(StateSelector.empty(), this.baseVariants)); + for (final StateDispatch dispatch : this.dispatches) { + final Map> values = dispatch.values(); + stream = stream.flatMap(pair -> { + return values.entrySet().stream().map(entry -> { + final StateSelector selector = pair.getFirst().with(entry.getKey()); + final List variants = mergeVariants(pair.getSecond(), entry.getValue()); + return Pair.of(selector, variants); + }); + }); + } + + final var builder = StateDispatch.raw(); + stream.forEach(pair -> builder.add(pair.getFirst(), pair.getSecond())); + return new MultiVariant(builder.build()); + } + + private static List mergeVariants( + final List firstVariants, final List secondVariants + ) { + final List variants = new ArrayList<>(); + firstVariants.forEach(first -> + secondVariants.forEach(second -> + variants.add(first.with(second)))); + return variants; + } + } + } + + record MultiPart() implements BlockDefinition { + + + + } + + interface Builder> extends + org.spongepowered.api.util.Builder, + CopyableBuilder> { + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java new file mode 100644 index 0000000..1240332 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java @@ -0,0 +1,122 @@ +package net.hellheim.spongetools.resourcepack.block; + + +import java.util.Iterator; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.state.StateContainer; +import org.spongepowered.api.state.StateProperty; + +import com.google.common.base.Splitter; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; + +import net.hellheim.spongetools.resourcepack.block.StateSelector.Builder; + +interface StateCodec
extends Codec { + + Codec> STATE_PROPERTY_VALUE = new StateCodec<>() { + @Override + public DataResult encode( + final StatePropertyValue input, final DynamicOps ops, final T prefix + ) { + return DataResult.success(ops.createString(input.serializationString())); + } + + @Override + public DataResult, T>> read( + final StateOps ops, final T input + ) { + return ops.getStringValue(input).flatMap(fullProperty -> + StateCodec.decodePropertyValue(ops, fullProperty) + .map(value -> Pair.of(value, ops.empty()))); + } + }; + + Codec STATE_SELECTOR = new StateCodec<>() { + @Override + public DataResult encode( + final StateSelector input, final DynamicOps ops, final T prefix + ) { + return DataResult.success(ops.createString(input.serializationString())); + } + + @Override + public DataResult> read( + final StateOps ops, final T input + ) { + return ops.getStringValue(input).flatMap(selector -> + StateCodec.decodeSelector(ops, selector) + .map(value -> Pair.of(value, ops.empty()))); + } + }; + + Splitter COMMA_SPLITTER = Splitter.on(','); + Splitter EQUAL_SPLITTER = Splitter.on('=').limit(2); + + DataResult> read(StateOps ops, T input); + + @Override + default DataResult> decode(final DynamicOps ops, final T input) { + return ops instanceof final StateOps stateOps + ? this.read(stateOps, input) + : DataResult.error(() -> "Not a StateOps"); + } + + static DataResult decodeSelector(final StateContainer container, final String selector) { + final Builder builder = StateSelector.builder(); + for (final String property : COMMA_SPLITTER.split(selector)) { + final var value = StateCodec.decodePropertyValue(container, property); + if (value.isError()) { + return DataResult.error(value.error().get().messageSupplier(), builder.build()); + } + + builder.add(value.result().get()); + } + + return DataResult.success(builder.build()); + } + + static DataResult> decodePropertyValue( + final StateContainer container, final String fullProperty + ) { + final Iterator propertyData = EQUAL_SPLITTER.split(fullProperty).iterator(); + + final String propertyString = propertyData.next(); + if (propertyString.isEmpty()) { + return DataResult.error(() -> "Empty state property"); + } + + final @Nullable StateProperty property = container.findStateProperty(propertyString).orElse(null); + if (property == null) { + return DataResult.error(() -> String.format( + "Unknown state property: '%s'", + propertyString + )); + } + + if (!propertyData.hasNext()) { + return DataResult.error(() -> String.format( + "State property without value: %s", + propertyString + )); + } + + final String valueString = propertyData.next(); + if (valueString.isEmpty()) { + return DataResult.error(() -> "Empty state property value"); + } + + final @Nullable Comparable value = property.parseValue(valueString).orElse(null); + if (value == null) { + return DataResult.error(() -> String.format( + "Unknown value: '%s' for state property: '%s' %s", + valueString, propertyString, property.possibleValues() + )); + } + + return DataResult.success(StatePropertyValue.ofRaw(property, value)); + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java new file mode 100644 index 0000000..4c03196 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java @@ -0,0 +1,48 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.List; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.Encoder; + +import net.hellheim.spongetools.proxy.solid.codec.EncoderProxy; + +public interface StateCondition extends EncoderProxy { + + record AndCondition(List conditions) implements StateCondition { + + public static final Encoder ENCODER = Codec + + public AndCondition(final List conditions) { + this.conditions = List.copyOf(conditions); + } + + @Override + public Encoder codec() { + // TODO Auto-generated method stub + return null; + } + } + + record OrCondition(List conditions) implements StateCondition { + + public OrCondition(final List conditions) { + this.conditions = List.copyOf(conditions); + } + + @Override + public Encoder codec() { + // TODO Auto-generated method stub + return null; + } + } + + record PropertyCondition() implements StateCondition { + + @Override + public Encoder codec() { + // TODO Auto-generated method stub + return null; + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java new file mode 100644 index 0000000..c982539 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java @@ -0,0 +1,716 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.spongepowered.api.state.State; +import org.spongepowered.api.state.StateProperty; +import org.spongepowered.api.util.CopyableBuilder; + +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.function.QuadFunction; +import net.hellheim.spongetools.function.QuinFunction; +import net.hellheim.spongetools.function.TriFunction; + +public class StateDispatch { + + public static final Codec CODEC = Codec + .unboundedMap(StateSelector.CODEC, Variant.CODEC.listOf()) + .xmap(StateDispatch::new, StateDispatch::values); + + private final Set> properties; + private final Map> values; + + protected StateDispatch(final Map> values) { + this(values, values.keySet().stream() + .flatMap(selector -> selector.properties().stream()) + .collect(Collectors.toSet())); + } + + protected StateDispatch(final Map> values, final Set> properties) { + this.values = Map.copyOf(values); + this.properties = Set.copyOf(properties); + } + + public static StateDispatch of(final Variant... variants) { + return StateDispatch.raw().add(StateSelector.empty(), variants).build(); + } + + public static StateDispatch of(final Collection variants) { + return StateDispatch.raw().add(StateSelector.empty(), variants).build(); + } + + public static Builder raw() { + return new Builder<>(); + } + + public static < + T1 extends Comparable> + P1.Builder of( + final StateProperty p1 + ) { + return new P1.Builder<>(p1); + } + + public static < + T1 extends Comparable, + T2 extends Comparable> + P2.Builder of( + final StateProperty p1, + final StateProperty p2 + ) { + return new P2.Builder<>(p1, p2); + } + + public static < + T1 extends Comparable, + T2 extends Comparable, + T3 extends Comparable> + P3.Builder of( + final StateProperty p1, + final StateProperty p2, + final StateProperty p3 + ) { + return new P3.Builder<>(p1, p2, p3); + } + + public static < + T1 extends Comparable, + T2 extends Comparable, + T3 extends Comparable, + T4 extends Comparable> + P4.Builder of( + final StateProperty p1, + final StateProperty p2, + final StateProperty p3, + final StateProperty p4 + ) { + return new P4.Builder<>(p1, p2, p3, p4); + } + + public static < + T1 extends Comparable, + T2 extends Comparable, + T3 extends Comparable, + T4 extends Comparable, + T5 extends Comparable> + P5.Builder of( + final StateProperty p1, + final StateProperty p2, + final StateProperty p3, + final StateProperty p4, + final StateProperty p5 + ) { + return new P5.Builder<>(p1, p2, p3, p4, p5); + } + + public Set> properties() { + return this.properties; + } + + public Set selectors() { + return this.values.keySet(); + } + + public Map> values() { + return this.values; + } + + public Builder toBuilder() { + return StateDispatch.raw().from(this); + } + + public static final class P1< + T1 extends Comparable> + extends StateDispatch { + + private final StateProperty p1; + + private P1( + final Map> values, + final Set> properties, + final StateProperty p1 + ) { + super(values, properties); + this.p1 = p1; + } + + @Override + public Builder toBuilder() { + return StateDispatch.of(this.p1); + } + + public static final class Builder< + T1 extends Comparable> + extends StateDispatch.Builder> { + + private final StateProperty p1; + + private Builder( + final StateProperty p1 + ) { + this.p1 = Objects.requireNonNull(p1, "property"); + } + + public Builder add(final T1 v1, final Variant... variants) { + return this.add(StateSelector.builder().add(this.p1, v1), variants); + } + + public Builder add(final T1 v1, final Collection variants) { + return this.add(StateSelector.builder().add(this.p1, v1), variants); + } + + public Builder generate(final Function generator) { + Objects.requireNonNull(generator, "generator"); + this.p1.possibleValues().forEach(v1 -> + this.add(v1, generator.apply(v1))); + return this; + } + + public Builder generateList(final Function> generator) { + Objects.requireNonNull(generator, "generator"); + this.p1.possibleValues().forEach(v1 -> + this.add(v1, generator.apply(v1))); + return this; + } + + @Override + public P1 build() { + this.validate(); + return new P1<>(this.values, this.properties, this.p1); + } + } + } + + public static final class P2< + T1 extends Comparable, + T2 extends Comparable> + extends StateDispatch { + + private final StateProperty p1; + private final StateProperty p2; + + private P2( + final Map> values, + final Set> properties, + final StateProperty p1, + final StateProperty p2 + ) { + super(values, properties); + this.p1 = p1; + this.p2 = p2; + } + + @Override + public Builder toBuilder() { + return StateDispatch.of(this.p1, this.p2); + } + + public static final class Builder< + T1 extends Comparable, + T2 extends Comparable> + extends StateDispatch.Builder> { + + private final StateProperty p1; + private final StateProperty p2; + + private Builder( + final StateProperty p1, + final StateProperty p2 + ) { + this.p1 = Objects.requireNonNull(p1, "property1"); + this.p2 = Objects.requireNonNull(p2, "property2"); + } + + public Builder add(final T1 v1, final T2 v2, final Variant... variants) { + return this.add(StateSelector.builder().add(this.p1, v1).add(this.p2, v2), variants); + } + + public Builder add(final T1 v1, final T2 v2, final Collection variants) { + return this.add(StateSelector.builder().add(this.p1, v1).add(this.p2, v2), variants); + } + + public Builder generate(final BiFunction generator) { + Objects.requireNonNull(generator, "generator"); + this.p1.possibleValues().forEach(v1 -> + this.p2.possibleValues().forEach(v2 -> + this.add(v1, v2, generator.apply(v1, v2)))); + return this; + } + + public Builder generateList(final BiFunction> generator) { + Objects.requireNonNull(generator, "generator"); + this.p1.possibleValues().forEach(v1 -> + this.p2.possibleValues().forEach(v2 -> + this.add(v1, v2, generator.apply(v1, v2)))); + return this; + } + + @Override + public P2 build() { + this.validate(); + return new P2<>(this.values, this.properties, this.p1, this.p2); + } + } + } + + public static final class P3< + T1 extends Comparable, + T2 extends Comparable, + T3 extends Comparable> + extends StateDispatch { + + private final StateProperty p1; + private final StateProperty p2; + private final StateProperty p3; + + private P3( + final Map> values, + final Set> properties, + final StateProperty p1, + final StateProperty p2, + final StateProperty p3 + ) { + super(values, properties); + this.p1 = p1; + this.p2 = p2; + this.p3 = p3; + } + + @Override + public Builder toBuilder() { + return StateDispatch.of(this.p1, this.p2, this.p3); + } + + public static final class Builder< + T1 extends Comparable, + T2 extends Comparable, + T3 extends Comparable> + extends StateDispatch.Builder> { + + private final StateProperty p1; + private final StateProperty p2; + private final StateProperty p3; + + private Builder( + final StateProperty p1, + final StateProperty p2, + final StateProperty p3 + ) { + this.p1 = Objects.requireNonNull(p1, "property1"); + this.p2 = Objects.requireNonNull(p2, "property2"); + this.p3 = Objects.requireNonNull(p3, "property3"); + } + + public Builder add(final T1 v1, final T2 v2, final T3 v3, final Variant... variants) { + return this.add(StateSelector.builder().add(this.p1, v1).add(this.p2, v2).add(this.p3, v3), variants); + } + + public Builder add(final T1 v1, final T2 v2, final T3 v3, final Collection variants) { + return this.add(StateSelector.builder().add(this.p1, v1).add(this.p2, v2).add(this.p3, v3), variants); + } + + public Builder generate(final TriFunction generator) { + Objects.requireNonNull(generator, "generator"); + this.p1.possibleValues().forEach(v1 -> + this.p2.possibleValues().forEach(v2 -> + this.p3.possibleValues().forEach(v3 -> + this.add(v1, v2, v3, generator.apply(v1, v2, v3))))); + return this; + } + + public Builder generateList(final TriFunction> generator) { + Objects.requireNonNull(generator, "generator"); + this.p1.possibleValues().forEach(v1 -> + this.p2.possibleValues().forEach(v2 -> + this.p3.possibleValues().forEach(v3 -> + this.add(v1, v2, v3, generator.apply(v1, v2, v3))))); + return this; + } + + @Override + public P3 build() { + this.validate(); + return new P3<>(this.values, this.properties, this.p1, this.p2, this.p3); + } + } + } + + public static final class P4< + T1 extends Comparable, + T2 extends Comparable, + T3 extends Comparable, + T4 extends Comparable> + extends StateDispatch { + + private final StateProperty p1; + private final StateProperty p2; + private final StateProperty p3; + private final StateProperty p4; + + private P4( + final Map> values, + final Set> properties, + final StateProperty p1, + final StateProperty p2, + final StateProperty p3, + final StateProperty p4 + ) { + super(values, properties); + this.p1 = p1; + this.p2 = p2; + this.p3 = p3; + this.p4 = p4; + } + + @Override + public Builder toBuilder() { + return StateDispatch.of(this.p1, this.p2, this.p3, this.p4); + } + + public static final class Builder< + T1 extends Comparable, + T2 extends Comparable, + T3 extends Comparable, + T4 extends Comparable> + extends StateDispatch.Builder> { + + private final StateProperty p1; + private final StateProperty p2; + private final StateProperty p3; + private final StateProperty p4; + + private Builder( + final StateProperty p1, + final StateProperty p2, + final StateProperty p3, + final StateProperty p4 + ) { + this.p1 = Objects.requireNonNull(p1, "property1"); + this.p2 = Objects.requireNonNull(p2, "property2"); + this.p3 = Objects.requireNonNull(p3, "property3"); + this.p4 = Objects.requireNonNull(p4, "property4"); + } + + public Builder add(final T1 v1, final T2 v2, final T3 v3, final T4 v4, final Variant... variants) { + return this.add(StateSelector.builder().add(this.p1, v1).add(this.p2, v2).add(this.p3, v3).add(this.p4, v4), variants); + } + + public Builder add(final T1 v1, final T2 v2, final T3 v3, final T4 v4, final Collection variants) { + return this.add(StateSelector.builder().add(this.p1, v1).add(this.p2, v2).add(this.p3, v3).add(this.p4, v4), variants); + } + + public Builder generate(final QuadFunction generator) { + Objects.requireNonNull(generator, "generator"); + this.p1.possibleValues().forEach(v1 -> + this.p2.possibleValues().forEach(v2 -> + this.p3.possibleValues().forEach(v3 -> + this.p4.possibleValues().forEach(v4 -> + this.add(v1, v2, v3, v4, generator.apply(v1, v2, v3, v4)))))); + return this; + } + + public Builder generateList(final QuadFunction> generator) { + Objects.requireNonNull(generator, "generator"); + this.p1.possibleValues().forEach(v1 -> + this.p2.possibleValues().forEach(v2 -> + this.p3.possibleValues().forEach(v3 -> + this.p4.possibleValues().forEach(v4 -> + this.add(v1, v2, v3, v4, generator.apply(v1, v2, v3, v4)))))); + return this; + } + + @Override + public P4 build() { + this.validate(); + return new P4<>(this.values, this.properties, this.p1, this.p2, this.p3, this.p4); + } + } + } + + public static final class P5< + T1 extends Comparable, + T2 extends Comparable, + T3 extends Comparable, + T4 extends Comparable, + T5 extends Comparable> + extends StateDispatch { + + private final StateProperty p1; + private final StateProperty p2; + private final StateProperty p3; + private final StateProperty p4; + private final StateProperty p5; + + private P5( + final Map> values, + final Set> properties, + final StateProperty p1, + final StateProperty p2, + final StateProperty p3, + final StateProperty p4, + final StateProperty p5 + ) { + super(values, properties); + this.p1 = p1; + this.p2 = p2; + this.p3 = p3; + this.p4 = p4; + this.p5 = p5; + } + + @Override + public Builder toBuilder() { + return StateDispatch.of(this.p1, this.p2, this.p3, this.p4, this.p5); + } + + public static final class Builder< + T1 extends Comparable, + T2 extends Comparable, + T3 extends Comparable, + T4 extends Comparable, + T5 extends Comparable> + extends StateDispatch.Builder> { + + private final StateProperty p1; + private final StateProperty p2; + private final StateProperty p3; + private final StateProperty p4; + private final StateProperty p5; + + private Builder( + final StateProperty p1, + final StateProperty p2, + final StateProperty p3, + final StateProperty p4, + final StateProperty p5 + ) { + this.p1 = Objects.requireNonNull(p1, "property1"); + this.p2 = Objects.requireNonNull(p2, "property2"); + this.p3 = Objects.requireNonNull(p3, "property3"); + this.p4 = Objects.requireNonNull(p4, "property4"); + this.p5 = Objects.requireNonNull(p5, "property5"); + } + + public Builder add(final T1 v1, final T2 v2, final T3 v3, final T4 v4, final T5 v5, final Variant... variants) { + return this.add(StateSelector.builder().add(this.p1, v1).add(this.p2, v2).add(this.p3, v3).add(this.p4, v4).add(this.p5, v5), variants); + } + + public Builder add(final T1 v1, final T2 v2, final T3 v3, final T4 v4, final T5 v5, final Collection variants) { + return this.add(StateSelector.builder().add(this.p1, v1).add(this.p2, v2).add(this.p3, v3).add(this.p4, v4), variants); + } + + public Builder generate(final QuinFunction generator) { + Objects.requireNonNull(generator, "generator"); + this.p1.possibleValues().forEach(v1 -> + this.p2.possibleValues().forEach(v2 -> + this.p3.possibleValues().forEach(v3 -> + this.p4.possibleValues().forEach(v4 -> + this.p5.possibleValues().forEach(v5 -> + this.add(v1, v2, v3, v4, v5, generator.apply(v1, v2, v3, v4, v5))))))); + return this; + } + + public Builder generateList(final QuinFunction> generator) { + Objects.requireNonNull(generator, "generator"); + this.p1.possibleValues().forEach(v1 -> + this.p2.possibleValues().forEach(v2 -> + this.p3.possibleValues().forEach(v3 -> + this.p4.possibleValues().forEach(v4 -> + this.p5.possibleValues().forEach(v5 -> + this.add(v1, v2, v3, v4, v5, generator.apply(v1, v2, v3, v4, v5))))))); + return this; + } + + @Override + public P5 build() { + this.validate(); + return new P5<>(this.values, this.properties, this.p1, this.p2, this.p3, this.p4, this.p5); + } + } + } + + public static class Builder> implements + org.spongepowered.api.util.Builder, + CopyableBuilder { + + protected final Map> values = new HashMap<>(); + protected final Set> properties = new HashSet<>(); + private final Set propertyNames = new HashSet<>(); + + protected Builder() { + this.reset(); + } + + @SuppressWarnings("unchecked") + private B cast() { + return (B) this; + } + + public B addAll(final Map> values) { + Objects.requireNonNull(values, "values").forEach(this::add); + return this.cast(); + } + + public B add(final State state, final Variant... variants) { + return this.add(StateSelector.of(state), variants); + } + + public B add(final State state, final Collection variants) { + return this.add(StateSelector.of(state), variants); + } + + public B add(final StateSelector.Builder selector, final Variant... variants) { + return this.add(selector.build(), variants); + } + + public B add(final StateSelector.Builder selector, final Collection variants) { + return this.add(selector.build(), variants); + } + + public B add(final StateSelector selector, final Variant... variants) { + return this.add(selector, List.of(Objects.requireNonNull(variants, "variants"))); + } + + public B add(final StateSelector selector, final Collection variants) { + this.validateInput(selector, variants); + if (this.values.containsKey(selector)) { + this.values.put(selector, List.copyOf(variants)); + return this.cast(); + } + + for (final StateProperty property : selector.properties()) { + final String propertyName = property.name(); + if (this.propertyNames.contains(propertyName) && !this.properties.contains(property)) { + throw new IllegalArgumentException(String.format( + "Given selector has property with name '%s', " + + "but this dispatch already contains another property with the same name", + propertyName + )); + } + } + + for (final StateSelector current : this.values.keySet()) { + if (current.overlaps(selector)) { + throw this.overlap(selector, current); + } + } + + this.putEntry(selector, List.copyOf(variants)); + return this.cast(); + } + + public B expand(final StateSelector selector, final Variant... variants) { + return this.expand(selector, List.of(variants)); + } + + public B expand(final StateSelector selector, final Collection variants) { + this.validateInput(selector, variants); + if (this.values.containsKey(selector)) { + this.values.put(selector, List.copyOf(variants)); + return this.cast(); + } + + final var values = this.values.entrySet().iterator(); + final Map> valuesToAdd = new HashMap<>(); + while (values.hasNext()) { + final var entry = values.next(); + final StateSelector oldSelector = entry.getKey(); + final List oldVariants = entry.getValue(); + + if (oldSelector.test(selector)) { + values.remove(); + final Stream> newProperties = selector.properties().stream() + .filter(property -> !oldSelector.properties().contains(property)); + + StateSelector.populate(newProperties::iterator) + .map(oldSelector::with) + .forEach(newSelector -> valuesToAdd.put(newSelector, oldVariants)); + + valuesToAdd.put(selector, List.copyOf(variants)); + + } else if (oldSelector.overlaps(selector)) { + throw this.overlap(selector, oldSelector); + } + } + + valuesToAdd.forEach(this::putEntry); + return this.cast(); + } + + @Override + public B reset() { + this.values.clear(); + this.properties.clear(); + this.propertyNames.clear(); + return this.cast(); + } + + @Override + public B from(final StateDispatch dispatch) { + return this.reset().addAll(Objects.requireNonNull(dispatch, "dispatch").values()); + } + + @Override + public StateDispatch build() { + this.validate(); + return new StateDispatch(this.values, this.properties); + } + + private void validateInput(final StateSelector selector, final Collection variants) { + Objects.requireNonNull(selector, "selector"); + Objects.requireNonNull(variants, "variants"); + if (variants.isEmpty()) { + throw new IllegalArgumentException("At least one variant must be provided"); + } + } + + private RuntimeException overlap(final StateSelector given, final StateSelector current) { + return new IllegalArgumentException(String.format( + "Given selector (%s) overlaps with the selector in this dispatch (%s)", + given, current + )); + } + + private void putEntry(final StateSelector selector, final List variants) { + this.values.put(selector, List.copyOf(variants)); + this.properties.addAll(selector.properties()); + selector.properties().forEach(property -> this.propertyNames.add(property.name())); + } + + protected void validate() { + if (this.values.isEmpty()) { + throw new IllegalStateException("Dispatch must contain at least one selector"); + } + + final List missingSelectors = StateSelector.populate(this.properties) + .filter(fullSelector -> { + for (final StateSelector selector : this.values.keySet()) { + if (selector.test(fullSelector)) { + return false; + } + } + return true; + }) + .toList(); + + if (!missingSelectors.isEmpty()) { + String message = "Missing selectors for property sets:"; + for (final StateSelector selector : missingSelectors) { + message += "\n\t\t" + selector.serializationString(); + } + throw new IllegalStateException(message); + } + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java new file mode 100644 index 0000000..c832dab --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java @@ -0,0 +1,38 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.Objects; + +import org.spongepowered.api.state.State; +import org.spongepowered.api.state.StateContainer; + +import com.mojang.serialization.DynamicOps; + +import net.hellheim.spongetools.proxy.solid.block.StateContainerProxy; +import net.hellheim.spongetools.proxy.solid.codec.DynamicOpsProxy; + +public final class StateOps> implements DynamicOpsProxy, StateContainerProxy { + + private final DynamicOps ops; + private final StateContainer container; + + private StateOps(final DynamicOps ops, final StateContainer container) { + this.ops = Objects.requireNonNull(ops, "ops"); + this.container = Objects.requireNonNull(container, "contaier"); + } + + public static > StateOps of( + final DynamicOps ops, final StateContainer container + ) { + return new StateOps<>(ops, container); + } + + @Override + public DynamicOps getAsOps() { + return this.ops; + } + + @Override + public StateContainer getAsStateContainer() { + return this.container; + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java new file mode 100644 index 0000000..12c3117 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java @@ -0,0 +1,43 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.Objects; +import java.util.function.Supplier; + +import org.spongepowered.api.Sponge; +import org.spongepowered.api.data.type.StringRepresentable; +import org.spongepowered.api.state.StateProperty; + +import com.mojang.serialization.Codec; + +public interface StatePropertyValue> extends StringRepresentable { + + public static final Codec> CODEC = StateCodec.STATE_PROPERTY_VALUE; + + static > StatePropertyValue of( + final StateProperty property, final T value + ) { + return Sponge.game().factoryProvider().provide(Factory.class).of(property, value); + } + + static > StatePropertyValue of( + final StateProperty property, final Supplier valueSupplier + ) { + return StatePropertyValue.of(property, Objects.requireNonNull(valueSupplier, "valueSupplier").get()); + } + + @SuppressWarnings("unchecked") + static > StatePropertyValue ofRaw( + final StateProperty property, final Object value + ) { + return StatePropertyValue.of(property, (T) value); + } + + StateProperty property(); + + T value(); + + interface Factory { + + > StatePropertyValue of(StateProperty property, T value); + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java new file mode 100644 index 0000000..a0b84e3 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java @@ -0,0 +1,227 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.data.type.StringRepresentable; +import org.spongepowered.api.state.State; +import org.spongepowered.api.state.StateProperty; +import org.spongepowered.api.util.CopyableBuilder; + +import com.google.common.collect.Sets; +import com.mojang.serialization.Codec; + +public final class StateSelector implements StringRepresentable { + + public static final Codec CODEC = StateCodec.STATE_SELECTOR; + + private static final StateSelector EMPTY = new StateSelector(Map.of()); + + private static final Comparator> COMPARE_BY_NAME = + Comparator.comparing(value -> value.property().name()); + + private final Map, StatePropertyValue> values; + + private StateSelector(final Map, StatePropertyValue> values) { + this.values = Map.copyOf(values); + } + + public static Builder builder() { + return new Builder(); + } + + public static StateSelector empty() { + return StateSelector.EMPTY; + } + + public static StateSelector of(final State state) { + final Builder builder = StateSelector.builder(); + Objects.requireNonNull(state, "state").statePropertyMap().forEach((property, value) -> + builder.add(StatePropertyValue.ofRaw(property, value))); + return builder.build(); + } + + public static Stream populate(final StateProperty... properties) { + return StateSelector.populate(List.of(properties)); + } + + public static Stream populate(final Iterable> properties) { + Objects.requireNonNull(properties, "properties"); + Stream selectors = Stream.of(StateSelector.empty()); + for (final StateProperty property : properties) { + selectors = selectors.flatMap(selector -> + property.possibleValues().stream().map(value -> + selector.with(StatePropertyValue.ofRaw(property, value)))); + } + return selectors; + } + + public Set> properties() { + return this.values.keySet(); + } + + public Collection> values() { + return this.values.values(); + } + + public boolean overlaps(final StateSelector selector) { + final var commonProperties = Sets.intersection(this.properties(), selector.properties()); + for (final StateProperty property : commonProperties) { + final var thisValue = this.values.get(property).value(); + final var thatValue = selector.values.get(property).value(); + if (!Objects.equals(thisValue, thatValue)) { + return false; + } + } + + return true; + } + + public boolean test(final StateSelector selector) { + Objects.requireNonNull(selector, "selector"); + return this.test(property -> { + final @Nullable StatePropertyValue value = selector.values.get(property); + return value == null ? null : value.value(); + }); + } + + public boolean test(final State state) { + Objects.requireNonNull(state, "state"); + return this.test(property -> state.stateProperty(property).orElse(null)); + } + + private boolean test(final Function, @Nullable Comparable> valueLookup) { + for (final StatePropertyValue value : this.values()) { + if (!Objects.equals(value.value(), valueLookup.apply(value.property()))) { + return false; + } + } + return true; + } + + public Builder toBuilder() { + return StateSelector.builder().from(this); + } + + public > StateSelector with( + final StateProperty property, final T value + ) { + return this.toBuilder().add(property, value).build(); + } + + public > StateSelector with( + final StateProperty property, final Supplier valueSupplier + ) { + return this.toBuilder().add(property, valueSupplier).build(); + } + + public StateSelector with(final StatePropertyValue value) { + return this.toBuilder().add(value).build(); + } + + public StateSelector with(final StateSelector selector) { + return this.toBuilder().addAll(selector).build(); + } + + @Override + public String serializationString() { + return this.values().stream() + .sorted(StateSelector.COMPARE_BY_NAME) + .map(StatePropertyValue::serializationString) + .collect(Collectors.joining(",")); + } + + @Override + public int hashCode() { + return this.values.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (this.getClass() != obj.getClass()) { + return false; + } else { + return this.values.equals(((StateSelector) obj).values); + } + } + + public static class Builder implements + org.spongepowered.api.util.Builder, + CopyableBuilder { + + private final Map, StatePropertyValue> values = new HashMap<>(); + private final Set propertyNames = new HashSet<>(); + + public > Builder add(final StateProperty property, final T value) { + return this.add(StatePropertyValue.of(property, value)); + } + + public > Builder add(final StateProperty property, final Supplier valueSupplier) { + return this.add(StatePropertyValue.of(property, valueSupplier)); + } + + public Builder add(final StatePropertyValue value) { + final StateProperty property = value.property(); + final String propertyName = property.name(); + if (this.propertyNames.contains(propertyName) && !this.values.containsKey(property)) { + throw new IllegalArgumentException(String.format( + "Given selector has property with name '%s', " + + "but this selector already contains another property with the same name", + propertyName + )); + } + + this.values.put(property, value); + this.propertyNames.add(propertyName); + return this; + } + + public Builder addAll(final StatePropertyValue... values) { + for (final StatePropertyValue value : Objects.requireNonNull(values, "values")) { + this.add(value); + } + return this; + } + + public Builder addAll(final Iterable> values) { + for (final StatePropertyValue value : Objects.requireNonNull(values, "values")) { + this.add(value); + } + return this; + } + + public Builder addAll(final StateSelector selector) { + return this.addAll(Objects.requireNonNull(selector, "selector").values()); + } + + @Override + public Builder from(final StateSelector selector) { + return this.reset().addAll(selector); + } + + @Override + public Builder reset() { + this.values.clear(); + this.propertyNames.clear(); + return this; + } + + @Override + public StateSelector build() { + return new StateSelector(this.values); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java new file mode 100644 index 0000000..1d81b7c --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java @@ -0,0 +1,129 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Supplier; + +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.util.CopyableBuilder; + +import com.mojang.serialization.Codec; + +public final class Variant { + + public static final Codec CODEC = VariantPropertyValue.LIST_CODEC.xmap( + list -> Variant.builder().addAll(list).build(), + variant -> List.copyOf(variant.values()) + ); + + private static final Variant EMPTY = new Variant(Map.of()); + + private final Map, VariantPropertyValue> values; + + private Variant(final Map, VariantPropertyValue> values) { + this.values = Map.copyOf(values); + } + + public static Builder builder() { + return new Builder(); + } + + public static Variant empty() { + return Variant.EMPTY; + } + + public static Variant model(final ResourceKey model) { + return Variant.builder().add(VariantProperties.MODEL, model).build(); + } + + public Set> properties() { + return this.values.keySet(); + } + + public Collection> values() { + return this.values.values(); + } + + public Builder toBuilder() { + return Variant.builder().from(this); + } + + public Variant with(final VariantProperty property, final T value) { + return this.toBuilder().add(property, value).build(); + } + + public Variant with(final VariantProperty property, final Supplier valueSupplier) { + return this.toBuilder().add(property, valueSupplier).build(); + } + + public Variant with(final VariantPropertyValue value) { + return this.toBuilder().add(value).build(); + } + + public Variant with(final Variant variant) { + return this.toBuilder().addAll(variant).build(); + } + + public static class Builder implements + org.spongepowered.api.util.Builder, + CopyableBuilder { + + private final Map, VariantPropertyValue> values = new HashMap<>(); + + public Builder() { + this.reset(); + } + + public Builder add(final VariantProperty property, final T value) { + return this.add(VariantPropertyValue.of(property, value)); + } + + public Builder add(final VariantProperty property, final Supplier valueSupplier) { + return this.add(VariantPropertyValue.of(property, valueSupplier)); + } + + public Builder add(final VariantPropertyValue value) { + Objects.requireNonNull(value, "value"); + this.values.put(value.property(), value); + return this; + } + + public Builder addAll(final VariantPropertyValue... values) { + for (final VariantPropertyValue value : Objects.requireNonNull(values, "values")) { + this.add(value); + } + return this; + } + + public Builder addAll(final Iterable> values) { + for (final VariantPropertyValue value : Objects.requireNonNull(values, "values")) { + this.add(value); + } + return this; + } + + public Builder addAll(final Variant variant) { + return this.addAll(Objects.requireNonNull(variant, "variant").values()); + } + + @Override + public Builder from(final Variant variant) { + return this.reset().addAll(variant); + } + + @Override + public Builder reset() { + this.values.clear(); + return this; + } + + @Override + public Variant build() { + return new Variant(this.values); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java new file mode 100644 index 0000000..a94da55 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java @@ -0,0 +1,31 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.Optional; + +import org.spongepowered.api.ResourceKey; + +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.codec.list.SpongeCodecs; + +public final class VariantProperties { + + public static final VariantProperty MODEL = property("model", SpongeCodecs.RESOURCE_KEY, Optional.empty()); + + public static final VariantProperty X_ROT = property("x", VariantRotation.CODEC, Optional.of(VariantRotation.R0)); + + public static final VariantProperty Y_ROT = property("y", VariantRotation.CODEC, Optional.of(VariantRotation.R0)); + + public static final VariantProperty UV_LOCK = property("uvlock", Codec.BOOL, Optional.of(false)); + + public static final VariantProperty WEIGHT = property("weight", Codec.INT, Optional.of(0)); + + private static VariantProperty property( + final String name, final Codec valueCodec, final Optional defaultValue + ) { + return new VariantProperty<>(name, valueCodec, defaultValue); + } + + private VariantProperties() { + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java new file mode 100644 index 0000000..14ed502 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java @@ -0,0 +1,39 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; + +import org.spongepowered.api.data.type.StringRepresentable; + +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.codec.LateBoundIdMapper; + +public record VariantProperty(String name, Codec valueCodec, Optional defaultValue) + implements StringRepresentable { + + private static final LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); + + public static final Codec> CODEC = VariantProperty.ID_MAPPER.codec(Codec.STRING); + + public VariantProperty(final String name, final Codec valueCodec, final Optional defaultValue) { + this.name = Objects.requireNonNull(name, "name").toLowerCase(); + this.valueCodec = Objects.requireNonNull(valueCodec, "valueCodec"); + this.defaultValue = Objects.requireNonNull(defaultValue, "defaultValue"); + VariantProperty.ID_MAPPER.put(this.name, this); + } + + public VariantPropertyValue with(final T value) { + return VariantPropertyValue.of(this, value); + } + + public VariantPropertyValue with(final Supplier valueSupplier) { + return VariantPropertyValue.of(this, valueSupplier); + } + + @Override + public String serializationString() { + return this.name; + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantPropertyValue.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantPropertyValue.java new file mode 100644 index 0000000..aebb80b --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantPropertyValue.java @@ -0,0 +1,49 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import com.mojang.serialization.Codec; + +public record VariantPropertyValue(VariantProperty property, T value) { + + private static final Codec, Object>> MAP_CODEC = Codec.dispatchedMap(VariantProperty.CODEC, VariantProperty::valueCodec); + + public static final Codec>> LIST_CODEC = VariantPropertyValue.MAP_CODEC.xmap( + map -> map.entrySet().stream() + .>map(e -> { + @SuppressWarnings("unchecked") + final var property = (VariantProperty) e.getKey(); + return VariantPropertyValue.of(property, e.getValue()); + }) + .filter(v -> !v.isDefault()) + .collect(Collectors.toUnmodifiableList()), + list -> list.stream() + .filter(v -> !v.isDefault()) + .collect(Collectors.toUnmodifiableMap(VariantPropertyValue::property, VariantPropertyValue::value)) + ); + + public VariantPropertyValue(final VariantProperty property, final T value) { + this.property = Objects.requireNonNull(property, "property"); + this.value = Objects.requireNonNull(value, "value"); + } + + public static VariantPropertyValue of( + final VariantProperty property, final T value + ) { + return new VariantPropertyValue<>(property, value); + } + + public static VariantPropertyValue of( + final VariantProperty property, final Supplier valueSupplier + ) { + return VariantPropertyValue.of(property, Objects.requireNonNull(valueSupplier, "valueSupplier").get()); + } + + public boolean isDefault() { + return this.property.defaultValue().map(this.value::equals).orElse(false); + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantRotation.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantRotation.java new file mode 100644 index 0000000..e605695 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantRotation.java @@ -0,0 +1,32 @@ +package net.hellheim.spongetools.resourcepack.block; + +import org.spongepowered.api.data.type.StringRepresentable; + +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.codec.StringRepresentableCodec; + +public enum VariantRotation implements StringRepresentable { + + R0(0), + R90(90), + R180(180), + R270(270); + + public static final Codec CODEC = StringRepresentableCodec.fromValues(VariantRotation::values); + + private final int value; + + private VariantRotation(final int value) { + this.value = value; + } + + public int value() { + return this.value; + } + + @Override + public String serializationString() { + return Integer.toString(this.value); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/ConditionalProperty.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/ConditionalProperty.java similarity index 99% rename from src/main/java/net/hellheim/spongetools/custom/model/item/ConditionalProperty.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/ConditionalProperty.java index 8d06896..3abfd0d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/ConditionalProperty.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/ConditionalProperty.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.util.function.Function; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/Item.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/Item.java similarity index 96% rename from src/main/java/net/hellheim/spongetools/custom/model/item/Item.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/Item.java index 14756de..50f73ec 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/Item.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/Item.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.util.Objects; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemDefinition.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java similarity index 99% rename from src/main/java/net/hellheim/spongetools/custom/model/item/ItemDefinition.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java index 46ff798..d2c90f4 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemDefinition.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.util.Collection; import java.util.List; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemModel.java similarity index 94% rename from src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/ItemModel.java index 424f269..6e0ca3a 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemModel.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemModel.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.util.Objects; import java.util.function.Consumer; @@ -12,10 +12,10 @@ import net.hellheim.spongetools.SpongeTools; import net.hellheim.spongetools.codec.list.RegistryCodecs; -import net.hellheim.spongetools.custom.model.ModelTemplate; -import net.hellheim.spongetools.custom.model.TexturedModel; -import net.hellheim.spongetools.custom.model.Textures; -import net.hellheim.spongetools.custom.model.util.GuiLight; +import net.hellheim.spongetools.resourcepack.ModelTemplate; +import net.hellheim.spongetools.resourcepack.TexturedModel; +import net.hellheim.spongetools.resourcepack.Textures; +import net.hellheim.spongetools.resourcepack.util.GuiLight; public record ItemModel(TexturedModel model, ItemTransforms display, GuiLight guiLight) { diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemTransforms.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemTransforms.java similarity index 98% rename from src/main/java/net/hellheim/spongetools/custom/model/item/ItemTransforms.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/ItemTransforms.java index 1c4ad84..133898f 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/ItemTransforms.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemTransforms.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectEntry.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java similarity index 92% rename from src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectEntry.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java index 95ad01c..36ddfa9 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectEntry.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.util.Objects; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectProperty.java similarity index 97% rename from src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectProperty.java index 4a83a16..b61d081 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/RangeSelectProperty.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectProperty.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.util.Objects; import java.util.function.Function; @@ -13,9 +13,9 @@ import net.hellheim.spongetools.codec.LateBoundIdMapper; import net.hellheim.spongetools.codec.list.ExtraCodecs; import net.hellheim.spongetools.codec.list.SpongeCodecs; -import net.hellheim.spongetools.custom.model.util.CompassTarget; -import net.hellheim.spongetools.custom.model.util.TimeSource; import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; +import net.hellheim.spongetools.resourcepack.util.CompassTarget; +import net.hellheim.spongetools.resourcepack.util.TimeSource; public interface RangeSelectProperty extends MapCodecProxy { diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java similarity index 98% rename from src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java index 3bb93dd..4f63c91 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectProperty.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.text.SimpleDateFormat; import java.util.List; @@ -30,8 +30,8 @@ import net.hellheim.spongetools.codec.list.RegistryCodecs; import net.hellheim.spongetools.codec.list.SpongeCodecs; import net.hellheim.spongetools.codec.list.StringRepresentableCodecs; -import net.hellheim.spongetools.custom.model.util.ChargeType; import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; +import net.hellheim.spongetools.resourcepack.util.ChargeType; public interface SelectProperty extends MapCodecProxy> { diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitch.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitch.java similarity index 93% rename from src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitch.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitch.java index b795097..8d94362 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitch.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitch.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.util.List; import java.util.Objects; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitchCase.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java similarity index 94% rename from src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitchCase.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java index 4aea643..a14c6cb 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/SelectSwitchCase.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.util.List; import java.util.Objects; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/SpecialModel.java similarity index 98% rename from src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/SpecialModel.java index caf5af5..bbe97e1 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/SpecialModel.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/SpecialModel.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.util.Objects; import java.util.Optional; @@ -16,8 +16,8 @@ import net.hellheim.spongetools.codec.LateBoundIdMapper; import net.hellheim.spongetools.codec.list.SpongeCodecs; import net.hellheim.spongetools.codec.list.StringRepresentableCodecs; -import net.hellheim.spongetools.custom.model.util.SkullType; import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; +import net.hellheim.spongetools.resourcepack.util.SkullType; public interface SpecialModel extends MapCodecProxy { diff --git a/src/main/java/net/hellheim/spongetools/custom/model/item/TintSource.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/TintSource.java similarity index 99% rename from src/main/java/net/hellheim/spongetools/custom/model/item/TintSource.java rename to src/main/java/net/hellheim/spongetools/resourcepack/item/TintSource.java index bf5bd9c..f582414 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/item/TintSource.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/TintSource.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.item; +package net.hellheim.spongetools.resourcepack.item; import java.util.function.Function; diff --git a/src/main/java/net/hellheim/spongetools/custom/model/util/ChargeType.java b/src/main/java/net/hellheim/spongetools/resourcepack/util/ChargeType.java similarity index 63% rename from src/main/java/net/hellheim/spongetools/custom/model/util/ChargeType.java rename to src/main/java/net/hellheim/spongetools/resourcepack/util/ChargeType.java index 45dee53..efd570d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/util/ChargeType.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/util/ChargeType.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.util; +package net.hellheim.spongetools.resourcepack.util; import org.spongepowered.api.data.type.StringRepresentable; @@ -9,20 +9,14 @@ // TODO Maybe expose as registry? public enum ChargeType implements StringRepresentable { - NONE("none"), - ARROW("arrow"), - ROCKET("rocket"); - + NONE, + ARROW, + ROCKET; + public static final Codec CODEC = StringRepresentableCodec.fromValues(ChargeType::values); - private final String name; - - private ChargeType(final String name) { - this.name = name; - } - @Override public String serializationString() { - return this.name; + return this.name().toLowerCase(); } } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/util/CompassTarget.java b/src/main/java/net/hellheim/spongetools/resourcepack/util/CompassTarget.java similarity index 61% rename from src/main/java/net/hellheim/spongetools/custom/model/util/CompassTarget.java rename to src/main/java/net/hellheim/spongetools/resourcepack/util/CompassTarget.java index 09c0972..a0e9612 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/util/CompassTarget.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/util/CompassTarget.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.util; +package net.hellheim.spongetools.resourcepack.util; import org.spongepowered.api.data.type.StringRepresentable; @@ -7,21 +7,15 @@ import net.hellheim.spongetools.codec.StringRepresentableCodec; public enum CompassTarget implements StringRepresentable { - NONE("none"), - LODESTONE("lodestone"), - SPAWN("spawn"), - RECOVERY("recovery"); + NONE, + LODESTONE, + SPAWN, + RECOVERY; public static final Codec CODEC = StringRepresentableCodec.fromValues(CompassTarget::values); - private final String name; - - private CompassTarget(final String name) { - this.name = name; - } - @Override public String serializationString() { - return this.name; + return this.name().toLowerCase(); } } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/util/GuiLight.java b/src/main/java/net/hellheim/spongetools/resourcepack/util/GuiLight.java similarity index 69% rename from src/main/java/net/hellheim/spongetools/custom/model/util/GuiLight.java rename to src/main/java/net/hellheim/spongetools/resourcepack/util/GuiLight.java index 2698cac..ff50ee7 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/util/GuiLight.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/util/GuiLight.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.util; +package net.hellheim.spongetools.resourcepack.util; import org.spongepowered.api.data.type.StringRepresentable; @@ -7,20 +7,14 @@ import net.hellheim.spongetools.codec.StringRepresentableCodec; public enum GuiLight implements StringRepresentable { - FRONT("front"), - SIDE("side"); + FRONT, + SIDE; public static final Codec CODEC = StringRepresentableCodec.fromValues(GuiLight.values()); public static final GuiLight DEFAULT = GuiLight.SIDE; - private final String name; - - private GuiLight(String name) { - this.name = name; - } - @Override public String serializationString() { - return this.name; + return this.name().toLowerCase(); } } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/util/SkullType.java b/src/main/java/net/hellheim/spongetools/resourcepack/util/SkullType.java similarity index 55% rename from src/main/java/net/hellheim/spongetools/custom/model/util/SkullType.java rename to src/main/java/net/hellheim/spongetools/resourcepack/util/SkullType.java index 728a9b6..8897402 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/util/SkullType.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/util/SkullType.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.util; +package net.hellheim.spongetools.resourcepack.util; import org.spongepowered.api.data.type.StringRepresentable; @@ -8,24 +8,18 @@ // TODO Expose as registry? public enum SkullType implements StringRepresentable { - SKELETON("skeleton"), - WITHER_SKELETON("wither_skeleton"), - PLAYER("player"), - ZOMBIE("zombie"), - CREEPER("creeper"), - PIGLIN("piglin"), - DRAGON("dragon"); + SKELETON, + WITHER_SKELETON, + PLAYER, + ZOMBIE, + CREEPER, + PIGLIN, + DRAGON; public static final Codec CODEC = StringRepresentableCodec.fromValues(SkullType::values); - private final String name; - - private SkullType(String name) { - this.name = name; - } - @Override public String serializationString() { - return this.name; + return this.name().toLowerCase(); } } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/util/TimeSource.java b/src/main/java/net/hellheim/spongetools/resourcepack/util/TimeSource.java similarity index 60% rename from src/main/java/net/hellheim/spongetools/custom/model/util/TimeSource.java rename to src/main/java/net/hellheim/spongetools/resourcepack/util/TimeSource.java index 2c643b6..a4be8a8 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/util/TimeSource.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/util/TimeSource.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.util; +package net.hellheim.spongetools.resourcepack.util; import org.spongepowered.api.data.type.StringRepresentable; @@ -7,20 +7,14 @@ import net.hellheim.spongetools.codec.StringRepresentableCodec; public enum TimeSource implements StringRepresentable { - RANDOM("random"), - DAYTIME("daytime"), - MOON_PHASE("moon_phase"); + RANDOM, + DAYTIME, + MOON_PHASE; public static final Codec CODEC = StringRepresentableCodec.fromValues(TimeSource::values); - private final String name; - - private TimeSource(String name) { - this.name = name; - } - @Override public String serializationString() { - return this.name; + return this.name().toLowerCase(); } } diff --git a/src/main/java/net/hellheim/spongetools/custom/model/util/WoodTypes.java b/src/main/java/net/hellheim/spongetools/resourcepack/util/WoodTypes.java similarity index 89% rename from src/main/java/net/hellheim/spongetools/custom/model/util/WoodTypes.java rename to src/main/java/net/hellheim/spongetools/resourcepack/util/WoodTypes.java index a24ec4c..83c2f19 100644 --- a/src/main/java/net/hellheim/spongetools/custom/model/util/WoodTypes.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/util/WoodTypes.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.model.util; +package net.hellheim.spongetools.resourcepack.util; public final class WoodTypes { From d38bba49e15ffc4ec6f33868cd021e2d77827820 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Wed, 14 May 2025 23:54:16 +0300 Subject: [PATCH 17/55] continue custom stuff --- .../net/hellheim/spongetools/SpongeTools.java | 30 +- .../codec/list/RegistryCodecs.java | 23 +- .../spongetools/codec/list/SpongeCodecs.java | 33 ++ .../custom/block/BlockStateRegistrar.java | 31 -- .../custom/block/CustomBlockType.java | 33 -- .../spongetools/custom/type/EitherType.java | 151 ++++++ .../block/BasicCustomBlockType.java | 12 +- .../type/block/BlockStateDispatcher.java | 30 ++ .../custom/type/block/BlockStateHolder.java | 27 + .../{ => type}/block/BlockStateProvider.java | 6 +- .../custom/type/block/CustomBlockType.java | 51 ++ .../block/CustomBlockTypeBuilder.java | 24 +- .../block/CustomBlockTypeProperties.java | 2 +- .../custom/type/block/EitherBlockType.java | 167 ++++++ .../block/NoAvailableStateException.java | 2 +- .../{ => type}/item/CustomItemType.java | 6 +- .../item/CustomItemTypeProperties.java | 24 +- .../{ => type}/item/DeferredItemType.java | 2 +- .../{ => type}/item/EitherItemType.java | 156 ++---- .../item/IDefaultedCustomItemType.java | 6 +- .../custom/{ => type}/item/IconProxy.java | 2 +- .../item/data/CustomConsumeEffect.java | 2 +- .../event/RegisterBlockStateHolderEvent.java | 16 + ...ItemTransforms.java => ItemTransform.java} | 22 +- .../spongetools/resourcepack/Model.java | 203 +++++++ .../spongetools/resourcepack/ModelPart.java | 199 +++++++ .../resourcepack/ModelPartFace.java | 166 ++++++ .../resourcepack/ModelPartRotation.java | 92 ++++ .../spongetools/resourcepack/TextureSlot.java | 45 +- .../resourcepack/TextureSlots.java | 102 ++-- .../resourcepack/block/BlockDefinition.java | 203 ++++++- .../resourcepack/block/StateCodec.java | 288 ++++++++-- .../resourcepack/block/StateCondition.java | 507 +++++++++++++++++- .../resourcepack/block/StateDispatch.java | 7 +- .../resourcepack/block/StateOps.java | 7 + .../resourcepack/block/StatePart.java | 56 ++ .../resourcepack/block/StatePredicate.java | 22 + .../block/StatePropertyValue.java | 9 + .../resourcepack/block/StateSelector.java | 35 +- .../resourcepack/block/Variant.java | 15 + .../resourcepack/block/VariantProperties.java | 8 +- .../resourcepack/block/VariantRotation.java | 32 -- .../spongetools/resourcepack/item/Item.java | 43 -- .../resourcepack/item/ItemDefinition.java | 262 +-------- .../resourcepack/item/ItemModel.java | 288 ++++++---- .../resourcepack/item/RangeSelectEntry.java | 6 +- .../resourcepack/item/SelectSwitchCase.java | 6 +- .../meta}/AnimationFrame.java | 2 +- .../meta}/GuiScaling.java | 2 +- .../meta}/Metadata.java | 2 +- .../meta}/MetadataLike.java | 2 +- .../meta}/MetadataSection.java | 3 +- .../meta}/MetadataSectionLike.java | 2 +- .../util}/VillagerHat.java | 19 +- 54 files changed, 2643 insertions(+), 848 deletions(-) delete mode 100644 src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/EitherType.java rename src/main/java/net/hellheim/spongetools/custom/{ => type}/block/BasicCustomBlockType.java (87%) create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateDispatcher.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java rename src/main/java/net/hellheim/spongetools/custom/{ => type}/block/BlockStateProvider.java (96%) create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java rename src/main/java/net/hellheim/spongetools/custom/{ => type}/block/CustomBlockTypeBuilder.java (84%) rename src/main/java/net/hellheim/spongetools/custom/{ => type}/block/CustomBlockTypeProperties.java (92%) create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/block/EitherBlockType.java rename src/main/java/net/hellheim/spongetools/custom/{ => type}/block/NoAvailableStateException.java (85%) rename src/main/java/net/hellheim/spongetools/custom/{ => type}/item/CustomItemType.java (98%) rename src/main/java/net/hellheim/spongetools/custom/{ => type}/item/CustomItemTypeProperties.java (90%) rename src/main/java/net/hellheim/spongetools/custom/{ => type}/item/DeferredItemType.java (98%) rename src/main/java/net/hellheim/spongetools/custom/{ => type}/item/EitherItemType.java (63%) rename src/main/java/net/hellheim/spongetools/custom/{ => type}/item/IDefaultedCustomItemType.java (88%) rename src/main/java/net/hellheim/spongetools/custom/{ => type}/item/IconProxy.java (94%) rename src/main/java/net/hellheim/spongetools/custom/{ => type}/item/data/CustomConsumeEffect.java (97%) create mode 100644 src/main/java/net/hellheim/spongetools/event/RegisterBlockStateHolderEvent.java rename src/main/java/net/hellheim/spongetools/resourcepack/{item/ItemTransforms.java => ItemTransform.java} (81%) create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/Model.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/ModelPart.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/StatePart.java create mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/StatePredicate.java delete mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/block/VariantRotation.java delete mode 100644 src/main/java/net/hellheim/spongetools/resourcepack/item/Item.java rename src/main/java/net/hellheim/spongetools/{custom/metadata => resourcepack/meta}/AnimationFrame.java (97%) rename src/main/java/net/hellheim/spongetools/{custom/metadata => resourcepack/meta}/GuiScaling.java (99%) rename src/main/java/net/hellheim/spongetools/{custom/metadata => resourcepack/meta}/Metadata.java (94%) rename src/main/java/net/hellheim/spongetools/{custom/metadata => resourcepack/meta}/MetadataLike.java (53%) rename src/main/java/net/hellheim/spongetools/{custom/metadata => resourcepack/meta}/MetadataSection.java (98%) rename src/main/java/net/hellheim/spongetools/{custom/metadata => resourcepack/meta}/MetadataSectionLike.java (76%) rename src/main/java/net/hellheim/spongetools/{custom/metadata => resourcepack/util}/VillagerHat.java (67%) diff --git a/src/main/java/net/hellheim/spongetools/SpongeTools.java b/src/main/java/net/hellheim/spongetools/SpongeTools.java index 9c7ea02..102fddc 100644 --- a/src/main/java/net/hellheim/spongetools/SpongeTools.java +++ b/src/main/java/net/hellheim/spongetools/SpongeTools.java @@ -11,11 +11,14 @@ import com.mojang.serialization.MapCodec; -import net.hellheim.spongetools.custom.item.CustomItemType; -import net.hellheim.spongetools.custom.item.EitherItemType; -import net.hellheim.spongetools.custom.item.data.CustomConsumeEffect; -import net.hellheim.spongetools.resourcepack.item.Item; -import net.hellheim.spongetools.resourcepack.item.ItemModel; +import net.hellheim.spongetools.custom.type.block.CustomBlockType; +import net.hellheim.spongetools.custom.type.block.EitherBlockType; +import net.hellheim.spongetools.custom.type.item.CustomItemType; +import net.hellheim.spongetools.custom.type.item.EitherItemType; +import net.hellheim.spongetools.custom.type.item.data.CustomConsumeEffect; +import net.hellheim.spongetools.resourcepack.Model; +import net.hellheim.spongetools.resourcepack.block.BlockDefinition; +import net.hellheim.spongetools.resourcepack.item.ItemDefinition; public final class SpongeTools { @@ -27,19 +30,28 @@ public static ResourceKey key(final String value) { public static final class Registries { - public static final DefaultedRegistryType CUSTOM_ITEM_TYPE = Registries.key("item"); + public static final DefaultedRegistryType CUSTOM_ITEM_TYPE = Registries.key("custom_item"); + + public static final DefaultedRegistryType CUSTOM_BLOCK_TYPE = Registries.key("custom_block"); public static final DefaultedRegistryType EITHER_ITEM_TYPE = Registries.key("either_item"); + public static final DefaultedRegistryType EITHER_BLOCK_TYPE = Registries.key("either_block"); + + /** + * Definitions from this registry will be included in built ResourcePack. + */ + public static final DefaultedRegistryType ITEM_DEFINITION = Registries.key("items"); + /** - * Items from this registry will be included in built ResourcePack. + * Definitions from this registry will be included in built ResourcePack. */ - public static final DefaultedRegistryType ITEM = Registries.key("items"); + public static final DefaultedRegistryType BLOCK_DEFINITION = Registries.key("blockstates"); /** * Models from this registry will be included in built ResourcePack. */ - public static final DefaultedRegistryType ITEM_MODEL = Registries.key("models/item"); + public static final DefaultedRegistryType MODEL = Registries.key("models"); public static final DefaultedRegistryType> CONSUME_EFFECT_TYPE = Registries.key("consume_effect_type"); diff --git a/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java b/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java index c9d6c24..1b54cfe 100644 --- a/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java +++ b/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java @@ -173,11 +173,14 @@ import com.mojang.serialization.MapCodec; import net.hellheim.spongetools.SpongeTools; -import net.hellheim.spongetools.custom.item.CustomItemType; -import net.hellheim.spongetools.custom.item.EitherItemType; -import net.hellheim.spongetools.custom.item.data.CustomConsumeEffect; -import net.hellheim.spongetools.resourcepack.item.Item; -import net.hellheim.spongetools.resourcepack.item.ItemModel; +import net.hellheim.spongetools.custom.type.block.CustomBlockType; +import net.hellheim.spongetools.custom.type.block.EitherBlockType; +import net.hellheim.spongetools.custom.type.item.CustomItemType; +import net.hellheim.spongetools.custom.type.item.EitherItemType; +import net.hellheim.spongetools.custom.type.item.data.CustomConsumeEffect; +import net.hellheim.spongetools.resourcepack.Model; +import net.hellheim.spongetools.resourcepack.block.BlockDefinition; +import net.hellheim.spongetools.resourcepack.item.ItemDefinition; /** * Codecs for all {@link RegistryType}s provided by SpongeAPI. @@ -188,11 +191,17 @@ public final class RegistryCodecs { public static final Codec CUSTOM_ITEM_TYPE = RegistryCodecs.register(CustomItemType.class, CustomItemType.registry()); + public static final Codec CUSTOM_BLOCK_TYPE = RegistryCodecs.register(CustomBlockType.class, CustomBlockType.registry()); + public static final Codec EITHER_ITEM_TYPE = RegistryCodecs.register(EitherItemType.class, EitherItemType.registry()); - public static final Codec ITEM = RegistryCodecs.register(Item.class, Item.registry()); + public static final Codec EITHER_BLOCK_TYPE = RegistryCodecs.register(EitherBlockType.class, EitherBlockType.registry()); + + public static final Codec ITEM_DEFINITION = RegistryCodecs.register(ItemDefinition.class, ItemDefinition.registry()); + + public static final Codec BLOCK_DEFINITION = RegistryCodecs.register(BlockDefinition.class, BlockDefinition.registry()); - public static final Codec ITEM_MODEL = RegistryCodecs.register(ItemModel.class, ItemModel.registry()); + public static final Codec MODEL = RegistryCodecs.register(Model.class, Model.registry()); public static final Codec> CUSTOM_CONSUME_EFFECT_TYPE = RegistryCodecs.of(SpongeTools.Registries.CONSUME_EFFECT_TYPE); diff --git a/src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java b/src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java index 35c45e7..442dc81 100644 --- a/src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java +++ b/src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java @@ -7,8 +7,10 @@ import org.spongepowered.api.ResourceKeyed; import org.spongepowered.api.registry.RegistryKey; import org.spongepowered.api.registry.RegistryType; +import org.spongepowered.api.util.Axis; import org.spongepowered.api.util.Direction; import org.spongepowered.api.util.Ticks; +import org.spongepowered.api.util.rotation.Rotation; import org.spongepowered.api.util.weighted.RandomObjectTable; import org.spongepowered.api.util.weighted.TableEntry; import org.spongepowered.api.util.weighted.VariableAmount; @@ -24,6 +26,7 @@ import net.hellheim.spongetools.codec.StringRepresentableCodec; import net.hellheim.spongetools.codec.dispatched.TableEntryCodecs; import net.hellheim.spongetools.codec.dispatched.VariableAmountCodecs; +import net.hellheim.spongetools.util.GeomUtil; /** * Codecs for SpongeAPI types @@ -36,6 +39,36 @@ public final class SpongeCodecs { public static final Codec VARIABLE_AMOUNT = VariableAmountCodecs.CODEC; + public static final Codec AXIS = StringRepresentableCodec.fromValues(Axis::values); + + public static final Codec ROTATION_BY_ANGLE = Codec.INT.flatXmap( + angle -> { + if (angle == 0) { + return DataResult.success(GeomUtil.ROT_0); + } else if (angle == 90) { + return DataResult.success(GeomUtil.ROT_90); + } else if (angle == 180) { + return DataResult.success(GeomUtil.ROT_180); + } else if (angle == 270) { + return DataResult.success(GeomUtil.ROT_270); + } else { + return DataResult.error(() -> "Rotation angle must be 0, 90, 180 or 270: " + angle); + } + }, + rotation -> { + if (GeomUtil.is0(rotation)) { + return DataResult.success(0); + } else if (GeomUtil.is90(rotation)) { + return DataResult.success(90); + } else if (GeomUtil.is180(rotation)) { + return DataResult.success(180); + } else if (GeomUtil.is270(rotation)) { + return DataResult.success(270); + } else { + return DataResult.error(() -> "Unknown rotation: " + rotation); + } + }); + public static final Codec DIRECTION = StringRepresentableCodec.fromValues(Direction::values); public static final Codec CARDINAL_DIRECTION = SpongeCodecs.DIRECTION.validate(dir -> dir.isCardinal() diff --git a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java b/src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java deleted file mode 100644 index 3772800..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateRegistrar.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.hellheim.spongetools.custom.block; - -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -import org.spongepowered.api.block.BlockState; - -public final class BlockStateRegistrar { - - private static final Set OCCUPIED_STATES = new HashSet<>(); - - public static boolean isOccupied(final BlockState state) { - return BlockStateRegistrar.OCCUPIED_STATES.contains(Objects.requireNonNull(state, "state")); - } - - public static boolean isAvailable(final BlockState state) { - return !BlockStateRegistrar.isOccupied(state); - } - - public static void register(final BlockState state) { - if (BlockStateRegistrar.isOccupied(state)) { - throw new IllegalArgumentException("State already occupied: " + state.asString()); - } - - BlockStateRegistrar.OCCUPIED_STATES.add(state); - } - - private BlockStateRegistrar() { - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java deleted file mode 100644 index 623acc6..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockType.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.hellheim.spongetools.custom.block; - -import org.spongepowered.api.block.BlockState; - -import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; -import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; - -public interface CustomBlockType extends - BehaviourCallbackHolder { - - BlockStateProvider stateProvider(); - - /** - * @return The state bound to this block - * @throws IllegalStateException if state is not yet bound - * @see #bind(BlockState) - */ - BlockState state(); - - // TODO move the algorithm description to somewhere else. - /** - * Binds the state to this {@link CustomBlockType}.
- * The state is chosen in a way where all registered - * {@link CustomBlockType}s get the appropriate result.
- * If block is already used in the world, the used state would be provided.
- * If block is not yet used in the world, the state would be chosen from {@link #stateProvider()}.
- * If it's not possible to chose the state, TODO something is thrown. - * - * @param state The state to bind to this {@link CustomBlockType} - * @throws IllegalStateException if state is already bound - */ - void bind(BlockState state); -} diff --git a/src/main/java/net/hellheim/spongetools/custom/type/EitherType.java b/src/main/java/net/hellheim/spongetools/custom/type/EitherType.java new file mode 100644 index 0000000..7015a57 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/EitherType.java @@ -0,0 +1,151 @@ +package net.hellheim.spongetools.custom.type; + +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +import com.mojang.datafixers.util.Either; + +public interface EitherType> { + + boolean isCommon(); + + boolean isCustom(); + + Optional common(); + + Optional custom(); + + Either either(); + + default EITHER mapCommon(final Function commonMapper) { + return this.map(commonMapper, Function.identity()); + } + + default EITHER mapCustom(final Function customMapper) { + return this.map(Function.identity(), customMapper); + } + + EITHER map(Function commonMapper, Function customMapper); + + T apply(Function commonMapper, Function customMapper); + + void accept(Consumer commonAction, Consumer customAction); + + boolean test(Predicate commonTest, Predicate customTest); + + @Override + int hashCode(); + + @Override + boolean equals(Object obj); + + interface Common> extends EitherType { + + COMMON get(); + + @Override + default boolean isCommon() { + return true; + } + + @Override + default boolean isCustom() { + return false; + } + + @Override + default Optional common() { + return Optional.of(this.get()); + } + + @Override + default Optional custom() { + return Optional.empty(); + } + + @Override + default Either either() { + return Either.left(this.get()); + } + + @Override + default T apply( + final Function commonMapper, + final Function customMapper + ) { + return commonMapper.apply(this.get()); + } + + @Override + default void accept( + final Consumer commonAction, + final Consumer customAction + ) { + commonAction.accept(this.get()); + } + + @Override + default boolean test( + final Predicate commonTest, + final Predicate customTest + ) { + return commonTest.test(this.get()); + } + } + + interface Custom> extends EitherType { + + CUSTOM get(); + + @Override + default boolean isCommon() { + return false; + } + + @Override + default boolean isCustom() { + return true; + } + + @Override + default Optional common() { + return Optional.empty(); + } + + @Override + default Optional custom() { + return Optional.of(this.get()); + } + + @Override + default Either either() { + return Either.right(this.get()); + } + + @Override + default T apply( + final Function commonMapper, + final Function customMapper + ) { + return customMapper.apply(this.get()); + } + + @Override + default void accept( + final Consumer commonAction, + final Consumer customAction + ) { + customAction.accept(this.get()); + } + + @Override + default boolean test( + final Predicate commonTest, + final Predicate customTest + ) { + return customTest.test(this.get()); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/BasicCustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java similarity index 87% rename from src/main/java/net/hellheim/spongetools/custom/block/BasicCustomBlockType.java rename to src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java index d2d99ff..8154fcf 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/BasicCustomBlockType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java @@ -1,5 +1,6 @@ -package net.hellheim.spongetools.custom.block; +package net.hellheim.spongetools.custom.type.block; +import java.util.List; import java.util.Objects; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -11,6 +12,7 @@ import net.hellheim.spongetools.custom.behaviour.BehaviourHolder; import net.hellheim.spongetools.custom.behaviour.BehaviourHolderProxy; import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; +import net.hellheim.spongetools.resourcepack.block.Variant; public class BasicCustomBlockType implements CustomBlockType, @@ -19,6 +21,7 @@ public class BasicCustomBlockType implements private final BehaviourCallbackHolderLogic callbacks; private final BlockStateProvider stateProvider; + private final List model; private @MonotonicNonNull BlockState state; private @MonotonicNonNull BlockStateExtension stateExtension; @@ -26,7 +29,7 @@ public BasicCustomBlockType(final CustomBlockTypeBuilder builder) { Objects.requireNonNull(builder, "builder").validate(); this.callbacks = builder.callbacks.asImmutable(); this.stateProvider = builder.stateProvider; - this.bind(this.stateProvider.provide()); + this.model = List.copyOf(builder.model); } @Override @@ -53,6 +56,11 @@ public void bind(final BlockState state) { this.stateExtension = BlockStateExtension.getFor(state); } + @Override + public List model() { + return this.model; + } + @Override public BehaviourHolder getAsBehaviourHolder() { return this.stateExtension; diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateDispatcher.java b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateDispatcher.java new file mode 100644 index 0000000..deca177 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateDispatcher.java @@ -0,0 +1,30 @@ +package net.hellheim.spongetools.custom.type.block; + +import java.util.Optional; + +import org.spongepowered.api.Sponge; +import org.spongepowered.api.block.BlockState; + +public interface BlockStateDispatcher { + + static BlockStateDispatcher get() { + return Sponge.game().factoryProvider().provide(BlockStateDispatcher.class); + } + + Optional get(BlockState state); + + boolean isOccupied(BlockState state); + + default boolean isAvailable(final BlockState state) { + return !this.isOccupied(state); + } + + default void dispatch(final BlockStateHolder holder, final BlockStateProvider provider) { + this.submit(holder, provider); + this.dispatch(); + } + + void submit(BlockStateHolder holder, BlockStateProvider provider); + + void dispatch(); +} diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java new file mode 100644 index 0000000..0ba55a3 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java @@ -0,0 +1,27 @@ +package net.hellheim.spongetools.custom.type.block; + +import org.spongepowered.api.block.BlockState; + +public interface BlockStateHolder { + + /** + * @return The state bound to this holder + * @throws IllegalStateException if state is not yet bound + * @see #bind(BlockState) + */ + BlockState state(); + + // TODO move the algorithm description to somewhere else. + /** + * Binds the state to this {@link BlockStateHolder}.
+ * The state is chosen in a way where all submitted + * {@link BlockStateHolder}s get the appropriate result.
+ * If block is already used in the world, the used state would be provided.
+ * If block is not yet used in the world, the state would be chosen from {@link #stateProvider()}.
+ * If it's not possible to chose the state, TODO something is thrown. + * + * @param state The state to bind to this {@link BlockStateHolder} + * @throws IllegalStateException if state is already bound + */ + void bind(BlockState state); +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java similarity index 96% rename from src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java rename to src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java index 2b277fb..2d3a1f6 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/BlockStateProvider.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.block; +package net.hellheim.spongetools.custom.type.block; import java.util.Arrays; import java.util.Collection; @@ -37,7 +37,7 @@ static AnyState anyState(final Collection states) { @SafeVarargs static AnyBlock anyBlock(final Supplier... blocks) { - return new AnyBlock(Arrays.stream(blocks).map(Supplier::get).collect(Collectors.toUnmodifiableSet())); + return new AnyBlock(Arrays.stream(blocks).map(Supplier::get).collect(Collectors.toSet())); } static AnyBlock anyBlock(final BlockType... blocks) { @@ -71,7 +71,7 @@ default BlockState provide(final Predicate predicate) { } default Stream availableStates() { - return this.allStates().filter(BlockStateRegistrar::isAvailable); + return this.allStates().filter(BlockStateDispatcher.get()::isAvailable); } Stream allStates(); diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java new file mode 100644 index 0000000..83dea31 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java @@ -0,0 +1,51 @@ +package net.hellheim.spongetools.custom.type.block; + +import java.util.List; +import java.util.Optional; + +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.registry.DefaultedRegistryType; + +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.RegistryCodecs; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; +import net.hellheim.spongetools.proxy.solid.block.BlockStateProxy; +import net.hellheim.spongetools.resourcepack.block.Variant; + +public interface CustomBlockType extends + BehaviourCallbackHolder, + BlockStateHolder, + BlockStateProxy { + + static DefaultedRegistryType registry() { + return SpongeTools.Registries.CUSTOM_BLOCK_TYPE; + } + + static Codec registryCodec() { + return RegistryCodecs.CUSTOM_BLOCK_TYPE; + } + + static Optional resolve(final ResourceKey key) { + return CustomBlockType.registry() + .get() + .findValue(key); + } + + static Optional get(final BlockState state) { + return BlockStateDispatcher.get().get(state) + .map(holder -> holder instanceof final CustomBlockType block ? block : null); + } + + BlockStateProvider stateProvider(); + + List model(); + + @Override + default BlockState getAsBlockState() { + return this.state(); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeBuilder.java b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java similarity index 84% rename from src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeBuilder.java rename to src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java index 059ac84..ea5be1c 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeBuilder.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java @@ -1,5 +1,7 @@ -package net.hellheim.spongetools.custom.block; +package net.hellheim.spongetools.custom.type.block; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.function.Supplier; @@ -13,6 +15,7 @@ import net.hellheim.spongetools.custom.behaviour.BehaviourType; import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; import net.hellheim.spongetools.custom.behaviour.type.BlockTypeExtension; +import net.hellheim.spongetools.resourcepack.block.Variant; @SuppressWarnings("unchecked") public class CustomBlockTypeBuilder> implements @@ -20,6 +23,7 @@ public class CustomBlockTypeBuilder> impleme protected BehaviourCallbackHolderLogic.Mutable callbacks; protected @Nullable BlockStateProvider stateProvider; + protected final List model = new ArrayList<>(); public CustomBlockTypeBuilder() { this.reset(); @@ -113,9 +117,27 @@ public B defaultState(final Supplier blockSupplier) { } + public B model(final Variant... variants) { + for (final Variant variant : Objects.requireNonNull(variants, "variants")) { + this.model.add(Objects.requireNonNull(variant, "variant")); + } + + return this.cast(); + } + + public B model(final Iterable variants) { + for (final Variant variant : Objects.requireNonNull(variants, "variants")) { + this.model.add(Objects.requireNonNull(variant, "variant")); + } + + return this.cast(); + } + + public B reset() { this.callbacks = BehaviourCallbackHolderLogic.mutable(); this.stateProvider = null; + this.model.clear(); return this.cast(); } diff --git a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeProperties.java b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java similarity index 92% rename from src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeProperties.java rename to src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java index f6baebc..8c3e8f8 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/CustomBlockTypeProperties.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.block; +package net.hellheim.spongetools.custom.type.block; import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderLogic; diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/EitherBlockType.java b/src/main/java/net/hellheim/spongetools/custom/type/block/EitherBlockType.java new file mode 100644 index 0000000..e16378d --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/EitherBlockType.java @@ -0,0 +1,167 @@ +package net.hellheim.spongetools.custom.type.block; + +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.registry.DefaultedRegistryType; +import org.spongepowered.api.registry.RegistryTypes; + +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Codec; + +import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.RegistryCodecs; +import net.hellheim.spongetools.custom.type.EitherType; +import net.hellheim.spongetools.proxy.solid.block.BlockStateProxy; +import net.hellheim.spongetools.proxy.solid.block.BlockTypeProxy; + +public sealed abstract class EitherBlockType + implements EitherType, BlockTypeProxy + permits EitherBlockType.Common, EitherBlockType.Custom { + + private static final Map COMMON_MAP = new IdentityHashMap<>(); + private static final Map CUSTOM_MAP = new IdentityHashMap<>(); + + public static final Codec CODEC = Codec + .either(RegistryCodecs.BLOCK_TYPE, RegistryCodecs.CUSTOM_BLOCK_TYPE) + .xmap(EitherBlockType::of, EitherBlockType::either); + + public static final DefaultedRegistryType registry() { + return SpongeTools.Registries.EITHER_BLOCK_TYPE; + } + + public static Codec registryCodec() { + return RegistryCodecs.EITHER_BLOCK_TYPE; + } + + public static EitherBlockType common(final Supplier type) { + return EitherBlockType.common(type.get()); + } + + public static EitherBlockType common(final BlockType type) { + return EitherBlockType.COMMON_MAP.computeIfAbsent(type, EitherBlockType.Common::new); + } + + public static EitherBlockType custom(final Supplier type) { + return EitherBlockType.custom(type.get()); + } + + public static EitherBlockType custom(final CustomBlockType type) { + return EitherBlockType.CUSTOM_MAP.computeIfAbsent(type, EitherBlockType.Custom::new); + } + + public static EitherBlockType of(final Either either) { + return either.map(EitherBlockType::common, EitherBlockType::custom); + } + + public static Optional resolve(final ResourceKey key) { + return RegistryTypes.BLOCK_TYPE + .get() + .findValue(key) + .map(EitherBlockType::common) + .or(() -> CustomBlockType.resolve(key) + .map(EitherBlockType::custom)); + } + + protected static final class Common extends EitherBlockType implements + EitherType.Common { + + private final BlockType type; + + protected Common(final BlockType type) { + this.type = Objects.requireNonNull(type, "type"); + } + + @Override + public BlockType get() { + return this.get(); + } + + @Override + public BlockType getAsBlockType() { + return this.type; + } + + @Override + public EitherBlockType map( + final Function commonMapper, + final Function customMapper + ) { + final BlockType newType = commonMapper.apply(this.type); + return newType == this.type ? this : EitherBlockType.common(newType); + } + + @Override + public int hashCode() { + return this.type.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + + if (this.getClass() != obj.getClass()) { + return false; + } + + return this.type.equals(((EitherBlockType.Common) obj).type); + } + } + + protected static final class Custom extends EitherBlockType implements + EitherType.Custom, + BlockStateProxy { + + private final CustomBlockType type; + + protected Custom(final CustomBlockType type) { + this.type = Objects.requireNonNull(type, "type"); + } + + @Override + public CustomBlockType get() { + return this.type; + } + + @Override + public BlockState getAsBlockState() { + return this.type.getAsBlockState(); + } + + @Override + public EitherBlockType map( + final Function commonMapper, + final Function customMapper + ) { + final CustomBlockType newType = customMapper.apply(this.type); + return newType == this.type ? this : EitherBlockType.custom(newType); + } + + @Override + public int hashCode() { + return this.type.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + + if (this.getClass() != obj.getClass()) { + return false; + } + + return this.type.equals(((EitherBlockType.Custom) obj).type); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/block/NoAvailableStateException.java b/src/main/java/net/hellheim/spongetools/custom/type/block/NoAvailableStateException.java similarity index 85% rename from src/main/java/net/hellheim/spongetools/custom/block/NoAvailableStateException.java rename to src/main/java/net/hellheim/spongetools/custom/type/block/NoAvailableStateException.java index 29dee76..20be41e 100644 --- a/src/main/java/net/hellheim/spongetools/custom/block/NoAvailableStateException.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/NoAvailableStateException.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.block; +package net.hellheim.spongetools.custom.type.block; public class NoAvailableStateException extends IllegalStateException { diff --git a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemType.java b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java similarity index 98% rename from src/main/java/net/hellheim/spongetools/custom/item/CustomItemType.java rename to src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java index 6bd501d..06723fc 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item; +package net.hellheim.spongetools.custom.type.item; import java.util.Optional; @@ -24,7 +24,7 @@ import net.hellheim.spongetools.SpongeTools; import net.hellheim.spongetools.codec.list.RegistryCodecs; import net.hellheim.spongetools.proxy.solid.item.ItemStackSnapshotProxy; -import net.hellheim.spongetools.resourcepack.item.Item; +import net.hellheim.spongetools.resourcepack.item.ItemDefinition; import net.kyori.adventure.text.ComponentLike; public interface CustomItemType extends @@ -221,7 +221,7 @@ default DataContainer toContainer() { DefaultedRegistryReference base(); - Optional model(); + Optional model(); public static class DataBuilder extends AbstractDataBuilder { diff --git a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemTypeProperties.java b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java similarity index 90% rename from src/main/java/net/hellheim/spongetools/custom/item/CustomItemTypeProperties.java rename to src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java index 77a24cd..69fe095 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/CustomItemTypeProperties.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item; +package net.hellheim.spongetools.custom.type.item; import java.util.Objects; import java.util.Optional; @@ -31,8 +31,8 @@ import net.hellheim.spongetools.object.ValueSetBuilder; import net.hellheim.spongetools.proxy.solid.data.ValueContainerProxy; import net.hellheim.spongetools.proxy.solid.item.ItemStackSnapshotProxy; -import net.hellheim.spongetools.resourcepack.item.Item; import net.hellheim.spongetools.resourcepack.item.ItemDefinition; +import net.hellheim.spongetools.resourcepack.item.ItemModel; import net.hellheim.spongetools.resourcepack.item.TintSource; import net.hellheim.spongetools.util.TranslationUtil; import net.kyori.adventure.text.Component; @@ -52,7 +52,7 @@ public class CustomItemTypeProperties implements private final ResourceKey key; private final DefaultedRegistryReference base; - private final Optional model; + private final Optional model; private final DeferredValueContainer data; private final Component name; @@ -78,7 +78,7 @@ protected CustomItemTypeProperties(final Builder builder) { } protected CustomItemTypeProperties( - final ResourceKey key, final RegistryKey base, final Optional model, DeferredValueContainer data + final ResourceKey key, final RegistryKey base, final Optional model, DeferredValueContainer data ) { this.key = key; this.base = base.asDefaultedReference(Sponge::server); @@ -100,11 +100,11 @@ public static Builder builder() { return new Builder(); } - public static P4, ResourceKey, RegistryKey, Optional, DeferredValueContainer> codecBuilder(Instance instance) { + public static P4, ResourceKey, RegistryKey, Optional, DeferredValueContainer> codecBuilder(Instance instance) { return instance.group( SpongeCodecs.RESOURCE_KEY.fieldOf("key").forGetter(CustomItemTypeProperties::key), SpongeCodecs.registryKey(RegistryTypes.ITEM_TYPE).fieldOf("base").forGetter(CustomItemTypeProperties::base), - Item.CODEC.optionalFieldOf("model").forGetter(CustomItemTypeProperties::model), + ItemDefinition.CODEC.optionalFieldOf("model").forGetter(CustomItemTypeProperties::model), DeferredValueContainer.codec(ItemStackSnapshot.empty()).optionalFieldOf("data", DeferredValueContainer.EMPTY).forGetter(CustomItemTypeProperties::getAsData) ); } @@ -128,7 +128,7 @@ public DefaultedRegistryReference base() { return this.base; } - public Optional model() { + public Optional model() { return this.model; } @@ -167,7 +167,7 @@ public static class Builder implements protected @Nullable ResourceKey key; protected @Nullable RegistryKey base; - protected @Nullable Item model; + protected @Nullable ItemDefinition model; protected @Nullable DeferredValueContainer data; public Builder() { @@ -185,20 +185,20 @@ public Builder base(final RegistryKey base) { return this; } - public Builder model(final Item model) { + public Builder model(final ItemDefinition model) { this.model = Objects.requireNonNull(model, "model"); return this; } - public Builder model(final ItemDefinition definition) { - return this.model(Item.of(definition)); + public Builder model(final ItemModel definition) { + return this.model(ItemDefinition.of(definition)); } public Builder simpleModel(final TintSource... tints) { if (this.key == null) { throw new IllegalStateException("key must be set"); } - return this.model(ItemDefinition.simple(this.key, tints)); + return this.model(ItemModel.simple(this.key, tints)); } public Builder data(final DeferredValueContainer data) { diff --git a/src/main/java/net/hellheim/spongetools/custom/item/DeferredItemType.java b/src/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java similarity index 98% rename from src/main/java/net/hellheim/spongetools/custom/item/DeferredItemType.java rename to src/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java index 41fa487..8990d41 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/DeferredItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item; +package net.hellheim.spongetools.custom.type.item; import java.util.function.Supplier; diff --git a/src/main/java/net/hellheim/spongetools/custom/item/EitherItemType.java b/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java similarity index 63% rename from src/main/java/net/hellheim/spongetools/custom/item/EitherItemType.java rename to src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java index 54537bf..3fb7b19 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/EitherItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java @@ -1,14 +1,11 @@ -package net.hellheim.spongetools.custom.item; +package net.hellheim.spongetools.custom.type.item; import java.util.IdentityHashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.Predicate; import java.util.function.Supplier; -import java.util.function.UnaryOperator; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.ResourceKeyed; @@ -24,6 +21,7 @@ import net.hellheim.spongetools.SpongeTools; import net.hellheim.spongetools.codec.list.RegistryCodecs; +import net.hellheim.spongetools.custom.type.EitherType; import net.hellheim.spongetools.proxy.solid.data.ValueContainerProxy; import net.hellheim.spongetools.proxy.solid.item.IItemProxy; import net.hellheim.spongetools.proxy.solid.item.ItemStackSnapshotProxy; @@ -36,7 +34,7 @@ * Wrapper for either {@link ItemType} or {@link CustomItemType}. */ public sealed abstract class EitherItemType - implements ResourceKeyed, ComponentLike, ValueContainerProxy, IconProxy, IItemProxy + implements EitherType, ResourceKeyed, ComponentLike, ValueContainerProxy, IconProxy, IItemProxy permits EitherItemType.Common, EitherItemType.Custom { private static final Map COMMON_MAP = new IdentityHashMap<>(); @@ -93,39 +91,13 @@ public static Optional resolve(final ResourceKey key) { return RegistryTypes.ITEM_TYPE .get() .findValue(key) - .map(type -> EitherItemType.common(type)) + .map(EitherItemType::common) .or(() -> CustomItemType.resolve(key) - .map(type -> EitherItemType.custom(type))); + .map(EitherItemType::custom)); } - public abstract boolean isCommon(); - - public abstract boolean isCustom(); - - public abstract Optional common(); - - public abstract Optional custom(); - - public abstract Either either(); - - public EitherItemType mapCommon(final UnaryOperator commonOperator) { - return this.map(commonOperator, UnaryOperator.identity()); - } - - public EitherItemType mapCustom(final UnaryOperator customOperator) { - return this.map(UnaryOperator.identity(), customOperator); - } - - public abstract EitherItemType map(UnaryOperator commonOperator, UnaryOperator customOperator); - - public abstract T apply(Function commonFunction, Function customFunction); - - public abstract void accept(Consumer commonAction, Consumer customAction); - - public abstract boolean test(Predicate commonTest, Predicate customTest); - public abstract boolean is(ItemStackLike stack); public boolean isAny(final ItemStackLike... stacks) { @@ -148,13 +120,9 @@ public boolean isAny(final Iterable stacks) { return false; } - @Override - public abstract int hashCode(); - - @Override - public abstract boolean equals(Object obj); - - protected static final class Common extends EitherItemType implements ItemTypeProxy { + protected static final class Common extends EitherItemType implements + EitherType.Common, + ItemTypeProxy { private final ItemType type; private final IconProxy icon; @@ -164,6 +132,11 @@ protected Common(final ItemType type) { this.icon = IconProxy.wrapTypeCached(() -> this.type); } + @Override + public ItemType get() { + return this.type; + }; + @Override public ItemStackSnapshot getAsIcon() { return this.icon.getAsIcon(); @@ -190,51 +163,14 @@ public ResourceKey key() { } @Override - public boolean isCommon() { - return true; - } - - @Override - public boolean isCustom() { - return false; - } - - @Override - public Optional common() { - return Optional.of(this.type); - } - - @Override - public Optional custom() { - return Optional.empty(); - } - - @Override - public Either either() { - return Either.left(this.type); - } - - @Override - public EitherItemType map(final UnaryOperator commonOperator, final UnaryOperator customOperator) { - final ItemType newType = commonOperator.apply(this.type); + public EitherItemType map( + final Function commonMapper, + final Function customMapper + ) { + final ItemType newType = commonMapper.apply(this.type); return newType == this.type ? this : EitherItemType.common(newType); } - @Override - public T apply(final Function commonMapper, final Function customMapper) { - return commonMapper.apply(this.type); - } - - @Override - public void accept(final Consumer commonAction, final Consumer customAction) { - commonAction.accept(this.type); - } - - @Override - public boolean test(final Predicate commonTest, final Predicate customTest) { - return commonTest.test(this.type); - } - @Override public boolean is(final ItemStackLike stack) { return ItemUtil.is(this.type, stack) && !CustomItemType.isCustom(stack); @@ -259,7 +195,9 @@ public boolean equals(final Object obj) { } } - protected static final class Custom extends EitherItemType implements ItemStackSnapshotProxy { + protected static final class Custom extends EitherItemType implements + EitherType.Custom, + ItemStackSnapshotProxy { private final CustomItemType type; @@ -267,6 +205,11 @@ protected Custom(final CustomItemType type) { this.type = Objects.requireNonNull(type, "type"); } + @Override + public CustomItemType get() { + return this.get(); + } + @Override public ItemStackSnapshot getAsIcon() { return this.type.getAsIcon(); @@ -293,51 +236,14 @@ public ResourceKey key() { } @Override - public boolean isCommon() { - return false; - } - - @Override - public boolean isCustom() { - return true; - } - - @Override - public Optional common() { - return Optional.empty(); - } - - @Override - public Optional custom() { - return Optional.of(this.type); - } - - @Override - public Either either() { - return Either.right(this.type); - } - - @Override - public EitherItemType map(final UnaryOperator commonOperator, final UnaryOperator customOperator) { - final CustomItemType newType = customOperator.apply(this.type); + public EitherItemType map( + final Function commonMapper, + final Function customMapper + ) { + final CustomItemType newType = customMapper.apply(this.type); return newType == this.type ? this : EitherItemType.custom(newType); } - @Override - public T apply(final Function commonMapper, final Function customMapper) { - return customMapper.apply(this.type); - } - - @Override - public void accept(final Consumer commonAction, final Consumer customAction) { - customAction.accept(this.type); - } - - @Override - public boolean test(final Predicate commonTest, final Predicate customTest) { - return customTest.test(this.type); - } - @Override public boolean is(final ItemStackLike stack) { return CustomItemType.is(this.type, stack); diff --git a/src/main/java/net/hellheim/spongetools/custom/item/IDefaultedCustomItemType.java b/src/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java similarity index 88% rename from src/main/java/net/hellheim/spongetools/custom/item/IDefaultedCustomItemType.java rename to src/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java index 4b4631f..6603e5d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/IDefaultedCustomItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item; +package net.hellheim.spongetools.custom.type.item; import java.util.Optional; @@ -9,7 +9,7 @@ import net.hellheim.spongetools.object.DeferredValueContainer; import net.hellheim.spongetools.proxy.solid.data.ValueContainerProxy; -import net.hellheim.spongetools.resourcepack.item.Item; +import net.hellheim.spongetools.resourcepack.item.ItemDefinition; import net.kyori.adventure.text.Component; public interface IDefaultedCustomItemType extends CustomItemType, ValueContainerProxy { @@ -32,7 +32,7 @@ default DefaultedRegistryReference base() { } @Override - default Optional model() { + default Optional model() { return this.properties().model(); } diff --git a/src/main/java/net/hellheim/spongetools/custom/item/IconProxy.java b/src/main/java/net/hellheim/spongetools/custom/type/item/IconProxy.java similarity index 94% rename from src/main/java/net/hellheim/spongetools/custom/item/IconProxy.java rename to src/main/java/net/hellheim/spongetools/custom/type/item/IconProxy.java index 9e80aa6..f45f572 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/IconProxy.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/IconProxy.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item; +package net.hellheim.spongetools.custom.type.item; import java.util.function.Supplier; diff --git a/src/main/java/net/hellheim/spongetools/custom/item/data/CustomConsumeEffect.java b/src/main/java/net/hellheim/spongetools/custom/type/item/data/CustomConsumeEffect.java similarity index 97% rename from src/main/java/net/hellheim/spongetools/custom/item/data/CustomConsumeEffect.java rename to src/main/java/net/hellheim/spongetools/custom/type/item/data/CustomConsumeEffect.java index 34144f2..9bd6662 100644 --- a/src/main/java/net/hellheim/spongetools/custom/item/data/CustomConsumeEffect.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/data/CustomConsumeEffect.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.item.data; +package net.hellheim.spongetools.custom.type.item.data; import java.util.function.Function; diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateHolderEvent.java b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateHolderEvent.java new file mode 100644 index 0000000..59f9270 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateHolderEvent.java @@ -0,0 +1,16 @@ +package net.hellheim.spongetools.event; + +import org.spongepowered.api.event.lifecycle.LifecycleEvent; + +import net.hellheim.spongetools.custom.type.block.BlockStateDispatcher; +import net.hellheim.spongetools.custom.type.block.BlockStateHolder; +import net.hellheim.spongetools.custom.type.block.BlockStateProvider; + +public interface RegisterBlockStateHolderEvent extends LifecycleEvent { + + BlockStateDispatcher dispatcher(); + + default void register(final BlockStateHolder holder, final BlockStateProvider provider) { + this.dispatcher().submit(holder, provider); + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemTransforms.java b/src/main/java/net/hellheim/spongetools/resourcepack/ItemTransform.java similarity index 81% rename from src/main/java/net/hellheim/spongetools/resourcepack/item/ItemTransforms.java rename to src/main/java/net/hellheim/spongetools/resourcepack/ItemTransform.java index 133898f..c270369 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemTransforms.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/ItemTransform.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.resourcepack.item; +package net.hellheim.spongetools.resourcepack; import java.util.HashMap; import java.util.Map; @@ -14,15 +14,15 @@ import net.hellheim.spongetools.codec.list.MathCodecs; import net.hellheim.spongetools.codec.list.StringRepresentableCodecs; -public record ItemTransforms(Map transforms) { +public record ItemTransform(Map transforms) { - public static final ItemTransforms DEFAULT = new ItemTransforms(Map.of()); + public static final ItemTransform DEFAULT = new ItemTransform(Map.of()); - public static final Codec CODEC = + public static final Codec CODEC = Codec.unboundedMap(StringRepresentableCodecs.ITEM_DISPLAY_TYPE, MathCodecs.TRANSFORM) - .xmap(ItemTransforms::new, ItemTransforms::transforms); + .xmap(ItemTransform::new, ItemTransform::transforms); - public ItemTransforms(final Map transforms) { + public ItemTransform(final Map transforms) { this.transforms = Map.copyOf(transforms); } @@ -31,8 +31,8 @@ public static Builder builder() { } public static class Builder implements - org.spongepowered.api.util.Builder, - CopyableBuilder { + org.spongepowered.api.util.Builder, + CopyableBuilder { private final Map transforms = new HashMap<>(); @@ -86,7 +86,7 @@ public Builder putAll(final Transform transform, final Iterable Minecraft Wiki + */ +public record Model(TexturedModel model, ItemTransform display, List parts, GuiLight guiLight, boolean ambientOcclusion) { + + public static final boolean DEFAULT_AMBIENT_OCCLUSION = true; + + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + TexturedModel.MAP_CODEC.forGetter(Model::model), + ItemTransform.CODEC.optionalFieldOf("display", ItemTransform.DEFAULT).forGetter(Model::display), + ModelPart.CODEC.listOf().optionalFieldOf("elements", List.of()).forGetter(Model::parts), + GuiLight.CODEC.optionalFieldOf("gui_light", GuiLight.DEFAULT).forGetter(Model::guiLight), + Codec.BOOL.optionalFieldOf("ambientocclusion", Model.DEFAULT_AMBIENT_OCCLUSION).forGetter(Model::ambientOcclusion) + ).apply(instance, Model::new)); + + public Model( + final TexturedModel model, + final ItemTransform display, final List parts, + final GuiLight guiLight, final boolean ambientOcclusion + ) { + this.model = Objects.requireNonNull(model, "model"); + this.parts = Objects.requireNonNull(parts, "parts"); + this.display = Objects.requireNonNull(display, "display"); + this.guiLight = Objects.requireNonNull(guiLight, "guiLight"); + this.ambientOcclusion = ambientOcclusion; + } + + public static DefaultedRegistryType registry() { + return SpongeTools.Registries.MODEL; + } + + public static Codec registryCodec() { + return RegistryCodecs.MODEL; + } + + public static Model of(final ModelTemplate parent, final Textures textures, final ModelPart... parts) { + return Model.of(TexturedModel.of(parent, textures), parts); + } + + public static Model of(final ModelTemplate parent, final Textures textures, final ItemTransform display, final ModelPart... parts) { + return Model.of(TexturedModel.of(parent, textures), display, parts); + } + + public static Model of(final TexturedModel model, final ModelPart... parts) { + return Model.of(model, ItemTransform.DEFAULT, parts); + } + + public static Model of(final TexturedModel model, final ItemTransform display, final ModelPart... parts) { + return Model.builder().model(model).display(display).parts(parts).build(); + } + + public static Builder builder() { + return new Builder(); + } + + public ModelTemplate parent() { + return this.model().parent(); + } + + public Textures textures() { + return this.model().textures(); + } + + public static final class Builder implements + org.spongepowered.api.util.Builder, + CopyableBuilder { + + private @Nullable ModelTemplate parent; + private @Nullable Textures textures; + private ItemTransform display; + private GuiLight guiLight; + private boolean ambientOcclusion; + private final List parts = new ArrayList<>(); + + private Builder() { + this.reset(); + } + + public Builder display(final ItemTransform display) { + this.display = Objects.requireNonNull(display, "display"); + return this; + } + + public Builder display(final ItemTransform.Builder builder) { + return this.display(Objects.requireNonNull(builder, "builder").build()); + } + + public Builder display(final Consumer configurator) { + final ItemTransform.Builder builder = ItemTransform.builder(); + Objects.requireNonNull(configurator, "configurator").accept(builder); + return this.display(builder); + } + + public Builder model(final TexturedModel model) { + Objects.requireNonNull(model, "model"); + return this.parent(model.parent()).textures(model.textures()); + } + + public Builder parent(final ModelTemplate parent) { + this.parent = Objects.requireNonNull(parent, "parent"); + return this; + } + + public Builder textures(final Textures textures) { + this.textures = Objects.requireNonNull(textures, "textures"); + return this; + } + + public Builder textures(final Textures.Builder builder) { + return this.textures(Objects.requireNonNull(builder, "builder").build()); + } + + public Builder textures(final Consumer configurator) { + final Textures.Builder builder = Textures.builder(); + Objects.requireNonNull(configurator, "configurator").accept(builder); + return this.textures(builder); + } + + public Builder light(final GuiLight guiLight) { + this.guiLight = Objects.requireNonNull(guiLight, "guiLight"); + return this; + } + + public Builder occlusion(final boolean ambientOcclusion) { + this.ambientOcclusion = ambientOcclusion; + return this; + } + + public Builder parts(final ModelPart.Builder... builders) { + return this.parts(Arrays.stream(Objects.requireNonNull(builders, "builders")).map(ModelPart.Builder::build)); + } + + public Builder parts(final ModelPart... parts) { + return this.parts(Arrays.stream(Objects.requireNonNull(parts, "parts"))); + } + + public Builder parts(final Collection parts) { + return this.parts(Objects.requireNonNull(parts, "parts").stream()); + } + + private Builder parts(final Stream parts) { + parts.forEach(part -> this.parts.add(Objects.requireNonNull(part, "part"))); + return this; + } + + @Override + public Builder from(final Model model) { + return this.model(model.model()) + .display(model.display()) + .light(model.guiLight()) + .occlusion(model.ambientOcclusion()) + .parts(model.parts()); + } + + @Override + public Builder reset() { + this.parent = null; + this.textures = null; + this.display = ItemTransform.DEFAULT; + this.guiLight = GuiLight.DEFAULT; + this.ambientOcclusion = Model.DEFAULT_AMBIENT_OCCLUSION; + this.parts.clear(); + return this; + } + + @Override + public Model build() { + if (this.parent == null) { + throw new IllegalStateException("parent must be set"); + } else if (this.textures == null) { + throw new IllegalStateException("textures must be set"); + } + + return new Model( + TexturedModel.of(this.parent, this.textures), + this.display, this.parts, + this.guiLight, this.ambientOcclusion); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ModelPart.java b/src/main/java/net/hellheim/spongetools/resourcepack/ModelPart.java new file mode 100644 index 0000000..b4fc1be --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/ModelPart.java @@ -0,0 +1,199 @@ +package net.hellheim.spongetools.resourcepack; + +import java.util.EnumMap; +import java.util.Map; +import java.util.Objects; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.util.CopyableBuilder; +import org.spongepowered.api.util.Direction; +import org.spongepowered.math.vector.Vector3d; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.hellheim.spongetools.codec.list.MathCodecs; +import net.hellheim.spongetools.codec.list.SpongeCodecs; + +public final class ModelPart { + + public static final boolean DEFAULT_SHADE = true; + public static final int DEFAULT_LIGHT_EMISSION = 0; + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + MathCodecs.VECTOR3D.validate(ModelPart::validatePoint).fieldOf("from").forGetter(ModelPart::from), + MathCodecs.VECTOR3D.validate(ModelPart::validatePoint).fieldOf("to").forGetter(ModelPart::from), + ModelPartRotation.CODEC.fieldOf("rotation").forGetter(ModelPart::rotation), + Codec.BOOL.optionalFieldOf("shade", ModelPart.DEFAULT_SHADE).forGetter(ModelPart::shade), + Codec.INT.validate(ModelPart::validateLight).optionalFieldOf("light_emission", ModelPart.DEFAULT_LIGHT_EMISSION).forGetter(ModelPart::lightEmission), + Codec.unboundedMap(SpongeCodecs.CARDINAL_DIRECTION, ModelPartFace.CODEC).optionalFieldOf("faces", Map.of()).forGetter(ModelPart::faces) + ).apply(instance, ModelPart::new)); + + private final Vector3d from; + private final Vector3d to; + private final ModelPartRotation rotation; + private final boolean shade; + private final int lightEmission; + private final Map faces; + + private ModelPart( + final Vector3d from, final Vector3d to, final ModelPartRotation rotation, + final boolean shade, final int lightEmission, final Map faces + ) { + this.from = from; + this.to = to; + this.rotation = rotation; + this.shade = shade; + this.lightEmission = lightEmission; + this.faces = Map.copyOf(faces); + } + + public static Builder builder() { + return new Builder(); + } + + private static DataResult validatePoint(final Vector3d vec) { + return ModelPart.validatePointValue(vec, vec.x()) + .flatMap($ -> ModelPart.validatePointValue(vec, vec.y())) + .flatMap($ -> ModelPart.validatePointValue(vec, vec.z())); + } + + private static DataResult validatePointValue(final Vector3d vec, final double value) { + return value < -16.0D || value > 32.0D + ? DataResult.error(() -> "Point values must be in [-16;32] range: " + vec.toString()) + : DataResult.success(vec); + } + + private static DataResult validateLight(final int lightEmission) { + return lightEmission < 0 || lightEmission > 15 + ? DataResult.error(() -> "Light emission must be between 0 and 15: " + lightEmission) + : DataResult.success(lightEmission); + } + + public Vector3d from() { + return this.from; + } + + public Vector3d to() { + return this.to; + } + + public ModelPartRotation rotation() { + return this.rotation; + } + + public boolean shade() { + return this.shade; + } + + public int lightEmission() { + return this.lightEmission; + } + + public Map faces() { + return this.faces; + } + + public static final class Builder implements + org.spongepowered.api.util.Builder, + CopyableBuilder { + + private @Nullable Vector3d from; + private @Nullable Vector3d to; + private @Nullable ModelPartRotation rotation; + private boolean shade; + private int lightEmission; + private final Map faces = new EnumMap<>(Direction.class); + + private Builder() { + this.reset(); + } + + private Vector3d validatePoint(final Vector3d vec) { + return ModelPart.validatePoint(vec).getOrThrow(IllegalArgumentException::new); + } + + private int validateLight(final int lightEmission) { + return ModelPart.validateLight(lightEmission).getOrThrow(IllegalArgumentException::new); + } + + public Builder from(final Vector3d from) { + this.from = this.validatePoint(Objects.requireNonNull(from, "from")); + return this; + } + + public Builder to(final Vector3d to) { + this.to = this.validatePoint(Objects.requireNonNull(to, "to")); + return this; + } + + public Builder rotation(final ModelPartRotation rotation) { + this.rotation = Objects.requireNonNull(rotation, "rotation"); + return this; + } + + public Builder shade(final boolean shade) { + this.shade = shade; + return this; + } + + public Builder lightEmission(final int lightEmission) { + this.lightEmission = this.validateLight(lightEmission); + return this; + } + + public Builder face(final Direction direction, final ModelPartFace face) { + Objects.requireNonNull(direction, "direction"); + Objects.requireNonNull(face, "face"); + if (!direction.isCardinal()) { + throw new IllegalArgumentException("direction must be cardinal"); + } + + this.faces.put(direction, face); + return this; + } + + public Builder faces(final Map faces) { + Objects.requireNonNull(faces, "faces").forEach(this::face); + return this; + } + + @Override + public Builder from(final ModelPart element) { + Objects.requireNonNull(element, "element"); + return this + .from(element.from()) + .to(element.to()) + .rotation(element.rotation()) + .shade(element.shade()) + .lightEmission(element.lightEmission()) + .faces(element.faces()); + } + + @Override + public Builder reset() { + this.from = null; + this.to = null; + this.rotation = null; + this.shade = ModelPart.DEFAULT_SHADE; + this.lightEmission = ModelPart.DEFAULT_LIGHT_EMISSION; + this.faces.clear(); + return this; + } + + @Override + public ModelPart build() { + if (this.from == null) { + throw new IllegalStateException("from must be set"); + } else if (this.to == null) { + throw new IllegalStateException("to must be set"); + } else if (this.rotation == null) { + throw new IllegalStateException("rotation must be set"); + } + + return new ModelPart( + this.from, this.to, this.rotation, this.shade, this.lightEmission, this.faces); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java b/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java new file mode 100644 index 0000000..d212b6f --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java @@ -0,0 +1,166 @@ +package net.hellheim.spongetools.resourcepack; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.util.CopyableBuilder; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.util.rotation.Rotation; +import org.spongepowered.math.matrix.Matrix2d; +import org.spongepowered.math.vector.Vector2d; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.hellheim.spongetools.codec.list.MathCodecs; +import net.hellheim.spongetools.codec.list.SpongeCodecs; +import net.hellheim.spongetools.util.GeomUtil; + +public final class ModelPartFace { + + public static final int DEFAULT_TINT = -1; + public static final Rotation DEFAULT_ROTATION = GeomUtil.ROT_0; + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + TextureSlot.CODEC_HASHED.fieldOf("texture").forGetter(ModelPartFace::texture), + MathCodecs.MATRIX2D.optionalFieldOf("uv").forGetter(ModelPartFace::uv), + SpongeCodecs.CARDINAL_DIRECTION.optionalFieldOf("cullface").forGetter(ModelPartFace::cullface), + SpongeCodecs.ROTATION_BY_ANGLE.optionalFieldOf("rotation", ModelPartFace.DEFAULT_ROTATION).forGetter(ModelPartFace::rotation), + Codec.INT.optionalFieldOf("tintindex", ModelPartFace.DEFAULT_TINT).forGetter(ModelPartFace::tintIndex) + ).apply(instance, ModelPartFace::new)); + + private final TextureSlot texture; + private final Optional uv; + private final Optional cullface; + private final Rotation rotation; + private final int tintIndex; + + private ModelPartFace( + final TextureSlot texture, + final Optional uv, final Optional cullface, + final Rotation rotation, final int tintIndex + ) { + this.texture = texture; + this.uv = uv; + this.cullface = cullface; + this.rotation = rotation; + this.tintIndex = tintIndex; + } + + public static Builder builder() { + return new Builder(); + } + + public TextureSlot texture() { + return this.texture; + } + + public Optional uv() { + return this.uv; + } + + public Optional cullface() { + return this.cullface; + } + + public Rotation rotation() { + return this.rotation; + } + + public int tintIndex() { + return this.tintIndex; + } + + public static final class Builder implements + org.spongepowered.api.util.Builder, + CopyableBuilder { + + private @Nullable Matrix2d uv; + private @Nullable TextureSlot texture; + private @Nullable Direction cullface; + private @Nullable Rotation rotation; + private int tintIndex; + + private Builder() { + this.reset(); + } + + public Builder texture(final String textureId) { + return this.texture(TextureSlot.of(textureId)); + } + + public Builder texture(final TextureSlot texture) { + this.texture = Objects.requireNonNull(texture, "texture"); + return this; + } + + public Builder uv(final double x1, final double y1, final double x2, final double y2) { + return this.uv(new Matrix2d(x1, y1, x2, y2)); + } + + public Builder uv(final Vector2d u, final Vector2d v) { + return this.uv(new Matrix2d(u.x(), u.y(), v.x(), v.y())); + } + + public Builder uv(final Matrix2d uv) { + this.uv = Objects.requireNonNull(uv, "uv"); + return this; + } + + public Builder cullface(final Direction cullface) { + Objects.requireNonNull(cullface, "cullface"); + if (!cullface.isCardinal()) { + throw new IllegalArgumentException("cullface must be cardinal"); + } + + this.cullface = cullface; + return this; + } + + public Builder rotation(final Rotation rotation) { + this.rotation = Objects.requireNonNull(rotation, "rotation"); + return this; + } + + public Builder rotation(final Supplier rotationSupplier) { + return this.rotation(Objects.requireNonNull(rotationSupplier, "rotationSupplier").get()); + } + + public Builder tint(final int tintIndex) { + this.tintIndex = tintIndex; + return this; + } + + @Override + public Builder from(final ModelPartFace face) { + Objects.requireNonNull(face, "face"); + this.reset(); + face.uv().ifPresent(this::uv); + face.cullface.ifPresent(this::cullface); + return this + .texture(face.texture()) + .rotation(face.rotation()) + .tint(face.tintIndex()); + } + + @Override + public Builder reset() { + this.texture = null; + this.uv = null; + this.cullface = null; + this.rotation = ModelPartFace.DEFAULT_ROTATION; + this.tintIndex = ModelPartFace.DEFAULT_TINT; + return this; + } + + @Override + public ModelPartFace build() { + return new ModelPartFace( + this.texture, + Optional.ofNullable(this.uv), Optional.ofNullable(this.cullface), + this.rotation, this.tintIndex); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java b/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java new file mode 100644 index 0000000..a570eb2 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java @@ -0,0 +1,92 @@ +package net.hellheim.spongetools.resourcepack; + +import java.util.Objects; + +import org.spongepowered.api.util.Axis; +import org.spongepowered.math.vector.Vector3d; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.hellheim.spongetools.codec.list.MathCodecs; +import net.hellheim.spongetools.codec.list.SpongeCodecs; + +public final class ModelPartRotation { + + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + MathCodecs.VECTOR3D.fieldOf("origin").forGetter(ModelPartRotation::origin), + SpongeCodecs.AXIS.fieldOf("axis").forGetter(ModelPartRotation::axis), + Codec.DOUBLE.fieldOf("angle").forGetter(ModelPartRotation::angle), + Codec.BOOL.fieldOf("rescale").forGetter(ModelPartRotation::rescale) + ).apply(instance, ModelPartRotation::new)) + .validate(ModelPartRotation::validate); + + private final Vector3d origin; + private final Axis axis; + private final double angle; + private final boolean rescale; + + private ModelPartRotation( + final Vector3d origin, final Axis axis, final double angle, final boolean rescale + ) { + this.origin = origin; + this.axis = axis; + this.angle = angle; + this.rescale = rescale; + } + + public static ModelPartRotation of( + final Vector3d origin, final Axis axis, final double angle, final boolean rescale + ) { + Objects.requireNonNull(origin, "origin"); + Objects.requireNonNull(axis, "axis"); + final ModelPartRotation rotation = new ModelPartRotation(origin, axis, angle, rescale); + rotation.validate().ifError(error -> { + throw new IllegalArgumentException(error.message()); + }); + return rotation; + } + + private DataResult validate() { + if (this.angle != 0.0F && Math.abs(this.angle) != 22.5D && Math.abs(this.angle) != 45.0D) { + return DataResult.error(() -> + "Invalid angle " + this.angle + ", only -45/-22.5/0/22.5/45 allowed"); + } else { + return DataResult.success(this); + } + } + + public Vector3d origin() { + return this.origin; + } + + public Axis axis() { + return this.axis; + } + + public double angle() { + return this.angle; + } + + public boolean rescale() { + return this.rescale; + } + + public ModelPartRotation withOrigin(final Vector3d origin) { + return ModelPartRotation.of(origin, this.axis, this.angle, this.rescale); + } + + public ModelPartRotation withAxis(final Axis axis) { + return ModelPartRotation.of(this.origin, axis, this.angle, this.rescale); + } + + public ModelPartRotation withAngle(final double angle) { + return ModelPartRotation.of(this.origin, this.axis, angle, this.rescale); + } + + public ModelPartRotation withRescale(final boolean rescale) { + return ModelPartRotation.of(this.origin, this.axis, this.angle, rescale); + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java b/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java index cc00a41..489ce6f 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java @@ -1,5 +1,7 @@ package net.hellheim.spongetools.resourcepack; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -7,6 +9,7 @@ import org.spongepowered.api.util.annotation.CatalogedBy; import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; import net.hellheim.spongetools.codec.LateBoundIdMapper; @@ -14,18 +17,50 @@ * TextureSlot will pick textures from parent slots if its own texture is absent. */ @CatalogedBy(TextureSlots.class) -public record TextureSlot(String id, Optional parent) implements StringRepresentable { +public final class TextureSlot implements StringRepresentable { + private static final Map VALUES = new HashMap<>(); private static final LateBoundIdMapper ID_MAPPER = new LateBoundIdMapper<>(); - public static final Codec CODEC = ID_MAPPER.codec(Codec.STRING); + public static final Codec CODEC = TextureSlot.ID_MAPPER.codec(Codec.STRING); + public static final Codec CODEC_HASHED = TextureSlot.ID_MAPPER.codec(Codec.STRING + .flatComapMap( + id -> "#" + id, + id -> !id.isEmpty() && id.charAt(0) == '#' + ? DataResult.success(id.substring(1)) + : DataResult.error(() -> "id must have # in the begining"))); - public TextureSlot(final String id, final Optional parent) { - this.id = Objects.requireNonNull(id, "id"); - this.parent = Objects.requireNonNull(parent, "parent"); + private final String id; + private final Optional parent; + + private TextureSlot(final String id, final Optional parent) { + this.id = id; + this.parent = parent; TextureSlot.ID_MAPPER.put(id, this); } + public static TextureSlot of(final String id) { + return TextureSlot.of(id, Optional.empty()); + } + + public static TextureSlot of(final String id, final TextureSlot parent) { + return TextureSlot.of(id, Optional.of(parent)); + } + + public static TextureSlot of(final String id, final Optional parent) { + Objects.requireNonNull(id, "id"); + Objects.requireNonNull(parent, "parent"); + return TextureSlot.VALUES.computeIfAbsent(id, $ -> new TextureSlot(id, parent)); + } + + public String id() { + return this.id; + } + + public Optional parent() { + return this.parent; + } + @Override public String serializationString() { return this.id; diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java b/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java index 627ccc1..dfe3c85 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java @@ -1,70 +1,54 @@ package net.hellheim.spongetools.resourcepack; -import java.util.Optional; - -import org.checkerframework.checker.nullness.qual.Nullable; - public final class TextureSlots { public static final TextureSlot - ALL = TextureSlots.of("all"), - TEXTURE = TextureSlots.of("texture", ALL), - PARTICLE = TextureSlots.of("particle", TEXTURE), - END = TextureSlots.of("end", ALL), - BOTTOM = TextureSlots.of("bottom", END), - TOP = TextureSlots.of("top", END), - FRONT = TextureSlots.of("front", ALL), - BACK = TextureSlots.of("back", ALL), - SIDE = TextureSlots.of("side", ALL), - NORTH = TextureSlots.of("north", SIDE), - SOUTH = TextureSlots.of("south", SIDE), - EAST = TextureSlots.of("east", SIDE), - WEST = TextureSlots.of("west", SIDE), - UP = TextureSlots.of("up"), - DOWN = TextureSlots.of("down"), - CROSS = TextureSlots.of("cross"), - CROSS_EMISSIVE = TextureSlots.of("cross_emissive"), - PLANT = TextureSlots.of("plant"), - WALL = TextureSlots.of("wall", ALL), - RAIL = TextureSlots.of("rail"), - WOOL = TextureSlots.of("wool"), - PATTERN = TextureSlots.of("pattern"), - PANE = TextureSlots.of("pane"), - EDGE = TextureSlots.of("edge"), - FAN = TextureSlots.of("fan"), - STEM = TextureSlots.of("stem"), - UPPER_STEM = TextureSlots.of("upperstem"), - CROP = TextureSlots.of("crop"), - DIRT = TextureSlots.of("dirt"), - FIRE = TextureSlots.of("fire"), - LANTERN = TextureSlots.of("lantern"), - PLATFORM = TextureSlots.of("platform"), - UNSTICKY = TextureSlots.of("unsticky"), - TORCH = TextureSlots.of("torch"), - LAYER0 = TextureSlots.of("layer0"), - LAYER1 = TextureSlots.of("layer1"), - LAYER2 = TextureSlots.of("layer2"), - LIT_LOG = TextureSlots.of("lit_log"), - CANDLE = TextureSlots.of("candle"), - INSIDE = TextureSlots.of("inside"), - CONTENT = TextureSlots.of("content"), - INNER_TOP = TextureSlots.of("inner_top"), - FLOWERBED = TextureSlots.of("flowerbed") + ALL = TextureSlot.of("all"), + TEXTURE = TextureSlot.of("texture", ALL), + PARTICLE = TextureSlot.of("particle", TEXTURE), + END = TextureSlot.of("end", ALL), + BOTTOM = TextureSlot.of("bottom", END), + TOP = TextureSlot.of("top", END), + FRONT = TextureSlot.of("front", ALL), + BACK = TextureSlot.of("back", ALL), + SIDE = TextureSlot.of("side", ALL), + NORTH = TextureSlot.of("north", SIDE), + SOUTH = TextureSlot.of("south", SIDE), + EAST = TextureSlot.of("east", SIDE), + WEST = TextureSlot.of("west", SIDE), + UP = TextureSlot.of("up"), + DOWN = TextureSlot.of("down"), + CROSS = TextureSlot.of("cross"), + CROSS_EMISSIVE = TextureSlot.of("cross_emissive"), + PLANT = TextureSlot.of("plant"), + WALL = TextureSlot.of("wall", ALL), + RAIL = TextureSlot.of("rail"), + WOOL = TextureSlot.of("wool"), + PATTERN = TextureSlot.of("pattern"), + PANE = TextureSlot.of("pane"), + EDGE = TextureSlot.of("edge"), + FAN = TextureSlot.of("fan"), + STEM = TextureSlot.of("stem"), + UPPER_STEM = TextureSlot.of("upperstem"), + CROP = TextureSlot.of("crop"), + DIRT = TextureSlot.of("dirt"), + FIRE = TextureSlot.of("fire"), + LANTERN = TextureSlot.of("lantern"), + PLATFORM = TextureSlot.of("platform"), + UNSTICKY = TextureSlot.of("unsticky"), + TORCH = TextureSlot.of("torch"), + LAYER0 = TextureSlot.of("layer0"), + LAYER1 = TextureSlot.of("layer1"), + LAYER2 = TextureSlot.of("layer2"), + LIT_LOG = TextureSlot.of("lit_log"), + CANDLE = TextureSlot.of("candle"), + INSIDE = TextureSlot.of("inside"), + CONTENT = TextureSlot.of("content"), + INNER_TOP = TextureSlot.of("inner_top"), + FLOWERBED = TextureSlot.of("flowerbed") ; - public static TextureSlot of(final String id, final Optional parent) { - return new TextureSlot(id, parent); - } - - public static TextureSlot of(final String id, final @Nullable TextureSlot parent) { - return TextureSlots.of(id, Optional.ofNullable(parent)); - } - - public static TextureSlot of(final String id) { - return TextureSlots.of(id, Optional.empty()); - } - private TextureSlots() { } } diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java index 5218a2e..55f0935 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java @@ -1,49 +1,99 @@ package net.hellheim.spongetools.resourcepack.block; import java.util.ArrayList; -import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Stream; -import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; -import org.spongepowered.api.state.StateContainer; +import org.spongepowered.api.registry.DefaultedRegistryType; import org.spongepowered.api.state.StateProperty; import org.spongepowered.api.util.CopyableBuilder; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.RegistryCodecs; + +/** + * @see Minecraft Wiki + */ public interface BlockDefinition { - static MultiVariant.Builder multiVariant(final Supplier> containerSupplier) { - return BlockDefinition.multiVariant(Objects.requireNonNull(containerSupplier, "containerSupplier").get()); + Codec CODEC = StateCodec.BLOCK_DEFINITION; + + public static DefaultedRegistryType registry() { + return SpongeTools.Registries.BLOCK_DEFINITION; } - static MultiVariant.Builder multiVariant(final StateContainer container) { - return new MultiVariant.Builder(containerSupplier); + public static Codec registryCodec() { + return RegistryCodecs.BLOCK_DEFINITION; } - final record MultiVariant(StateDispatch dispatch) implements BlockDefinition { + static MultiVariant.Builder variant(final Supplier blockSupplier) { + return BlockDefinition.variant(Objects.requireNonNull(blockSupplier, "blockSupplier").get()); + } + + static MultiVariant.Builder variant(final BlockType block) { + return new MultiVariant.Builder(block); + } + + static MultiPart.Builder part(final Supplier blockSupplier) { + return BlockDefinition.part(Objects.requireNonNull(blockSupplier, "blockSupplier").get()); + } + + static MultiPart.Builder part(final BlockType block) { + return new MultiPart.Builder(block); + } + + BlockType block(); + + Builder toBuilder(); + + BlockDefinition expandWith(BlockState state, List variants); + + final class MultiVariant implements BlockDefinition { + + public static final Codec CODEC = StateCodec.MULTI_VARIANT; + + private final BlockType block; + private final StateDispatch dispatch; + + private MultiVariant(final BlockType block, final StateDispatch dispatch) { + this.block = block; + this.dispatch = dispatch; + } - public static final Codec CODEC = RecordCodecBuilder.create( - instance -> instance.group( - StateDispatch.CODEC.fieldOf("variants").forGetter(null) - ).apply(null, null)).validate(null); + @Override + public BlockType block() { + return this.block; + } + + public StateDispatch dispatch() { + return this.dispatch; + } + + @Override + public Builder toBuilder() { + return BlockDefinition.variant(this.block()).from(this); + } - public MultiVariant(final StateDispatch dispatch) { - this.dispatch = Objects.requireNonNull(dispatch, "dispatch"); + @Override + public MultiVariant expandWith(final BlockState state, final List variants) { + return this.withDispatchBuilder(b -> b.add(state, variants)); } - public Builder toBuilder(final StateContainer container) { - return BlockDefinition.multiVariant(container).from(this); + public MultiVariant withDispatchBuilder(final UnaryOperator> dispatchBuilderOperator) { + Objects.requireNonNull(dispatchBuilderOperator, "dispatchBuilderOperator"); + return this.withDispatch(dispatch -> dispatchBuilderOperator.apply(dispatch.toBuilder()).build()); } public MultiVariant withDispatch(final UnaryOperator dispatchOperator) { @@ -53,13 +103,13 @@ public MultiVariant withDispatch(final UnaryOperator dispatchOper public static final class Builder implements BlockDefinition.Builder { - private final StateContainer container; + private final BlockType block; private final List baseVariants = new ArrayList<>(); private final List dispatches = new ArrayList<>(); private final Set> seenProperties = new HashSet<>(); - private Builder(StateContainer container) { - this.container = Objects.requireNonNull(container, "container"); + private Builder(BlockType block) { + this.block = Objects.requireNonNull(block, "block"); this.reset(); } @@ -101,10 +151,10 @@ public Builder dispatch(final Iterable dispatches) { private void tryDispatch(final StateDispatch dispatch) { Objects.requireNonNull(dispatch, "dispatch"); for (final StateProperty property : dispatch.properties()) { - if (this.container.findStateProperty(property.name()).orElse(null) != property) { - throw new IllegalStateException("Property " + property + " is not defined for container " + this.container); + if (!this.block.stateProperties().contains(property)) { + throw new IllegalStateException("Property " + property + " is not defined for block " + this.block); } else if (!this.seenProperties.add(property)) { - throw new IllegalStateException("Values of property " + property + " already defined for container " + this.container); + throw new IllegalStateException("Values of property " + property + " already defined for block " + this.block); } } @@ -140,7 +190,7 @@ public MultiVariant build() { final var builder = StateDispatch.raw(); stream.forEach(pair -> builder.add(pair.getFirst(), pair.getSecond())); - return new MultiVariant(builder.build()); + return new MultiVariant(this.block, builder.build()); } private static List mergeVariants( @@ -155,10 +205,113 @@ private static List mergeVariants( } } - record MultiPart() implements BlockDefinition { + final class MultiPart implements BlockDefinition { + private final BlockType block; + private final List parts; + private MultiPart(final BlockType block, final List parts) { + this.block = block; + this.parts = List.copyOf(parts); + } + + @Override + public BlockType block() { + return this.block; + } + public List parts() { + return this.parts; + } + + @Override + public Builder toBuilder() { + return BlockDefinition.part(this.block()).from(this); + } + + @Override + public BlockDefinition expandWith(final BlockState state, final List variants) { + final Builder builder = BlockDefinition.part(this.block); + final StateCondition isState = StateCondition.is(state); + builder.add(StatePart.of(isState, variants)); + + final StateCondition notState = isState.negate(); + this.parts.forEach(part -> { + final Optional oldCondition = part.condition(); + final StateCondition newCondition = oldCondition.isEmpty() + ? notState + : StateCondition.and(oldCondition.get(), notState); + builder.add(StatePart.of(newCondition, part.variants())); + }); + + return builder.build(); + } + + public static final class Builder implements BlockDefinition.Builder { + + private final BlockType block; + private final List parts = new ArrayList<>(); + private final Set> seenProperties = new HashSet<>(); + + private Builder(final BlockType block) { + this.block = Objects.requireNonNull(block, "block"); + } + + public Builder add(final StatePart... parts) { + for (final StatePart part : Objects.requireNonNull(parts, "parts")) { + this.addPart(part); + } + + return this; + } + + public Builder add(final Iterable parts) { + for (final StatePart part : Objects.requireNonNull(parts, "parts")) { + this.addPart(part); + } + + return this; + } + + private void addPart(final StatePart part) { + Objects.requireNonNull(part, "part"); + if (part.condition().orElse(null) == StateCondition.alwaysFalse()) { + // @see #build + // return; + } + + for (final StateProperty property : part.properties()) { + if (!this.block.stateProperties().contains(property)) { + throw new IllegalStateException("Property " + property + " is not defined for block " + this.block); + } + } + } + + @Override + public Builder from(final MultiPart definition) { + return this.reset().add(Objects.requireNonNull(definition, "definition").parts()); + } + + @Override + public Builder reset() { + this.parts.clear(); + this.seenProperties.clear(); + return this; + } + + @Override + public MultiPart build() { + if (this.parts.isEmpty()) { + // Client will throw exception if there is no + // at least one StatePart with at least one Variant + // even if this part will never apply (e.g. with StateCondition#alwaysFalse). + // Maybe it's fine to just add always-false part if no parts are provided. + throw new IllegalStateException("At least one StatePart must be provided"); + } + + return new MultiPart(this.block, this.parts); + } + } } interface Builder> extends diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java index 1240332..32a03a6 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java @@ -1,9 +1,12 @@ package net.hellheim.spongetools.resourcepack.block; - +import java.util.HashSet; import java.util.Iterator; +import java.util.List; +import java.util.Set; import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.block.BlockType; import org.spongepowered.api.state.StateContainer; import org.spongepowered.api.state.StateProperty; @@ -13,11 +16,10 @@ import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import net.hellheim.spongetools.resourcepack.block.StateSelector.Builder; - interface StateCodec extends Codec { Codec> STATE_PROPERTY_VALUE = new StateCodec<>() { + @Override public DataResult encode( final StatePropertyValue input, final DynamicOps ops, final T prefix @@ -36,6 +38,7 @@ public DataResult, T>> read( }; Codec STATE_SELECTOR = new StateCodec<>() { + @Override public DataResult encode( final StateSelector input, final DynamicOps ops, final T prefix @@ -53,8 +56,158 @@ public DataResult> read( } }; + // TODO TEST THIS TEST THIS TEST THIS + Codec STATE_CONDITION = new StateCodec() { + + @Override + public DataResult encode( + final StateCondition input, final DynamicOps ops, final T prefix + ) { + return switch (input) { + case final StateCondition.OrCondition condition -> + StateCondition.LIST_CODEC.encode(condition.conditions(), ops, prefix) + .map(conditions -> ops.set(ops.emptyMap(), "OR", conditions)); + case final StateCondition.AndCondition condition -> { + + yield StateCondition.LIST_CODEC.encode(condition.conditions(), ops, prefix); + } + case final StateCondition.PropertyCondition condition -> { + yield ops.mergeToMap(prefix, + ops.createString(condition.property().name()), + ops.createString(condition.valuesString())); + } + default -> DataResult.error(() -> "Unknown StateCondition: " + input); + }; + } + + @Override + public DataResult> read( + final StateOps ops, final T input + ) { + return ops.getMap(input).flatMap(map -> { + final long amount = map.entries().count(); + if (amount == 0) { + return DataResult.error(() -> "No conditions found"); + } else if (amount == 1) { + final @Nullable T or = map.get("OR"); + if (or != null) { + return StateCondition.LIST_CODEC.decode(ops, or) + .map(pair -> Pair.of(StateCondition.or(pair.getFirst()), pair.getSecond())); + } + + final @Nullable T and = map.get("AND"); + if (and != null) { + return StateCondition.LIST_CODEC.decode(ops, and) + .map(pair -> Pair.of(StateCondition.and(pair.getFirst()), pair.getSecond())); + } + + return StateCodec.decodePropertyCondition(ops, map.entries().findAny().get()) + .map(condition -> Pair.of(condition, ops.empty())); + } else { + final List conditions = map.entries() + .map(entry -> StateCodec.decodePropertyCondition(ops, entry)) + .filter(DataResult::isSuccess) + .map(DataResult::getOrThrow) + .toList(); + + return conditions.isEmpty() + ? DataResult.error(() -> "No conditions found") + : DataResult.success(Pair.of(StateCondition.and(conditions), ops.empty())); + } + }); + } + }; + + Codec MULTI_VARIANT = new StateCodec<>() { + + @Override + public DataResult encode( + final BlockDefinition.MultiVariant input, final DynamicOps ops, final T prefix + ) { + return StateDispatch.CODEC.encode(input.dispatch(), ops, prefix) + .map(dispatch -> ops.set(ops.emptyMap(), StateCodec.KEY_VARIANT, dispatch)); + } + + @Override + public DataResult> read( + final StateOps ops, final T input + ) { + if (!(ops.getAsStateContainer() instanceof final BlockType block)) { + return DataResult.error(() -> "StateOps container not a BlockType"); + } + + return ops.get(input, StateCodec.KEY_VARIANT) + .flatMap(dispatch -> StateDispatch.CODEC.decode(ops, dispatch)) + .map(pair -> Pair.of(BlockDefinition.variant(block).dispatch(pair.getFirst()).build(), pair.getSecond())); + } + }; + + Codec MULTI_PART = new StateCodec<>() { + + @Override + public DataResult encode( + final BlockDefinition.MultiPart input, final DynamicOps ops, final T prefix + ) { + return StatePart.LIST_CODEC.encode(input.parts(), ops, prefix) + .map(parts -> ops.set(ops.emptyMap(), StateCodec.KEY_PART, parts)); + } + + @Override + public DataResult> read( + final StateOps ops, final T input + ) { + if (!(ops.getAsStateContainer() instanceof final BlockType block)) { + return DataResult.error(() -> "StateOps container not a BlockType"); + } + + return ops.get(input, StateCodec.KEY_PART) + .flatMap(parts -> StatePart.LIST_CODEC.decode(ops, parts)) + .map(pair -> Pair.of(BlockDefinition.part(block).add(pair.getFirst()).build(), pair.getSecond())); + } + }; + + Codec BLOCK_DEFINITION = new Codec<>() { + + @Override + public DataResult encode( + final BlockDefinition input, final DynamicOps ops, final T prefix + ) { + return switch (input) { + case BlockDefinition.MultiVariant definition -> + BlockDefinition.MultiVariant.CODEC.encode(definition, ops, prefix); + case BlockDefinition.MultiPart definition -> + BlockDefinition.MultiPart.CODEC.encode(definition, ops, prefix); + default -> DataResult.error(() -> "Unknown BlockDefinition: " + input); + }; + } + + @SuppressWarnings("unchecked") + @Override + public DataResult> decode( + final DynamicOps ops, final T input + ) { + final @Nullable T variant = ops.get(input, StateCodec.KEY_VARIANT).result().orElse(null); + if (variant != null) { + return (DataResult>) (Object) + BlockDefinition.MultiVariant.CODEC.decode(ops, variant); + } + + final @Nullable T part = ops.get(input, StateCodec.KEY_PART).result().orElse(null); + if (part != null) { + return (DataResult>) (Object) + BlockDefinition.MultiPart.CODEC.decode(ops, variant); + } + + return DataResult.error(() -> "Unknown BlockDefinition"); + } + }; + + String KEY_VARIANT = "variants"; + String KEY_PART = "multipart"; + Splitter COMMA_SPLITTER = Splitter.on(','); Splitter EQUAL_SPLITTER = Splitter.on('=').limit(2); + Splitter PIPE_SPLITTER = Splitter.on('|').omitEmptyStrings(); DataResult> read(StateOps ops, T input); @@ -66,7 +219,7 @@ default DataResult> decode(final DynamicOps ops, final T input } static DataResult decodeSelector(final StateContainer container, final String selector) { - final Builder builder = StateSelector.builder(); + final StateSelector.Builder builder = StateSelector.builder(); for (final String property : COMMA_SPLITTER.split(selector)) { final var value = StateCodec.decodePropertyValue(container, property); if (value.isError()) { @@ -80,43 +233,102 @@ static DataResult decodeSelector(final StateContainer containe } static DataResult> decodePropertyValue( - final StateContainer container, final String fullProperty - ) { - final Iterator propertyData = EQUAL_SPLITTER.split(fullProperty).iterator(); - - final String propertyString = propertyData.next(); - if (propertyString.isEmpty()) { - return DataResult.error(() -> "Empty state property"); - } - - final @Nullable StateProperty property = container.findStateProperty(propertyString).orElse(null); - if (property == null) { - return DataResult.error(() -> String.format( - "Unknown state property: '%s'", - propertyString - )); - } - - if (!propertyData.hasNext()) { - return DataResult.error(() -> String.format( - "State property without value: %s", - propertyString - )); - } - - final String valueString = propertyData.next(); - if (valueString.isEmpty()) { - return DataResult.error(() -> "Empty state property value"); - } - - final @Nullable Comparable value = property.parseValue(valueString).orElse(null); + final StateContainer container, final String fullProperty + ) { + final Iterator propertyData = EQUAL_SPLITTER.split(fullProperty).iterator(); + + final String propertyString = propertyData.next(); + if (propertyString.isEmpty()) { + return DataResult.error(() -> "Empty state property"); + } + + final @Nullable StateProperty property = container.findStateProperty(propertyString).orElse(null); + if (property == null) { + return DataResult.error(() -> String.format( + "Unknown state property: '%s'", + propertyString + )); + } + + if (!propertyData.hasNext()) { + return DataResult.error(() -> String.format( + "State property without value: '%s'", + propertyString + )); + } + + final String valueString = propertyData.next(); + if (valueString.isEmpty()) { + return DataResult.error(() -> "Empty state property value"); + } + + final @Nullable Comparable value = property.parseValue(valueString).orElse(null); + if (value == null) { + return DataResult.error(() -> String.format( + "Unknown value: '%s' for state property: '%s' %s", + valueString, propertyString, property.possibleValues() + )); + } + + return DataResult.success(StatePropertyValue.ofRaw(property, value)); + } + + static DataResult decodePropertyCondition( + final StateOps ops, final Pair entry + ) { + final DataResult key = ops.getStringValue(entry.getFirst()); + if (key.isError()) { + return DataResult.error(key.error().get().messageSupplier()); + } + + final String propertyName = key.getOrThrow(); + final @Nullable StateProperty property = ops.findStateProperty(propertyName).orElse(null); + if (property == null) { + return DataResult.error(() -> String.format( + "Unknown state property '%' on container '%'", + propertyName, ops.getAsStateContainer() + )); + } + + final DataResult value = ops.getStringValue(entry.getSecond()); + if (value.isError()) { + return DataResult.error(value.error().get().messageSupplier()); + } + + String values = value.getOrThrow(); + final boolean negate = !values.isEmpty() && values.charAt(0) == '!'; + if (negate) { + values = values.substring(1); + } + + if (values.isEmpty()) { + return DataResult.error(() -> String.format( + "Empty property values for property '%s' on container '%'", + propertyName, ops.getAsStateContainer() + )); + } + + return StateCodec.decodePropertyConditionValues(ops, property, negate, values); + } + + static > DataResult decodePropertyConditionValues( + final StateOps ops, + final StateProperty property, final boolean negate, final String valueNames + ) { + final Set values = new HashSet<>(); + for (final String valueName : StateCodec.PIPE_SPLITTER.split(valueNames)) { + final @Nullable T value = property.parseValue(valueName).orElse(null); if (value == null) { return DataResult.error(() -> String.format( - "Unknown value: '%s' for state property: '%s' %s", - valueString, propertyString, property.possibleValues() - )); + "Unknown value '%' for property '%' in '%' on container '%'", + valueName, property.name(), valueNames, ops.getAsStateContainer() + ), + StateCondition.property(property, negate, values)); } - return DataResult.success(StatePropertyValue.ofRaw(property, value)); + values.add(value); } + + return DataResult.success(StateCondition.property(property, negate, values)); + } } diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java index 4c03196..cb3c26b 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java @@ -1,48 +1,515 @@ package net.hellheim.spongetools.resourcepack.block; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import com.mojang.serialization.Codec; -import com.mojang.serialization.Encoder; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.state.State; +import org.spongepowered.api.state.StateProperty; -import net.hellheim.spongetools.proxy.solid.codec.EncoderProxy; +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Sets; +import com.google.common.collect.Streams; +import com.mojang.serialization.Codec; -public interface StateCondition extends EncoderProxy { +public interface StateCondition extends StatePredicate { + + Codec CODEC = StateCodec.STATE_CONDITION; + + Codec> LIST_CODEC = StateCondition.CODEC.listOf(); + + static StateCondition alwaysTrue() { + return CompositeCondition.ALWAYS_TRUE; + } + + static StateCondition alwaysFalse() { + return CompositeCondition.ALWAYS_FALSE; + } + + static StateCondition always(final boolean value) { + return value ? StateCondition.alwaysTrue() : StateCondition.alwaysFalse(); + } + + static AndCondition.Builder and() { + return new AndCondition.Builder(); + } + + static StateCondition and(final Consumer configurator) { + final AndCondition.Builder builder = StateCondition.and(); + Objects.requireNonNull(configurator, "configurator").accept(builder); + return builder.build(); + } + + static StateCondition and(final StateCondition... conditions) { + return StateCondition.and().add(conditions).build(); + } + + static StateCondition and(final Iterable conditions) { + return StateCondition.and().add(conditions).build(); + } + + static StateCondition and(final Stream conditions) { + return StateCondition.and().add(conditions).build(); + } + + static OrCondition.Builder or() { + return new OrCondition.Builder(); + } + + static StateCondition or(final Consumer configurator) { + final OrCondition.Builder builder = StateCondition.or(); + Objects.requireNonNull(configurator, "configurator").accept(builder); + return builder.build(); + } + + static StateCondition or(final StateCondition... conditions) { + return StateCondition.or().add(conditions).build(); + } + + static StateCondition or(final Iterable conditions) { + return StateCondition.or().add(conditions).build(); + } + + static StateCondition or(final Stream conditions) { + return StateCondition.or().add(conditions).build(); + } + + static > StateCondition property( + final StateProperty property, final boolean inverse, final Collection values + ) { + return PropertyCondition.of(property, inverse, Set.copyOf(values)); + } + + @SafeVarargs + static > StateCondition property( + final StateProperty property, final boolean inverse, final T... values + ) { + return StateCondition.property(property, inverse, Set.of(values)); + } + + @SafeVarargs + static > StateCondition is( + final StateProperty property, final T... values + ) { + return StateCondition.property(property, false, values); + } + + static > StateCondition is( + final StateProperty property, final Collection values + ) { + return StateCondition.property(property, false, values); + } + + static > StateCondition is( + final StatePropertyValue value + ) { + return StateCondition.is(value.property(), value.value()); + } + + static StateCondition is(final State state) { + return StateCondition.and(StatePropertyValue.allOf(state).map(StateCondition::is)); + } + + @SafeVarargs + static > StateCondition not( + final StateProperty property, final T... values + ) { + return StateCondition.property(property, true, values); + } + + static > StateCondition not( + final StateProperty property, final Collection values + ) { + return StateCondition.property(property, true, values); + } + + static > StateCondition not( + final StatePropertyValue value + ) { + return StateCondition.not(value.property(), value.value()); + } + + static StateCondition not(final State state) { + return StateCondition.or(StatePropertyValue.allOf(state).map(StateCondition::not)); + } + + Set> properties(); - record AndCondition(List conditions) implements StateCondition { + StateCondition negate(); + + abstract class CompositeCondition implements StateCondition { + + private static final AndCondition ALWAYS_TRUE = new AndCondition(List.of(), Set.of()); + private static final OrCondition ALWAYS_FALSE = new OrCondition(List.of(), Set.of()); - public static final Encoder ENCODER = Codec + private final List conditions; + private final Set> properties; - public AndCondition(final List conditions) { + private CompositeCondition( + final List conditions, final Set> properties + ) { this.conditions = List.copyOf(conditions); + this.properties = Set.copyOf(properties); + } + + protected abstract StateCondition negate0(); + + public List conditions() { + return this.conditions; } @Override - public Encoder codec() { - // TODO Auto-generated method stub - return null; + public Set> properties() { + return this.properties; + } + + @Override + public StateCondition negate() { + if (this == StateCondition.alwaysFalse()) { + return StateCondition.alwaysTrue(); + } else if (this == StateCondition.alwaysTrue()) { + return StateCondition.alwaysFalse(); + } else { + return this.negate0(); + } + } + + public static abstract class Builder> + implements org.spongepowered.api.util.Builder { + + private final boolean bias; + protected final List conditions = new ArrayList<>(); + protected boolean always; + + private Builder(final boolean bias) { + this.bias = bias; + this.reset(); + } + + @SuppressWarnings("unchecked") + private B cast() { + return (B) this; + } + + protected abstract void tryAdd(StateCondition condition); + + protected abstract > StateCondition merge( + PropertyCondition first, PropertyCondition second + ); + + protected abstract CompositeCondition build0(Set> properties); + + public B add(final StateCondition... conditions) { + return this.add(Arrays.stream(conditions)); + } + + public B add(final Iterable conditions) { + return this.add(Streams.stream(conditions)); + } + + public B add(final Stream conditions) { + Objects.requireNonNull(conditions, "conditions").forEach(condition -> { + this.addSingle(Objects.requireNonNull(condition, "condition")); + }); + + return this.cast(); + } + + private void addSingle(final StateCondition condition) { + if (this.always) { + return; + } else if (condition instanceof final PropertyCondition property) { + this.merge(property); + } else { + this.tryAdd(condition); + } + } + + private > void merge(final PropertyCondition condition) { + @SuppressWarnings("unchecked") + final @Nullable PropertyCondition current = this.conditions.stream() + .filter(PropertyCondition.class::isInstance) + .map(PropertyCondition.class::cast) + .filter(c -> c.property().equals(condition.property())) + .map(c -> (PropertyCondition) c) + .findAny() + .orElse(null); + + if (current == null) { + this.tryAdd(condition); + } else { + this.conditions.remove(current); + this.tryAdd(this.merge(current, condition)); + } + } + + @Override + public B reset() { + this.conditions.clear(); + this.always = false; + return this.cast(); + } + + @Override + public StateCondition build() { + if (this.conditions.isEmpty()) { + return StateCondition.always(this.bias); + } else if (this.conditions.size() == 1) { + return this.conditions.get(0); + } + + final Set> properties = this.conditions.stream() + .flatMap(condition -> condition.properties().stream()) + .collect(Collectors.toSet()); + final CompositeCondition condition = this.build0(properties); + + final Iterator selectors = StateSelector.populate(properties).iterator(); + int positive = 0, negative = 0; + while (selectors.hasNext()) { + final StateSelector selector = selectors.next(); + if (condition.test(selector)) { + ++positive; + } else { + ++negative; + } + } + + if (positive == 0) { + return StateCondition.alwaysFalse(); + } else if (negative == 0) { + return StateCondition.alwaysTrue(); + } else { + return condition; + } + } } } - record OrCondition(List conditions) implements StateCondition { + final class AndCondition extends CompositeCondition { - public OrCondition(final List conditions) { - this.conditions = List.copyOf(conditions); + private AndCondition( + final List conditions, final Set> properties + ) { + super(conditions, properties); } @Override - public Encoder codec() { - // TODO Auto-generated method stub - return null; + public boolean test( + final Function, Optional>> propertyLookup + ) { + for (final StateCondition condition : this.conditions()) { + if (!condition.test(propertyLookup)) { + return false; + } + } + + return true; + } + + @Override + protected StateCondition negate0() { + return new OrCondition( + this.conditions().stream().map(StateCondition::negate).toList(), + this.properties()); + } + + public static final class Builder extends CompositeCondition.Builder { + + private Builder() { + super(true); + } + + @Override + protected void tryAdd(final StateCondition condition) { + if (condition instanceof final AndCondition and) { + this.add(and.conditions()); + } else if (condition == StateCondition.alwaysFalse()) { + this.conditions.clear(); + this.always = true; + } else if (condition != StateCondition.alwaysTrue()) { + this.conditions.add(condition); + } + } + + @Override + protected > @Nullable StateCondition merge( + final PropertyCondition first, final PropertyCondition second + ) { + final StateProperty property = first.property(); + final boolean inverse = first.inverse() && second.inverse(); + final Set values = first.inverse() == second.inverse() + ? first.inverse() + ? Sets.union(first.values(), second.values()) + : Sets.intersection(first.values(), second.values()) + : first.inverse() + ? Sets.difference(second.values(), first.values()) + : Sets.difference(first.values(), second.values()); + + return StateCondition.property(property, inverse, values); + }; + + @Override + protected CompositeCondition build0(final Set> properties) { + return new AndCondition(this.conditions, properties); + } } } - record PropertyCondition() implements StateCondition { + final class OrCondition extends CompositeCondition { + + private OrCondition( + final List conditions, final Set> properties + ) { + super(conditions, properties); + } + + @Override + public boolean test( + final Function, Optional>> propertyLookup + ) { + for (final StateCondition condition : this.conditions()) { + if (condition.test(propertyLookup)) { + return true; + } + } + + return false; + } @Override - public Encoder codec() { - // TODO Auto-generated method stub - return null; + protected StateCondition negate0() { + return new AndCondition( + this.conditions().stream().map(StateCondition::negate).toList(), + this.properties()); + } + + public static final class Builder extends CompositeCondition.Builder { + + private Builder() { + super(false); + } + + @Override + protected void tryAdd(final StateCondition condition) { + if (condition instanceof final OrCondition or) { + this.add(or.conditions()); + } else if (condition == StateCondition.alwaysTrue()) { + this.conditions.clear(); + this.always = true; + } else if (condition != StateCondition.alwaysFalse()) { + this.conditions.add(condition); + } + } + + @Override + protected > StateCondition merge( + final PropertyCondition first, final PropertyCondition second + ) { + final StateProperty property = first.property(); + final boolean inverse = !first.inverse() && !second.inverse(); + final Set values = first.inverse() == second.inverse() + ? first.inverse() + ? Sets.intersection(first.values(), second.values()) + : Sets.union(first.values(), second.values()) + : first.inverse() + ? Sets.difference(first.values(), second.values()) + : Sets.difference(second.values(), first.values()); + + return StateCondition.property(property, inverse, values); + }; + + @Override + protected CompositeCondition build0(final Set> properties) { + return new OrCondition(this.conditions, properties); + } + } + } + + final class PropertyCondition> implements StateCondition { + + private final StateProperty property; + private final boolean inverse; + private final Set values; + + private PropertyCondition( + final StateProperty property, final boolean inverse, final Set values + ) { + this.property = property; + this.inverse = inverse; + this.values = ImmutableSortedSet.copyOf(values); + } + + private static > StateCondition of( + final StateProperty property, final boolean inverse, final Set values + ) { + Objects.requireNonNull(property, "property"); + Objects.requireNonNull(values, "values"); + if (values.isEmpty()) { + return StateCondition.always(inverse); + } + + final Set possibleValues = Set.copyOf(property.possibleValues()); + final Set illegalValues = Sets.difference(values, possibleValues); + if (!illegalValues.isEmpty()) { + throw new IllegalArgumentException(String.format( + "Property '%s' does not support values '%'", + property.name(), illegalValues + )); + } + + if (values.size() == possibleValues.size()) { + return StateCondition.always(!inverse); + } + + return new PropertyCondition<>(property, inverse, values); + } + + public StateProperty property() { + return this.property; + } + + public boolean inverse() { + return this.inverse; + } + + public Set values() { + return this.values; + } + + @Override + public boolean test( + final Function, Optional>> propertyLookup + ) { + return propertyLookup.apply(this.property) + .map(value -> this.inverse ^ this.values.contains(value)) + .orElse(false); + } + + @Override + public Set> properties() { + return Set.of(this.property); + } + + @Override + public StateCondition.PropertyCondition negate() { + return new PropertyCondition<>(this.property, !this.inverse, this.values); + } + + public String valuesString() { + final String values = this.values.stream() + .map(value -> StatePropertyValue.of(this.property, value).valueName()) + .collect(Collectors.joining("|")); + return this.inverse ? "!" + values : values; } } } diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java index c982539..3daf445 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java @@ -25,7 +25,7 @@ public class StateDispatch { public static final Codec CODEC = Codec - .unboundedMap(StateSelector.CODEC, Variant.CODEC.listOf()) + .unboundedMap(StateSelector.CODEC, Variant.LIST_CODEC) .xmap(StateDispatch::new, StateDispatch::values); private final Set> properties; @@ -669,10 +669,7 @@ public StateDispatch build() { private void validateInput(final StateSelector selector, final Collection variants) { Objects.requireNonNull(selector, "selector"); - Objects.requireNonNull(variants, "variants"); - if (variants.isEmpty()) { - throw new IllegalArgumentException("At least one variant must be provided"); - } + Variant.validate(variants); } private RuntimeException overlap(final StateSelector given, final StateSelector current) { diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java index c832dab..9241ccb 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java @@ -1,6 +1,7 @@ package net.hellheim.spongetools.resourcepack.block; import java.util.Objects; +import java.util.function.Supplier; import org.spongepowered.api.state.State; import org.spongepowered.api.state.StateContainer; @@ -26,6 +27,12 @@ public static > StateOps of( return new StateOps<>(ops, container); } + public static > StateOps of( + final DynamicOps ops, final Supplier> containerSupplier + ) { + return new StateOps<>(ops, Objects.requireNonNull(containerSupplier, "containerSupplier").get()); + } + @Override public DynamicOps getAsOps() { return this.ops; diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePart.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePart.java new file mode 100644 index 0000000..5ea9332 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePart.java @@ -0,0 +1,56 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +import org.spongepowered.api.state.StateProperty; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +public record StatePart(Optional condition, List variants) { + + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + StateCondition.CODEC.optionalFieldOf("when").forGetter(StatePart::condition), + Variant.LIST_CODEC.fieldOf("apply").forGetter(StatePart::variants) + ).apply(instance, StatePart::new)); + + public static final Codec> LIST_CODEC = StatePart.CODEC.listOf(); + + public StatePart(final Optional condition, final List variants) { + this.condition = Objects.requireNonNull(condition, "condition") + .filter(c -> c != StateCondition.alwaysTrue()); + this.variants = List.copyOf(Variant.validate(variants)); + } + + public static StatePart of(final Optional condition, final List variants) { + return new StatePart(condition, variants); + } + + public static StatePart of(final Optional condition, final Variant... variants) { + return StatePart.of(condition, List.of(variants)); + } + + public static StatePart of(final StateCondition condition, final List variants) { + return StatePart.of(Optional.of(condition), variants); + } + + public static StatePart of(final StateCondition condition, final Variant... variants) { + return StatePart.of(Optional.of(condition), variants); + } + + public static StatePart of(final List variants) { + return StatePart.of(Optional.empty(), variants); + } + + public static StatePart of(final Variant... variants) { + return StatePart.of(Optional.empty(), variants); + } + + public Set> properties() { + return this.condition.map(StateCondition::properties).orElse(Set.of()); + } +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePredicate.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePredicate.java new file mode 100644 index 0000000..f02f68d --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePredicate.java @@ -0,0 +1,22 @@ +package net.hellheim.spongetools.resourcepack.block; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +import org.spongepowered.api.state.State; +import org.spongepowered.api.state.StateProperty; + +@FunctionalInterface +public interface StatePredicate { + + default boolean test(final State state) { + return this.test(Objects.requireNonNull(state, "state")::stateProperty); + } + + default boolean test(final StateSelector selector) { + return this.test(Objects.requireNonNull(selector, "selector")::get); + } + + boolean test(Function, Optional>> propertyLookup); +} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java index 12c3117..ff0ce57 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java @@ -2,9 +2,11 @@ import java.util.Objects; import java.util.function.Supplier; +import java.util.stream.Stream; import org.spongepowered.api.Sponge; import org.spongepowered.api.data.type.StringRepresentable; +import org.spongepowered.api.state.State; import org.spongepowered.api.state.StateProperty; import com.mojang.serialization.Codec; @@ -32,10 +34,17 @@ static > StatePropertyValue ofRaw( return StatePropertyValue.of(property, (T) value); } + static Stream> allOf(final State state) { + return state.statePropertyMap().entrySet().stream() + .map(e -> StatePropertyValue.ofRaw(e.getKey(), e.getValue())); + } + StateProperty property(); T value(); + String valueName(); + interface Factory { > StatePropertyValue of(StateProperty property, T value); diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java index a0b84e3..9931329 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; @@ -22,7 +23,7 @@ import com.google.common.collect.Sets; import com.mojang.serialization.Codec; -public final class StateSelector implements StringRepresentable { +public final class StateSelector implements StringRepresentable, StatePredicate { public static final Codec CODEC = StateCodec.STATE_SELECTOR; @@ -75,6 +76,12 @@ public Collection> values() { return this.values.values(); } + public > Optional get(final StateProperty property) { + @SuppressWarnings("unchecked") + final @Nullable StatePropertyValue value = (StatePropertyValue) this.values.get(property); + return value == null ? Optional.empty() : Optional.of(value.value()); + } + public boolean overlaps(final StateSelector selector) { final var commonProperties = Sets.intersection(this.properties(), selector.properties()); for (final StateProperty property : commonProperties) { @@ -88,27 +95,25 @@ public boolean overlaps(final StateSelector selector) { return true; } - public boolean test(final StateSelector selector) { - Objects.requireNonNull(selector, "selector"); - return this.test(property -> { - final @Nullable StatePropertyValue value = selector.values.get(property); - return value == null ? null : value.value(); - }); - } - - public boolean test(final State state) { - Objects.requireNonNull(state, "state"); - return this.test(property -> state.stateProperty(property).orElse(null)); + @Override + public boolean test(final Function, Optional>> propertyLookup) { + for (final StatePropertyValue value : this.values()) { + if (propertyLookup.apply(value.property()).map(value.value()::equals).orElse(false)) { + return false; + } + } + + return true; } - private boolean test(final Function, @Nullable Comparable> valueLookup) { + /*private boolean test(final Function, @Nullable Comparable> propertyLookup) { for (final StatePropertyValue value : this.values()) { - if (!Objects.equals(value.value(), valueLookup.apply(value.property()))) { + if (!Objects.equals(value.value(), propertyLookup.apply(value.property()))) { return false; } } return true; - } + }*/ public Builder toBuilder() { return StateSelector.builder().from(this); diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java index 1d81b7c..1453e30 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java @@ -12,6 +12,7 @@ import org.spongepowered.api.util.CopyableBuilder; import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; public final class Variant { @@ -20,6 +21,9 @@ public final class Variant { variant -> List.copyOf(variant.values()) ); + public static final Codec> LIST_CODEC = Variant.CODEC.listOf() + .validate(Variant::validateCodec); + private static final Variant EMPTY = new Variant(Map.of()); private final Map, VariantPropertyValue> values; @@ -40,6 +44,17 @@ public static Variant model(final ResourceKey model) { return Variant.builder().add(VariantProperties.MODEL, model).build(); } + protected static > C validate(final C variants) { + return Variant.validateCodec(Objects.requireNonNull(variants, "variants")) + .getOrThrow(IllegalArgumentException::new); + } + + private static > DataResult validateCodec(final C variants) { + return variants.isEmpty() + ? DataResult.error(() -> "At least one variant must be provided") + : DataResult.success(variants); + } + public Set> properties() { return this.values.keySet(); } diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java index a94da55..1aff037 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java @@ -3,22 +3,24 @@ import java.util.Optional; import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.util.rotation.Rotation; import com.mojang.serialization.Codec; import net.hellheim.spongetools.codec.list.SpongeCodecs; +import net.hellheim.spongetools.util.GeomUtil; public final class VariantProperties { public static final VariantProperty MODEL = property("model", SpongeCodecs.RESOURCE_KEY, Optional.empty()); - public static final VariantProperty X_ROT = property("x", VariantRotation.CODEC, Optional.of(VariantRotation.R0)); + public static final VariantProperty X_ROT = property("x", SpongeCodecs.ROTATION_BY_ANGLE, Optional.of(GeomUtil.ROT_0)); - public static final VariantProperty Y_ROT = property("y", VariantRotation.CODEC, Optional.of(VariantRotation.R0)); + public static final VariantProperty Y_ROT = property("y", SpongeCodecs.ROTATION_BY_ANGLE, Optional.of(GeomUtil.ROT_0)); public static final VariantProperty UV_LOCK = property("uvlock", Codec.BOOL, Optional.of(false)); - public static final VariantProperty WEIGHT = property("weight", Codec.INT, Optional.of(0)); + public static final VariantProperty WEIGHT = property("weight", Codec.INT, Optional.of(1)); private static VariantProperty property( final String name, final Codec valueCodec, final Optional defaultValue diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantRotation.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantRotation.java deleted file mode 100644 index e605695..0000000 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantRotation.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.hellheim.spongetools.resourcepack.block; - -import org.spongepowered.api.data.type.StringRepresentable; - -import com.mojang.serialization.Codec; - -import net.hellheim.spongetools.codec.StringRepresentableCodec; - -public enum VariantRotation implements StringRepresentable { - - R0(0), - R90(90), - R180(180), - R270(270); - - public static final Codec CODEC = StringRepresentableCodec.fromValues(VariantRotation::values); - - private final int value; - - private VariantRotation(final int value) { - this.value = value; - } - - public int value() { - return this.value; - } - - @Override - public String serializationString() { - return Integer.toString(this.value); - } -} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/Item.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/Item.java deleted file mode 100644 index 50f73ec..0000000 --- a/src/main/java/net/hellheim/spongetools/resourcepack/item/Item.java +++ /dev/null @@ -1,43 +0,0 @@ -package net.hellheim.spongetools.resourcepack.item; - -import java.util.Objects; - -import org.spongepowered.api.registry.DefaultedRegistryType; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; - -import net.hellheim.spongetools.SpongeTools; -import net.hellheim.spongetools.codec.list.RegistryCodecs; - -public record Item(ItemDefinition definition, boolean handAnimationOnSwap) { - - public static final boolean DEFAULT_HAND_ANIMATION_ON_SWAP = true; - - public static final Codec CODEC = RecordCodecBuilder.create( - instance -> instance.group( - ItemDefinition.CODEC.fieldOf("model").forGetter(Item::definition), - Codec.BOOL.optionalFieldOf("hand_animation_on_swap", Item.DEFAULT_HAND_ANIMATION_ON_SWAP).forGetter(Item::handAnimationOnSwap) - ).apply(instance, Item::new)); - - public Item(final ItemDefinition definition, final boolean handAnimationOnSwap) { - this.definition = Objects.requireNonNull(definition, "definition"); - this.handAnimationOnSwap = handAnimationOnSwap; - } - - public static DefaultedRegistryType registry() { - return SpongeTools.Registries.ITEM; - } - - public static Codec registryCodec() { - return RegistryCodecs.ITEM; - } - - public static Item of(final ItemDefinition definition, final boolean handAnimationOnSwap) { - return new Item(definition, handAnimationOnSwap); - } - - public static Item of(final ItemDefinition definition) { - return Item.of(definition, Item.DEFAULT_HAND_ANIMATION_ON_SWAP); - } -} diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java index d2c90f4..ccc23a2 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java @@ -1,260 +1,46 @@ package net.hellheim.spongetools.resourcepack.item; -import java.util.Collection; -import java.util.List; import java.util.Objects; -import java.util.Optional; -import java.util.function.Function; -import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.registry.DefaultedRegistryType; import com.mojang.serialization.Codec; -import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.hellheim.spongetools.codec.LateBoundIdMapper; -import net.hellheim.spongetools.codec.list.SpongeCodecs; -import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; +import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.RegistryCodecs; -public interface ItemDefinition extends MapCodecProxy { +/** + * @see Minecraft Wiki + */ +public record ItemDefinition(ItemModel model, boolean handAnimationOnSwap) { - LateBoundIdMapper> ID_MAPPER = new LateBoundIdMapper<>(); + public static final boolean DEFAULT_HAND_ANIMATION_ON_SWAP = true; - Codec CODEC = ItemDefinition.ID_MAPPER.codec(SpongeCodecs.RESOURCE_KEY) - .dispatch(ItemDefinition::mapCodec, Function.identity()); + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + ItemModel.CODEC.fieldOf("model").forGetter(ItemDefinition::model), + Codec.BOOL.optionalFieldOf("hand_animation_on_swap", ItemDefinition.DEFAULT_HAND_ANIMATION_ON_SWAP).forGetter(ItemDefinition::handAnimationOnSwap) + ).apply(instance, ItemDefinition::new)); - static Empty empty() { - return Empty.INSTANCE; + public ItemDefinition(final ItemModel model, final boolean handAnimationOnSwap) { + this.model = Objects.requireNonNull(model, "model"); + this.handAnimationOnSwap = handAnimationOnSwap; } - static BundleSelectedItem bundleSelectedItem() { - return BundleSelectedItem.INSTANCE; + public static DefaultedRegistryType registry() { + return SpongeTools.Registries.ITEM_DEFINITION; } - static Simple simple(final ResourceKey model, final TintSource... tints) { - return new Simple(model, List.of(tints)); + public static Codec registryCodec() { + return RegistryCodecs.ITEM_DEFINITION; } - static Simple simple(final ResourceKey model, final Collection tints) { - return new Simple(model, List.copyOf(tints)); + public static ItemDefinition of(final ItemModel model, final boolean handAnimationOnSwap) { + return new ItemDefinition(model, handAnimationOnSwap); } - static Composite composite(final ItemDefinition... models) { - return new Composite(List.of(models)); - } - - static Composite composote(final Collection models) { - return new Composite(List.copyOf(models)); - } - - static Conditional conditional(final ConditionalProperty property, final ItemDefinition onTrue, final ItemDefinition onFalse) { - return new Conditional(property, onTrue, onFalse); - } - - @SafeVarargs - static Select select(final SelectProperty property, final SelectSwitchCase... cases) { - return ItemDefinition.select(property, Optional.empty(), cases); - } - - @SafeVarargs - static Select select(final SelectProperty property, final ItemDefinition fallback, final SelectSwitchCase... cases) { - return ItemDefinition.select(property, Optional.of(fallback), cases); - } - - @SafeVarargs - static Select select(final SelectProperty property, final Optional fallback, final SelectSwitchCase... cases) { - return ItemDefinition.select(SelectSwitch.of(property, List.of(cases)), fallback); - } - - static Select select(final SelectProperty property, final Collection> cases) { - return ItemDefinition.select(property, Optional.empty(), cases); - } - - static Select select(final SelectProperty property, final ItemDefinition fallback, final Collection> cases) { - return ItemDefinition.select(property, Optional.of(fallback), cases); - } - - static Select select(final SelectProperty property, final Optional fallback, final Collection> cases) { - return ItemDefinition.select(SelectSwitch.of(property, List.copyOf(cases)), fallback); - } - - static Select select(final SelectSwitch body) { - return ItemDefinition.select(body, Optional.empty()); - } - - static Select select(final SelectSwitch body, final ItemDefinition fallback) { - return ItemDefinition.select(body, Optional.of(fallback)); - } - - static Select select(final SelectSwitch body, final Optional fallback) { - return new Select(body, fallback); - } - - static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final RangeSelectEntry... entries) { - return ItemDefinition.rangeSelect(property, scale, Optional.empty(), entries); - } - - static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final ItemDefinition fallback, final RangeSelectEntry... entries) { - return ItemDefinition.rangeSelect(property, scale, Optional.of(fallback), entries); - } - - static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final Optional fallback, final RangeSelectEntry... entries) { - return new RangeSelect(property, scale, fallback, List.of(entries)); - } - - static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final Collection entries) { - return ItemDefinition.rangeSelect(property, scale, Optional.empty(), entries); - } - - static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final ItemDefinition fallback, final Collection entries) { - return ItemDefinition.rangeSelect(property, scale, Optional.of(fallback), entries); - } - - static RangeSelect rangeSelect(final RangeSelectProperty property, final float scale, final Optional fallback, final Collection entries) { - return new RangeSelect(property, scale, fallback, List.copyOf(entries)); - } - - static Special special(final ResourceKey base, final SpecialModel model) { - return new Special(base, model); - } - - default Item asItem(final boolean handAnimationOnSwap) { - return Item.of(this, handAnimationOnSwap); - } - - default Item asItem() { - return Item.of(this); - } - - record Empty() implements ItemDefinition { - public static final Empty INSTANCE = new Empty(); - public static final MapCodec CODEC = MapCodec.unit(INSTANCE); - - @Override - public MapCodec mapCodec() { - return CODEC; - } - } - - record BundleSelectedItem() implements ItemDefinition { - public static final BundleSelectedItem INSTANCE = new BundleSelectedItem(); - public static final MapCodec CODEC = MapCodec.unit(INSTANCE); - - @Override - public MapCodec mapCodec() { - return CODEC; - } - } - - record Simple(ResourceKey model, List tints) implements ItemDefinition { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( - instance -> instance.group( - SpongeCodecs.RESOURCE_KEY.fieldOf("model").forGetter(Simple::model), - TintSource.CODEC.listOf().optionalFieldOf("tints", List.of()).forGetter(Simple::tints) - ).apply(instance, Simple::new)); - - public Simple(final ResourceKey model, final List tints) { - this.model = Objects.requireNonNull(model, "model"); - this.tints = Objects.requireNonNull(tints, "tints"); - } - - @Override - public MapCodec mapCodec() { - return CODEC; - } - } - - record Composite(List models) implements ItemDefinition { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( - instance -> instance.group( - ItemDefinition.CODEC.listOf().fieldOf("models").forGetter(Composite::models) - ).apply(instance, Composite::new)); - - public Composite(final List models) { - this.models = Objects.requireNonNull(models, "models"); - } - - @Override - public MapCodec mapCodec() { - return CODEC; - } - } - - record Conditional(ConditionalProperty property, ItemDefinition onTrue, ItemDefinition onFalse) implements ItemDefinition { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( - instance -> instance.group( - ConditionalProperty.CODEC.forGetter(Conditional::property), - ItemDefinition.CODEC.fieldOf("on_true").forGetter(Conditional::onTrue), - ItemDefinition.CODEC.fieldOf("on_false").forGetter(Conditional::onFalse)) - .apply(instance, Conditional::new)); - - public Conditional(final ConditionalProperty property, final ItemDefinition onTrue, final ItemDefinition onFalse) { - this.property = Objects.requireNonNull(property, "property"); - this.onTrue = Objects.requireNonNull(onTrue, "onTrue"); - this.onFalse = Objects.requireNonNull(onFalse, "onFalse"); - } - - @Override - public MapCodec mapCodec() { - return CODEC; - } - } - - record Select(SelectSwitch body, Optional fallback) implements ItemDefinition { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + SelectSwitch.CODEC.forGetter(Select::body), + ItemModel.CODEC.optionalFieldOf("fallback").forGetter(Select::fallback) + ).apply(instance, Select::new)); - public Builder display(final ItemTransforms.Builder builder) { - return this.display(Objects.requireNonNull(builder, "builder").build()); + public Select(final SelectSwitch body, final Optional fallback) { + this.body = Objects.requireNonNull(body, "body"); + this.fallback = Objects.requireNonNull(fallback, "fallback"); } - public Builder display(final Consumer configurator) { - final ItemTransforms.Builder builder = ItemTransforms.builder(); - Objects.requireNonNull(configurator, "configurator").accept(builder); - return this.display(builder); + @Override + public MapCodec mapCodec() { + return CODEC; } + } + + record RangeSelect(RangeSelectProperty property, float scale, Optional fallback, List entries) implements ItemModel { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + RangeSelectProperty.CODEC.forGetter(RangeSelect::property), + Codec.FLOAT.optionalFieldOf("scale", Float.valueOf(1.0F)).forGetter(RangeSelect::scale), + ItemModel.CODEC.optionalFieldOf("fallback").forGetter(RangeSelect::fallback), + RangeSelectEntry.CODEC.listOf().fieldOf("entries").forGetter(RangeSelect::entries) + ).apply(instance, RangeSelect::new)); - public Builder light(final GuiLight guiLight) { - this.guiLight = Objects.requireNonNull(guiLight, "guiLight"); - return this; + public RangeSelect(final RangeSelectProperty property, final float scale, final Optional fallback, final List entries) { + this.property = Objects.requireNonNull(property, "property"); + this.scale = scale; + this.fallback = Objects.requireNonNull(fallback, "fallback"); + this.entries = Objects.requireNonNull(entries, "entries"); } @Override - public Builder from(final ItemModel value) { - this.parent = value.parent(); - this.textures = value.textures(); - this.display = value.display(); - this.guiLight = value.guiLight; - return this; + public MapCodec mapCodec() { + return CODEC; } + } + + record Special(ResourceKey base, SpecialModel model) implements ItemModel { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + SpongeCodecs.RESOURCE_KEY.fieldOf("base").forGetter(Special::base), + SpecialModel.CODEC.fieldOf("model").forGetter(Special::model) + ).apply(instance, Special::new)); - @Override - public Builder reset() { - this.parent = null; - this.textures = null; - this.display = null; - this.guiLight = null; - return this; + public Special(final ResourceKey base, final SpecialModel model) { + this.base = Objects.requireNonNull(base, "base"); + this.model = Objects.requireNonNull(model, "model"); } @Override - public ItemModel build() { - return new ItemModel(TexturedModel.of(this.parent, this.textures), this.display, this.guiLight); + public MapCodec mapCodec() { + return CODEC; } } } diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java index 36ddfa9..c9aa476 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java @@ -5,14 +5,14 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; -public record RangeSelectEntry(float threshold, ItemDefinition model) { +public record RangeSelectEntry(float threshold, ItemModel model) { public static final Codec CODEC = RecordCodecBuilder.create( instance -> instance.group( Codec.FLOAT.fieldOf("threshold").forGetter(RangeSelectEntry::threshold), - ItemDefinition.CODEC.fieldOf("model").forGetter(RangeSelectEntry::model) + ItemModel.CODEC.fieldOf("model").forGetter(RangeSelectEntry::model) ).apply(instance, RangeSelectEntry::new)); - public RangeSelectEntry(final float threshold, final ItemDefinition model) { + public RangeSelectEntry(final float threshold, final ItemModel model) { this.threshold = threshold; this.model = Objects.requireNonNull(model, "model"); } diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java index a14c6cb..8df84e1 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java @@ -8,15 +8,15 @@ import net.hellheim.spongetools.codec.list.ExtraCodecs; -public record SelectSwitchCase(List values, ItemDefinition model) { +public record SelectSwitchCase(List values, ItemModel model) { public static Codec> codec(Codec codec) { return RecordCodecBuilder.create(instance -> instance.group( ExtraCodecs.nonEmptyCollection(ExtraCodecs.compactList(codec)).fieldOf("when").forGetter(SelectSwitchCase::values), - ItemDefinition.CODEC.fieldOf("model").forGetter(SelectSwitchCase::model) + ItemModel.CODEC.fieldOf("model").forGetter(SelectSwitchCase::model) ).apply(instance, SelectSwitchCase::new)); } - public SelectSwitchCase(final List values, final ItemDefinition model) { + public SelectSwitchCase(final List values, final ItemModel model) { this.values = Objects.requireNonNull(values, "values"); this.model = Objects.requireNonNull(model, "model"); } diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/AnimationFrame.java b/src/main/java/net/hellheim/spongetools/resourcepack/meta/AnimationFrame.java similarity index 97% rename from src/main/java/net/hellheim/spongetools/custom/metadata/AnimationFrame.java rename to src/main/java/net/hellheim/spongetools/resourcepack/meta/AnimationFrame.java index 8b14668..8421389 100644 --- a/src/main/java/net/hellheim/spongetools/custom/metadata/AnimationFrame.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/meta/AnimationFrame.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.metadata; +package net.hellheim.spongetools.resourcepack.meta; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/GuiScaling.java b/src/main/java/net/hellheim/spongetools/resourcepack/meta/GuiScaling.java similarity index 99% rename from src/main/java/net/hellheim/spongetools/custom/metadata/GuiScaling.java rename to src/main/java/net/hellheim/spongetools/resourcepack/meta/GuiScaling.java index f21f1b4..eaccb5b 100644 --- a/src/main/java/net/hellheim/spongetools/custom/metadata/GuiScaling.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/meta/GuiScaling.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.metadata; +package net.hellheim.spongetools.resourcepack.meta; import java.util.Objects; import java.util.OptionalInt; diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/Metadata.java b/src/main/java/net/hellheim/spongetools/resourcepack/meta/Metadata.java similarity index 94% rename from src/main/java/net/hellheim/spongetools/custom/metadata/Metadata.java rename to src/main/java/net/hellheim/spongetools/resourcepack/meta/Metadata.java index 734c40a..9bd6603 100644 --- a/src/main/java/net/hellheim/spongetools/custom/metadata/Metadata.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/meta/Metadata.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.metadata; +package net.hellheim.spongetools.resourcepack.meta; import java.util.Arrays; import java.util.Collection; diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataLike.java b/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataLike.java similarity index 53% rename from src/main/java/net/hellheim/spongetools/custom/metadata/MetadataLike.java rename to src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataLike.java index d2bfbdb..e309806 100644 --- a/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataLike.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataLike.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.metadata; +package net.hellheim.spongetools.resourcepack.meta; public interface MetadataLike { diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSection.java b/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSection.java similarity index 98% rename from src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSection.java rename to src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSection.java index 272ab9a..880352a 100644 --- a/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSection.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSection.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.metadata; +package net.hellheim.spongetools.resourcepack.meta; import java.util.ArrayList; import java.util.List; @@ -22,6 +22,7 @@ import net.hellheim.spongetools.codec.list.AdventureCodecs; import net.hellheim.spongetools.codec.list.ExtraCodecs; import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; +import net.hellheim.spongetools.resourcepack.util.VillagerHat; import net.kyori.adventure.text.Component; public interface MetadataSection extends MapCodecProxy, MetadataSectionLike { diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSectionLike.java b/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSectionLike.java similarity index 76% rename from src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSectionLike.java rename to src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSectionLike.java index 5c310e5..f50008b 100644 --- a/src/main/java/net/hellheim/spongetools/custom/metadata/MetadataSectionLike.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSectionLike.java @@ -1,4 +1,4 @@ -package net.hellheim.spongetools.custom.metadata; +package net.hellheim.spongetools.resourcepack.meta; public interface MetadataSectionLike extends MetadataLike { diff --git a/src/main/java/net/hellheim/spongetools/custom/metadata/VillagerHat.java b/src/main/java/net/hellheim/spongetools/resourcepack/util/VillagerHat.java similarity index 67% rename from src/main/java/net/hellheim/spongetools/custom/metadata/VillagerHat.java rename to src/main/java/net/hellheim/spongetools/resourcepack/util/VillagerHat.java index 52d0225..212ad6a 100644 --- a/src/main/java/net/hellheim/spongetools/custom/metadata/VillagerHat.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/util/VillagerHat.java @@ -1,27 +1,26 @@ -package net.hellheim.spongetools.custom.metadata; +package net.hellheim.spongetools.resourcepack.util; import org.spongepowered.api.data.type.StringRepresentable; import com.mojang.serialization.Codec; import net.hellheim.spongetools.codec.StringRepresentableCodec; +import net.hellheim.spongetools.resourcepack.meta.MetadataSection; +import net.hellheim.spongetools.resourcepack.meta.MetadataSectionLike; public enum VillagerHat implements StringRepresentable, MetadataSectionLike { - NONE("none"), - PARTIAL("partial"), - FULL("full"); - public static final Codec CODEC = StringRepresentableCodec.fromValues(VillagerHat::values); + NONE, - private final String name; + PARTIAL, - private VillagerHat(String name) { - this.name = name; - } + FULL; + + public static final Codec CODEC = StringRepresentableCodec.fromValues(VillagerHat::values); @Override public String serializationString() { - return this.name; + return this.name().toLowerCase(); } @Override From 1838e31b15b320ed51ae341919eb48ffbbe426ca Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sat, 17 May 2025 12:23:54 +0300 Subject: [PATCH 18/55] continue custom stuff --- .../behaviour/BehaviourCallbackHolder.java | 8 +++- .../behaviour/type/BlockStateBehaviours.java | 9 ++-- .../spongetools/custom/type/CustomType.java | 4 ++ .../type/block/BasicCustomBlockType.java | 41 +++++-------------- .../custom/type/block/BlockStateHolder.java | 9 +++- .../custom/type/block/BlockStateProvider.java | 3 +- .../custom/type/block/CustomBlockType.java | 21 ++-------- .../type/block/CustomBlockTypeBuilder.java | 22 +++++++++- .../type/block/CustomBlockTypeLike.java | 15 +++++++ .../type/block/CustomBlockTypePresets.java | 31 ++++++++++++++ .../type/block/CustomBlockTypeProperties.java | 30 +++++++++++++- .../type/block/DefaultedCustomBlockType.java | 30 ++++++++++++++ .../type/block/NoAvailableStateException.java | 14 ------- .../custom/type/item/CustomItemType.java | 2 + 14 files changed, 168 insertions(+), 71 deletions(-) create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/CustomType.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeLike.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/block/DefaultedCustomBlockType.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/type/block/NoAvailableStateException.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java index 5bcf238..920fde1 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java @@ -67,11 +67,15 @@ default M offer(final TypedBehaviourCallback holder) { - Objects.requireNonNull(holder, "holder").callbacks().forEach(this::offer); + default M offerAll(final Iterable> callbacks) { + Objects.requireNonNull(callbacks, "callbacks").forEach(t -> this.offer(t)); return this.cast(); } + default M offerFrom(final BehaviourCallbackHolder holder) { + return this.offerAll(Objects.requireNonNull(holder, "holder").callbacks()); + } + default M offerFrom( final BehaviourType> type, final BehaviourCallbackHolder holder diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java index a8d9724..e7abd0f 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java @@ -8,6 +8,7 @@ import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.EntityType; import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.fluid.FluidState; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.map.color.MapColorType; import org.spongepowered.api.util.AABB; @@ -44,18 +45,18 @@ public final class BlockStateBehaviours { /** * Signal that will power neighbour blocks. */ - public static final BehaviourType WEAK_SIGNAL = BehaviourType.create(); + public static final BehaviourType DIRECT_SIGNAL = BehaviourType.create(); /** * Signal that will go through neighbour blocks.
* * In vanilla this behaviour usually filters result of * {@link BlockStateExtension#get(BehaviourType)} - * for {@link #WEAK_SIGNAL} behaviour by side.
+ * for {@link #DIRECT_SIGNAL} behaviour by side.
* * Used by {@link BlockTypes#REPEATER} (horizontally) and other redstone-related blocks (upwards). */ - public static final BehaviourType STRONG_SIGNAL = BehaviourType.create(); + public static final BehaviourType INDIRECT_SIGNAL = BehaviourType.create(); /** * Result of this behaviour is usually used by {@link BlockTypes#COMPARATOR}. @@ -148,6 +149,8 @@ public final class BlockStateBehaviours { */ public static final BehaviourType> INSTRUMENT = BehaviourType.create(); + public static final BehaviourType> FLUID = BehaviourType.create(); + public static final BehaviourType REQUIRE_TOOL = BehaviourType.create(); public static final BehaviourType REPLACEABLE = BehaviourType.create(); diff --git a/src/main/java/net/hellheim/spongetools/custom/type/CustomType.java b/src/main/java/net/hellheim/spongetools/custom/type/CustomType.java new file mode 100644 index 0000000..87f5970 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/CustomType.java @@ -0,0 +1,4 @@ +package net.hellheim.spongetools.custom.type; + +public interface CustomType { +} diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java index 8154fcf..4308bb6 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java @@ -1,40 +1,30 @@ package net.hellheim.spongetools.custom.type.block; -import java.util.List; import java.util.Objects; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.spongepowered.api.block.BlockState; -import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; -import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderLogic; -import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderProxy; import net.hellheim.spongetools.custom.behaviour.BehaviourHolder; -import net.hellheim.spongetools.custom.behaviour.BehaviourHolderProxy; import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; -import net.hellheim.spongetools.resourcepack.block.Variant; -public class BasicCustomBlockType implements - CustomBlockType, - BehaviourHolderProxy, - BehaviourCallbackHolderProxy { +public class BasicCustomBlockType implements DefaultedCustomBlockType { - private final BehaviourCallbackHolderLogic callbacks; - private final BlockStateProvider stateProvider; - private final List model; + private final CustomBlockTypeProperties propeties; private @MonotonicNonNull BlockState state; private @MonotonicNonNull BlockStateExtension stateExtension; + public BasicCustomBlockType(final CustomBlockTypeProperties propeties) { + this.propeties = Objects.requireNonNull(propeties, "propeties"); + } + public BasicCustomBlockType(final CustomBlockTypeBuilder builder) { - Objects.requireNonNull(builder, "builder").validate(); - this.callbacks = builder.callbacks.asImmutable(); - this.stateProvider = builder.stateProvider; - this.model = List.copyOf(builder.model); + this(Objects.requireNonNull(builder, "builder").buildProperties()); } @Override - public BlockStateProvider stateProvider() { - return this.stateProvider; + public CustomBlockTypeProperties properties() { + return this.propeties; } @Override @@ -56,18 +46,7 @@ public void bind(final BlockState state) { this.stateExtension = BlockStateExtension.getFor(state); } - @Override - public List model() { - return this.model; - } - - @Override - public BehaviourHolder getAsBehaviourHolder() { + public BehaviourHolder stateExtension() { return this.stateExtension; } - - @Override - public BehaviourCallbackHolder getAsBehaviourCallbackHolder() { - return this.callbacks; - } } diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java index 0ba55a3..2b98d76 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java @@ -2,7 +2,9 @@ import org.spongepowered.api.block.BlockState; -public interface BlockStateHolder { +import net.hellheim.spongetools.proxy.solid.block.BlockStateProxy; + +public interface BlockStateHolder extends BlockStateProxy { /** * @return The state bound to this holder @@ -24,4 +26,9 @@ public interface BlockStateHolder { * @throws IllegalStateException if state is already bound */ void bind(BlockState state); + + @Override + default BlockState getAsBlockState() { + return this.state(); + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java index 2d3a1f6..ae74988 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java @@ -67,7 +67,8 @@ default BlockState provide(final Predicate predicate) { return this.availableStates() .filter(predicate) .findAny() - .orElseThrow(() -> new NoAvailableStateException(this.toString())); + .orElseThrow(() -> new IllegalStateException( + "No available states for provider " + this.toString())); } default Stream availableStates() { diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java index 83dea31..44df457 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java @@ -1,6 +1,5 @@ package net.hellheim.spongetools.custom.type.block; -import java.util.List; import java.util.Optional; import org.spongepowered.api.ResourceKey; @@ -11,15 +10,12 @@ import net.hellheim.spongetools.SpongeTools; import net.hellheim.spongetools.codec.list.RegistryCodecs; -import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; -import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; -import net.hellheim.spongetools.proxy.solid.block.BlockStateProxy; -import net.hellheim.spongetools.resourcepack.block.Variant; +import net.hellheim.spongetools.custom.type.CustomType; public interface CustomBlockType extends - BehaviourCallbackHolder, - BlockStateHolder, - BlockStateProxy { + CustomType, + CustomBlockTypeLike, + BlockStateHolder { static DefaultedRegistryType registry() { return SpongeTools.Registries.CUSTOM_BLOCK_TYPE; @@ -39,13 +35,4 @@ static Optional get(final BlockState state) { return BlockStateDispatcher.get().get(state) .map(holder -> holder instanceof final CustomBlockType block ? block : null); } - - BlockStateProvider stateProvider(); - - List model(); - - @Override - default BlockState getAsBlockState() { - return this.state(); - } } diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java index ea5be1c..a3a331f 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java @@ -134,6 +134,22 @@ public B model(final Iterable variants) { } + public B from(final CustomBlockType type) { + Objects.requireNonNull(type, "type"); + return this.reset() + .offerFrom(type) + .state(type.stateProvider()) + .model(type.model()); + } + + public B from(final CustomBlockTypeProperties properties) { + Objects.requireNonNull(properties, "properties"); + return this.reset() + .offerFrom(properties) + .state(properties.stateProvider()) + .model(properties.model()); + } + public B reset() { this.callbacks = BehaviourCallbackHolderLogic.mutable(); this.stateProvider = null; @@ -149,7 +165,11 @@ public B validate() { return this.cast(); } + public CustomBlockTypeProperties buildProperties() { + return new CustomBlockTypeProperties(this); + } + public CustomBlockType build() { - return new BasicCustomBlockType(this); + return new BasicCustomBlockType(this.buildProperties()); } } diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeLike.java b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeLike.java new file mode 100644 index 0000000..129ae0e --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeLike.java @@ -0,0 +1,15 @@ +package net.hellheim.spongetools.custom.type.block; + +import java.util.List; + +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; +import net.hellheim.spongetools.resourcepack.block.Variant; + +public interface CustomBlockTypeLike extends + BehaviourCallbackHolder { + + BlockStateProvider stateProvider(); + + List model(); +} diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java new file mode 100644 index 0000000..8932e0b --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java @@ -0,0 +1,31 @@ +package net.hellheim.spongetools.custom.type.block; + +import java.util.function.Consumer; + +import org.spongepowered.api.fluid.FluidTypes; + +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviours; + +public final class CustomBlockTypePresets { + + public static final CustomBlockTypeProperties + + SLAB = create(b -> b.state(BlockStateProvider.slab()) + .set(BlockStateBehaviours.FLUID, () -> FluidTypes.EMPTY.get().defaultState()) + .offer); + + private static final CustomBlockTypeProperties create( + final Consumer> configurator + ) { + final var builder = builder(); + configurator.accept(builder); + return builder.buildProperties(); + } + + private static final CustomBlockTypeBuilder builder() { + return new CustomBlockTypeBuilder<>(); + } + + private CustomBlockTypePresets() { + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java index 8c3e8f8..807fd36 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java @@ -1,17 +1,45 @@ package net.hellheim.spongetools.custom.type.block; +import java.util.List; +import java.util.Objects; + import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderLogic; import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderProxy; import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; +import net.hellheim.spongetools.resourcepack.block.Variant; public class CustomBlockTypeProperties implements + CustomBlockTypeLike, BehaviourCallbackHolderProxy { - private final BehaviourCallbackHolderLogic.Immutable callbacks = null; + private final BehaviourCallbackHolderLogic callbacks; + private final BlockStateProvider stateProvider; + private final List model; + + public CustomBlockTypeProperties(final CustomBlockTypeBuilder builder) { + Objects.requireNonNull(builder, "builder").validate(); + this.callbacks = builder.callbacks.asImmutable(); + this.stateProvider = builder.stateProvider; + this.model = List.copyOf(builder.model); + } @Override public BehaviourCallbackHolder getAsBehaviourCallbackHolder() { return this.callbacks; } + + @Override + public BlockStateProvider stateProvider() { + return this.stateProvider; + } + + @Override + public List model() { + return this.model; + } + + public CustomBlockTypeBuilder toBuilder() { + return new CustomBlockTypeBuilder<>(); + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/DefaultedCustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/type/block/DefaultedCustomBlockType.java new file mode 100644 index 0000000..de1b0d8 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/DefaultedCustomBlockType.java @@ -0,0 +1,30 @@ +package net.hellheim.spongetools.custom.type.block; + +import java.util.List; + +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolder; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderProxy; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; +import net.hellheim.spongetools.resourcepack.block.Variant; + +public interface DefaultedCustomBlockType extends + CustomBlockType, + BehaviourCallbackHolderProxy { + + CustomBlockTypeProperties properties(); + + @Override + default BehaviourCallbackHolder getAsBehaviourCallbackHolder() { + return this.properties(); + } + + @Override + default BlockStateProvider stateProvider() { + return this.properties().stateProvider(); + } + + @Override + default List model() { + return this.properties().model(); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/NoAvailableStateException.java b/src/main/java/net/hellheim/spongetools/custom/type/block/NoAvailableStateException.java deleted file mode 100644 index 20be41e..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/NoAvailableStateException.java +++ /dev/null @@ -1,14 +0,0 @@ -package net.hellheim.spongetools.custom.type.block; - -public class NoAvailableStateException extends IllegalStateException { - - private static final long serialVersionUID = -8505232760736136326L; - - public NoAvailableStateException() { - super(); - } - - public NoAvailableStateException(String message) { - super(message); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java index 06723fc..b494e4a 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java @@ -23,11 +23,13 @@ import net.hellheim.spongetools.SpongeTools; import net.hellheim.spongetools.codec.list.RegistryCodecs; +import net.hellheim.spongetools.custom.type.CustomType; import net.hellheim.spongetools.proxy.solid.item.ItemStackSnapshotProxy; import net.hellheim.spongetools.resourcepack.item.ItemDefinition; import net.kyori.adventure.text.ComponentLike; public interface CustomItemType extends + CustomType, ResourceKeyed, ComponentLike, DataSerializable, From 3a49748ac956c070bf0cf694275a7f00c749cdd8 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Thu, 22 May 2025 18:51:40 +0300 Subject: [PATCH 19/55] math --- .../math/mutable/package-info.java | 8 + .../math/mutable/vector/MutableVector2d.java | 366 ++++++++++++ .../math/mutable/vector/MutableVector2f.java | 446 ++++++++++++++ .../math/mutable/vector/MutableVector2i.java | 422 ++++++++++++++ .../math/mutable/vector/MutableVector2l.java | 422 ++++++++++++++ .../math/mutable/vector/MutableVector3d.java | 411 +++++++++++++ .../math/mutable/vector/MutableVector3f.java | 499 ++++++++++++++++ .../math/mutable/vector/MutableVector3i.java | 475 +++++++++++++++ .../math/mutable/vector/MutableVector3l.java | 475 +++++++++++++++ .../math/mutable/vector/MutableVector4d.java | 456 +++++++++++++++ .../math/mutable/vector/MutableVector4f.java | 544 ++++++++++++++++++ .../math/mutable/vector/MutableVector4i.java | 520 +++++++++++++++++ .../math/mutable/vector/MutableVector4l.java | 520 +++++++++++++++++ .../math/optional/package-info.java | 7 + .../optional/vector/OptionalVector2d.java | 219 +++++++ .../optional/vector/OptionalVector2i.java | 220 +++++++ .../optional/vector/OptionalVector2l.java | 220 +++++++ .../optional/vector/OptionalVector3d.java | 310 ++++++++++ .../optional/vector/OptionalVector3i.java | 311 ++++++++++ .../optional/vector/OptionalVector3l.java | 311 ++++++++++ .../optional/vector/OptionalVector4d.java | 481 ++++++++++++++++ .../optional/vector/OptionalVector4i.java | 482 ++++++++++++++++ .../optional/vector/OptionalVector4l.java | 482 ++++++++++++++++ .../spongetools/object/OptionalRotation.java | 90 +-- .../spongetools/object/OptionalVector3d.java | 146 ----- .../spongetools/object/Streamable.java | 70 +++ .../hellheim/spongetools/util/GeomUtil.java | 17 +- 27 files changed, 8708 insertions(+), 222 deletions(-) create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/package-info.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2d.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2f.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2i.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2l.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3d.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3f.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3i.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3l.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4d.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4f.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4i.java create mode 100644 src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4l.java create mode 100644 src/main/java/net/hellheim/spongetools/math/optional/package-info.java create mode 100644 src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2d.java create mode 100644 src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2i.java create mode 100644 src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2l.java create mode 100644 src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3d.java create mode 100644 src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3i.java create mode 100644 src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3l.java create mode 100644 src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4d.java create mode 100644 src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4i.java create mode 100644 src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4l.java delete mode 100644 src/main/java/net/hellheim/spongetools/object/OptionalVector3d.java create mode 100644 src/main/java/net/hellheim/spongetools/object/Streamable.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/package-info.java b/src/main/java/net/hellheim/spongetools/math/mutable/package-info.java new file mode 100644 index 0000000..20bccf1 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/package-info.java @@ -0,0 +1,8 @@ +/** + * This package provides mutable variants of objects from SpongePowered math.
+ *
+ * Most content is copied from the original and adjusted to be mutable. + * + * @see org.spongepowered.math + */ +package net.hellheim.spongetools.math.mutable; diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2d.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2d.java new file mode 100644 index 0000000..0f4b3d2 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2d.java @@ -0,0 +1,366 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector2d; +import org.spongepowered.math.vector.Vector2f; +import org.spongepowered.math.vector.Vector2i; +import org.spongepowered.math.vector.Vector2l; +import org.spongepowered.math.vector.Vectord; + +public final class MutableVector2d implements Vectord { + + private double x; + private double y; + + public MutableVector2d(final double x, final double y) { + this.x = x; + this.y = y; + } + + public double x() { + return this.x; + } + + public double y() { + return this.y; + } + + public MutableVector2d copy() { + return MutableVector2d.from(this); + } + + public MutableVector2d x(final MutableVector2d v) { + return this.x(v.x); + } + + public MutableVector2d x(final Vector2d v) { + return this.x(v.x()); + } + + public MutableVector2d x(final double a) { + this.x = a; + return this; + } + + public MutableVector2d y(final MutableVector2d v) { + return this.y(v.y); + } + + public MutableVector2d y(final Vector2d v) { + return this.y(v.y()); + } + + public MutableVector2d y(final double a) { + this.y = a; + return this; + } + + public MutableVector2d set(final MutableVector2d v) { + return this.set(v.x, v.y); + } + + public MutableVector2d set(final Vector2d v) { + return this.set(v.x(), v.y()); + } + + public MutableVector2d set(final double x, final double y) { + this.x = x; + this.y = y; + return this; + } + + public MutableVector2d add(final MutableVector2d v) { + return this.add(v.x, v.y); + } + + public MutableVector2d add(final Vector2d v) { + return this.add(v.x(), v.y()); + } + + public MutableVector2d add(final double x, final double y) { + this.x += x; + this.y += y; + return this; + } + + public MutableVector2d sub(final MutableVector2d v) { + return this.sub(v.x, v.y); + } + + public MutableVector2d sub(final Vector2d v) { + return this.sub(v.x(), v.y()); + } + + public MutableVector2d sub(final double x, final double y) { + this.x -= x; + this.y -= y; + return this; + } + + @Override + public MutableVector2d mul(final double a) { + return this.mul(a, a); + } + + public MutableVector2d mul(final MutableVector2d v) { + return this.mul(v.x, v.y); + } + + public MutableVector2d mul(final Vector2d v) { + return this.mul(v.x(), v.y()); + } + + public MutableVector2d mul(final double x, final double y) { + this.x *= x; + this.y *= y; + return this; + } + + @Override + public MutableVector2d div(final double a) { + return this.div(a, a); + } + + public MutableVector2d div(final MutableVector2d v) { + return this.div(v.x, v.y); + } + + public MutableVector2d div(final Vector2d v) { + return this.div(v.x(), v.y()); + } + + public MutableVector2d div(final double x, final double y) { + this.x /= x; + this.y /= y; + return this; + } + + public double dot(final MutableVector2d v) { + return this.dot(v.x, v.y); + } + + public double dot(final Vector2d v) { + return this.dot(v.x(), v.y()); + } + + public double dot(final double x, final double y) { + return this.x * x + this.y * y; + } + + public MutableVector2d project(final MutableVector2d v) { + return this.project(v.x, v.y); + } + + public MutableVector2d project(final Vector2d v) { + return this.project(v.x(), v.y()); + } + + public MutableVector2d project(final double x, final double y) { + final double lengthSquared = x * x + y * y; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final double a = this.dot(x, y) / lengthSquared; + return this.set(a * x, a * y); + } + + @Override + public MutableVector2d pow(final double pow) { + return this.pow(pow, pow); + } + + public MutableVector2d pow(final MutableVector2d v) { + return this.pow(v.x, v.y); + } + + public MutableVector2d pow(final Vector2d v) { + return this.pow(v.x(), v.y()); + } + + public MutableVector2d pow(final double x, final double y) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y)); + } + + @Override + public MutableVector2d ceil() { + return this.set(Math.ceil(this.x), Math.ceil(this.y)); + } + + @Override + public MutableVector2d floor() { + return this.set(GenericMath.floor(this.x), GenericMath.floor(this.y)); + } + + @Override + public MutableVector2d round() { + return this.set(Math.round(this.x), Math.round(this.y)); + } + + @Override + public MutableVector2d abs() { + return this.set(Math.abs(this.x), Math.abs(this.y)); + } + + @Override + public MutableVector2d negate() { + return this.set(-this.x, -this.y); + } + + public MutableVector2d min(final MutableVector2d v) { + return this.min(v.x, v.y); + } + + public MutableVector2d min(final Vector2d v) { + return this.min(v.x(), v.y()); + } + + public MutableVector2d min(final double x, final double y) { + return this.set(Math.min(this.x, x), Math.min(this.y, y)); + } + + public MutableVector2d max(final MutableVector2d v) { + return this.max(v.x, v.y); + } + + public MutableVector2d max(final Vector2d v) { + return this.max(v.x(), v.y()); + } + + public MutableVector2d max(final double x, final double y) { + return this.set(Math.max(this.x, x), Math.max(this.y, y)); + } + + public double distanceSquared(final MutableVector2d v) { + return this.distanceSquared(v.x, v.y); + } + + public double distanceSquared(final Vector2d v) { + return this.distanceSquared(v.x(), v.y()); + } + + public double distanceSquared(final double x, final double y) { + final double dx = this.x - x; + final double dy = this.y - y; + return dx * dx + dy * dy; + } + + public double distance(final MutableVector2d v) { + return this.distance(v.x, v.y); + } + + public double distance(final Vector2d v) { + return this.distance(v.x(), v.y()); + } + + public double distance(final double x, final double y) { + return Math.sqrt(this.distanceSquared(x, y)); + } + + @Override + public double lengthSquared() { + return this.x * this.x + this.y * this.y; + } + + @Override + public double length() { + return Math.sqrt(this.lengthSquared()); + } + + @Override + public MutableVector2d normalize() { + final double length = this.length(); + if (Math.abs(length) < GenericMath.FLT_EPSILON) { + throw new ArithmeticException("Cannot normalize the zero vector"); + } + return this.set(this.x / length, this.y / length); + } + + @Override + public int minAxis() { + return this.x < this.y ? 0 : 1; + } + + @Override + public int maxAxis() { + return this.x > this.y ? 0 : 1; + } + + @Override + public double[] toArray() { + return new double[]{this.x, this.y}; + } + + @Override + public Vector2i toInt() { + return new Vector2i(this.x, this.y); + } + + @Override + public Vector2l toLong() { + return new Vector2l(this.x, this.y); + } + + @Override + public Vector2f toFloat() { + return new Vector2f(this.x, this.y); + } + + @Override + public Vector2d toDouble() { + return new Vector2d((double) this.x, (double) this.y); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector2d that)) { + return false; + } else { + return Double.compare(that.x, this.x) == 0 + && Double.compare(that.y, this.y) == 0; + } + } + + @Override + public int hashCode() { + return Double.hashCode(this.x) * 31 + Double.hashCode(this.y); + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ")"; + } + + public static MutableVector2d zero() { + return MutableVector2d.of(0, 0); + } + + public static MutableVector2d unitX() { + return MutableVector2d.of(1, 0); + } + + public static MutableVector2d unitY() { + return MutableVector2d.of(0, 1); + } + + public static MutableVector2d one() { + return MutableVector2d.of(1, 1); + } + + public static MutableVector2d from(final double n) { + return MutableVector2d.of(n, n); + } + + public static MutableVector2d from(final MutableVector2d v) { + return MutableVector2d.of(v.x, v.y); + } + + public static MutableVector2d from(final Vector2d v) { + return MutableVector2d.of(v.x(), v.y()); + } + + public static MutableVector2d of(final double x, final double y) { + return new MutableVector2d(x, y); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2f.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2f.java new file mode 100644 index 0000000..507ee1f --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2f.java @@ -0,0 +1,446 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector2d; +import org.spongepowered.math.vector.Vector2f; +import org.spongepowered.math.vector.Vector2i; +import org.spongepowered.math.vector.Vector2l; +import org.spongepowered.math.vector.Vectorf; + +public final class MutableVector2f implements Vectorf { + + private float x; + private float y; + + public MutableVector2f(final double x, final double y) { + this((float) x, (float) y); + } + + public MutableVector2f(final float x, final float y) { + this.x = x; + this.y = y; + } + + public float x() { + return this.x; + } + + public float y() { + return this.y; + } + + public MutableVector2f copy() { + return MutableVector2f.from(this); + } + + public MutableVector2f x(final MutableVector2f v) { + return this.x(v.x); + } + + public MutableVector2f x(final Vector2f v) { + return this.x(v.x()); + } + + public MutableVector2f x(final double a) { + return this.x((float) a); + } + + public MutableVector2f x(final float a) { + this.x = a; + return this; + } + + public MutableVector2f y(final MutableVector2f v) { + return this.y(v.y); + } + + public MutableVector2f y(final Vector2f v) { + return this.y(v.y()); + } + + public MutableVector2f y(final double a) { + return this.y((float) a); + } + + public MutableVector2f y(final float a) { + this.y = a; + return this; + } + + public MutableVector2f set(final MutableVector2f v) { + return this.set(v.x, v.y); + } + + public MutableVector2f set(final Vector2f v) { + return this.set(v.x(), v.y()); + } + + public MutableVector2f set(final double x, final double y) { + return this.set((float) x, (float) y); + } + + public MutableVector2f set(final float x, final float y) { + this.x = x; + this.y = y; + return this; + } + + public MutableVector2f add(final MutableVector2f v) { + return this.add(v.x, v.y); + } + + public MutableVector2f add(final Vector2f v) { + return this.add(v.x(), v.y()); + } + + public MutableVector2f add(final double x, final double y) { + return this.add((float) x, (float) y); + } + + public MutableVector2f add(final float x, final float y) { + this.x += x; + this.y += y; + return this; + } + + public MutableVector2f sub(final MutableVector2f v) { + return this.sub(v.x, v.y); + } + + public MutableVector2f sub(final Vector2f v) { + return this.sub(v.x(), v.y()); + } + + public MutableVector2f sub(final double x, final double y) { + return this.sub((float) x, (float) y); + } + + public MutableVector2f sub(final float x, final float y) { + this.x -= x; + this.y -= y; + return this; + } + + public MutableVector2f mul(final double a) { + return this.mul((float) a); + } + + @Override + public MutableVector2f mul(final float a) { + return this.mul(a, a); + } + + public MutableVector2f mul(final MutableVector2f v) { + return this.mul(v.x, v.y); + } + + public MutableVector2f mul(final Vector2f v) { + return this.mul(v.x(), v.y()); + } + + public MutableVector2f mul(final double x, final double y) { + return this.mul((float) x, (float) y); + } + + public MutableVector2f mul(final float x, final float y) { + this.x *= x; + this.y *= y; + return this; + } + + public MutableVector2f div(final double a) { + return this.div((float) a); + } + + @Override + public MutableVector2f div(final float a) { + return this.div(a, a); + } + + public MutableVector2f div(final MutableVector2f v) { + return this.div(v.x, v.y); + } + + public MutableVector2f div(final Vector2f v) { + return this.div(v.x(), v.y()); + } + + public MutableVector2f div(final double x, final double y) { + return this.div((float) x, (float) y); + } + + public MutableVector2f div(final float x, final float y) { + this.x /= x; + this.y /= y; + return this; + } + + public float dot(final MutableVector2f v) { + return this.dot(v.x, v.y); + } + + public float dot(final Vector2f v) { + return this.dot(v.x(), v.y()); + } + + public float dot(final double x, final double y) { + return this.dot((float) x, (float) y); + } + + public float dot(final float x, final float y) { + return this.x * x + this.y * y; + } + + public MutableVector2f project(final MutableVector2f v) { + return this.project(v.x, v.y); + } + + public MutableVector2f project(final Vector2f v) { + return this.project(v.x(), v.y()); + } + + public MutableVector2f project(final double x, final double y) { + return this.project((float) x, (float) y); + } + + public MutableVector2f project(final float x, final float y) { + final float lengthSquared = x * x + y * y; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final float a = this.dot(x, y) / lengthSquared; + return this.set(a * x, a * y); + } + + public MutableVector2f pow(final double pow) { + return this.pow((float) pow); + } + + @Override + public MutableVector2f pow(final float pow) { + return this.pow(pow, pow); + } + + public MutableVector2f pow(final MutableVector2f v) { + return this.pow(v.x, v.y); + } + + public MutableVector2f pow(final Vector2f v) { + return this.pow(v.x(), v.y()); + } + + public MutableVector2f pow(final double x, final double y) { + return this.pow((float) x, (float) y); + } + + public MutableVector2f pow(final float x, final float y) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y)); + } + + @Override + public MutableVector2f ceil() { + return this.set(Math.ceil(this.x), Math.ceil(this.y)); + } + + @Override + public MutableVector2f floor() { + return this.set(GenericMath.floor(this.x), GenericMath.floor(this.y)); + } + + @Override + public MutableVector2f round() { + return this.set(Math.round(this.x), Math.round(this.y)); + } + + @Override + public MutableVector2f abs() { + return this.set(Math.abs(this.x), Math.abs(this.y)); + } + + @Override + public MutableVector2f negate() { + return this.set(-this.x, -this.y); + } + + public MutableVector2f min(final MutableVector2f v) { + return this.min(v.x, v.y); + } + + public MutableVector2f min(final Vector2f v) { + return this.min(v.x(), v.y()); + } + + public MutableVector2f min(final double x, final double y) { + return this.min((float) x, (float) y); + } + + public MutableVector2f min(final float x, final float y) { + return this.set(Math.min(this.x, x), Math.min(this.y, y)); + } + + public MutableVector2f max(final MutableVector2f v) { + return this.max(v.x, v.y); + } + + public MutableVector2f max(final Vector2f v) { + return this.max(v.x(), v.y()); + } + + public MutableVector2f max(final double x, final double y) { + return this.max((float) x, (float) y); + } + + public MutableVector2f max(final float x, final float y) { + return this.set(Math.max(this.x, x), Math.max(this.y, y)); + } + + public float distanceSquared(final MutableVector2f v) { + return this.distanceSquared(v.x, v.y); + } + + public float distanceSquared(final Vector2f v) { + return this.distanceSquared(v.x(), v.y()); + } + + public float distanceSquared(final double x, final double y) { + return this.distanceSquared((float) x, (float) y); + } + + public float distanceSquared(final float x, final float y) { + final float dx = this.x - x; + final float dy = this.y - y; + return dx * dx + dy * dy; + } + + public float distance(final MutableVector2f v) { + return this.distance(v.x, v.y); + } + + public float distance(final Vector2f v) { + return this.distance(v.x(), v.y()); + } + + public float distance(final double x, final double y) { + return this.distance((float) x, (float) y); + } + + public float distance(final float x, final float y) { + return (float) Math.sqrt(this.distanceSquared(x, y)); + } + + @Override + public float lengthSquared() { + return this.x * this.x + this.y * this.y; + } + + @Override + public float length() { + return (float) Math.sqrt(this.lengthSquared()); + } + + @Override + public MutableVector2f normalize() { + final float length = this.length(); + if (Math.abs(length) < GenericMath.FLT_EPSILON) { + throw new ArithmeticException("Cannot normalize the zero vector"); + } + return this.set(this.x / length, this.y / length); + } + + @Override + public int minAxis() { + return this.x < this.y ? 0 : 1; + } + + @Override + public int maxAxis() { + return this.x > this.y ? 0 : 1; + } + + @Override + public float[] toArray() { + return new float[]{this.x, this.y}; + } + + @Override + public Vector2i toInt() { + return new Vector2i(this.x, this.y); + } + + @Override + public Vector2l toLong() { + return new Vector2l(this.x, this.y); + } + + @Override + public Vector2f toFloat() { + return new Vector2f(this.x, this.y); + } + + @Override + public Vector2d toDouble() { + return new Vector2d((double) this.x, (double) this.y); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector2f that)) { + return false; + } else { + return Float.compare(that.x, this.x) == 0 + && Float.compare(that.y, this.y) == 0; + } + } + + @Override + public int hashCode() { + return Float.hashCode(this.x) * 31 + Float.hashCode(this.y); + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ")"; + } + + public static MutableVector2f zero() { + return MutableVector2f.of(0, 0); + } + + public static MutableVector2f unitX() { + return MutableVector2f.of(1, 0); + } + + public static MutableVector2f unitY() { + return MutableVector2f.of(0, 1); + } + + public static MutableVector2f one() { + return MutableVector2f.of(1, 1); + } + + public static MutableVector2f from(final double n) { + return MutableVector2f.from((float) n); + } + + public static MutableVector2f from(final float n) { + return MutableVector2f.of(n, n); + } + + public static MutableVector2f from(final MutableVector2f v) { + return MutableVector2f.of(v.x, v.y); + } + + public static MutableVector2f from(final Vector2f v) { + return MutableVector2f.of(v.x(), v.y()); + } + + public static MutableVector2f of(final double x, final double y) { + return new MutableVector2f(x, y); + } + + public static MutableVector2f of(final float x, final float y) { + return new MutableVector2f(x, y); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2i.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2i.java new file mode 100644 index 0000000..56c3b75 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2i.java @@ -0,0 +1,422 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector2d; +import org.spongepowered.math.vector.Vector2f; +import org.spongepowered.math.vector.Vector2i; +import org.spongepowered.math.vector.Vector2l; +import org.spongepowered.math.vector.Vectori; + +public final class MutableVector2i implements Vectori { + + private int x; + private int y; + + public MutableVector2i(final double x, final double y) { + this(GenericMath.floor(x), GenericMath.floor(y)); + } + + public MutableVector2i(final int x, final int y) { + this.x = x; + this.y = y; + } + + public int x() { + return this.x; + } + + public int y() { + return this.y; + } + + public MutableVector2i copy() { + return MutableVector2i.from(this); + } + + public MutableVector2i x(final MutableVector2i v) { + return this.x(v.x); + } + + public MutableVector2i x(final Vector2i v) { + return this.x(v.x()); + } + + public MutableVector2i x(final double a) { + return this.x(GenericMath.floor(a)); + } + + public MutableVector2i x(final int a) { + this.x = a; + return this; + } + + public MutableVector2i y(final MutableVector2i v) { + return this.y(v.y); + } + + public MutableVector2i y(final Vector2i v) { + return this.y(v.y()); + } + + public MutableVector2i y(final double a) { + return this.y(GenericMath.floor(a)); + } + + public MutableVector2i y(final int a) { + this.y = a; + return this; + } + + public MutableVector2i set(final MutableVector2i v) { + return this.set(v.x, v.y); + } + + public MutableVector2i set(final Vector2i v) { + return this.set(v.x(), v.y()); + } + + public MutableVector2i set(final double x, final double y) { + return this.set(GenericMath.floor(x), GenericMath.floor(y)); + } + + public MutableVector2i set(final int x, final int y) { + this.x = x; + this.y = y; + return this; + } + + public MutableVector2i add(final MutableVector2i v) { + return this.add(v.x, v.y); + } + + public MutableVector2i add(final Vector2i v) { + return this.add(v.x(), v.y()); + } + + public MutableVector2i add(final double x, final double y) { + return this.add(GenericMath.floor(x), GenericMath.floor(y)); + } + + public MutableVector2i add(final int x, final int y) { + this.x += x; + this.y += y; + return this; + } + + public MutableVector2i sub(final MutableVector2i v) { + return this.sub(v.x, v.y); + } + + public MutableVector2i sub(final Vector2i v) { + return this.sub(v.x(), v.y()); + } + + public MutableVector2i sub(final double x, final double y) { + return this.sub(GenericMath.floor(x), GenericMath.floor(y)); + } + + public MutableVector2i sub(final int x, final int y) { + this.x -= x; + this.y -= y; + return this; + } + + public MutableVector2i mul(final double a) { + return this.mul(GenericMath.floor(a)); + } + + @Override + public MutableVector2i mul(final int a) { + return this.mul(a, a); + } + + public MutableVector2i mul(final MutableVector2i v) { + return this.mul(v.x, v.y); + } + + public MutableVector2i mul(final Vector2i v) { + return this.mul(v.x(), v.y()); + } + + public MutableVector2i mul(final double x, final double y) { + return this.mul(GenericMath.floor(x), GenericMath.floor(y)); + } + + public MutableVector2i mul(final int x, final int y) { + this.x *= x; + this.y *= y; + return this; + } + + public MutableVector2i div(final double a) { + return this.div(GenericMath.floor(a)); + } + + @Override + public MutableVector2i div(final int a) { + return this.div(a, a); + } + + public MutableVector2i div(final MutableVector2i v) { + return this.div(v.x, v.y); + } + + public MutableVector2i div(final Vector2i v) { + return this.div(v.x(), v.y()); + } + + public MutableVector2i div(final double x, final double y) { + return this.div(GenericMath.floor(x), GenericMath.floor(y)); + } + + public MutableVector2i div(final int x, final int y) { + this.x /= x; + this.y /= y; + return this; + } + + public int dot(final MutableVector2i v) { + return this.dot(v.x, v.y); + } + + public int dot(final Vector2i v) { + return this.dot(v.x(), v.y()); + } + + public int dot(final double x, final double y) { + return this.dot(GenericMath.floor(x), GenericMath.floor(y)); + } + + public int dot(final int x, final int y) { + return this.x * x + this.y * y; + } + + public MutableVector2i project(final MutableVector2i v) { + return this.project(v.x, v.y); + } + + public MutableVector2i project(final Vector2i v) { + return this.project(v.x(), v.y()); + } + + public MutableVector2i project(final double x, final double y) { + return this.project(GenericMath.floor(x), GenericMath.floor(y)); + } + + public MutableVector2i project(final int x, final int y) { + final int lengthSquared = x * x + y * y; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final float a = (float) this.dot(x, y) / lengthSquared; + return this.set(a * x, a * y); + } + + public MutableVector2i pow(final double pow) { + return this.pow(GenericMath.floor(pow)); + } + + @Override + public MutableVector2i pow(final int pow) { + return this.pow(pow, pow); + } + + public MutableVector2i pow(final MutableVector2i v) { + return this.pow(v.x, v.y); + } + + public MutableVector2i pow(final Vector2i v) { + return this.pow(v.x(), v.y()); + } + + public MutableVector2i pow(final double x, final double y) { + return this.pow(GenericMath.floor(x), GenericMath.floor(y)); + } + + public MutableVector2i pow(final int x, final int y) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y)); + } + + @Override + public MutableVector2i abs() { + return this.set(Math.abs(this.x), Math.abs(this.y)); + } + + @Override + public MutableVector2i negate() { + return this.set(-this.x, -this.y); + } + + public MutableVector2i min(final MutableVector2i v) { + return this.min(v.x, v.y); + } + + public MutableVector2i min(final Vector2i v) { + return this.min(v.x(), v.y()); + } + + public MutableVector2i min(final double x, final double y) { + return this.min(GenericMath.floor(x), GenericMath.floor(y)); + } + + public MutableVector2i min(final int x, final int y) { + return this.set(Math.min(this.x, x), Math.min(this.y, y)); + } + + public MutableVector2i max(final MutableVector2i v) { + return this.max(v.x, v.y); + } + + public MutableVector2i max(final Vector2i v) { + return this.max(v.x(), v.y()); + } + + public MutableVector2i max(final double x, final double y) { + return this.max(GenericMath.floor(x), GenericMath.floor(y)); + } + + public MutableVector2i max(final int x, final int y) { + return this.set(Math.max(this.x, x), Math.max(this.y, y)); + } + + public int distanceSquared(final MutableVector2i v) { + return this.distanceSquared(v.x, v.y); + } + + public int distanceSquared(final Vector2i v) { + return this.distanceSquared(v.x(), v.y()); + } + + public int distanceSquared(final double x, final double y) { + return this.distanceSquared(GenericMath.floor(x), GenericMath.floor(y)); + } + + public int distanceSquared(final int x, final int y) { + final int dx = this.x - x; + final int dy = this.y - y; + return dx * dx + dy * dy; + } + + public float distance(final MutableVector2i v) { + return this.distance(v.x, v.y); + } + + public float distance(final Vector2i v) { + return this.distance(v.x(), v.y()); + } + + public float distance(final double x, final double y) { + return this.distance(GenericMath.floor(x), GenericMath.floor(y)); + } + + public float distance(final int x, final int y) { + return (float) Math.sqrt(this.distanceSquared(x, y)); + } + + @Override + public int lengthSquared() { + return this.x * this.x + this.y * this.y; + } + + @Override + public float length() { + return (float) Math.sqrt(this.lengthSquared()); + } + + @Override + public int minAxis() { + return this.x < this.y ? 0 : 1; + } + + @Override + public int maxAxis() { + return this.x > this.y ? 0 : 1; + } + + @Override + public int[] toArray() { + return new int[]{this.x, this.y}; + } + + @Override + public Vector2i toInt() { + return new Vector2i(this.x, this.y); + } + + @Override + public Vector2l toLong() { + return new Vector2l(this.x, this.y); + } + + @Override + public Vector2f toFloat() { + return new Vector2f(this.x, this.y); + } + + @Override + public Vector2d toDouble() { + return new Vector2d((double) this.x, (double) this.y); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector2i that)) { + return false; + } else { + return that.x == this.x + && that.y == this.y; + } + } + + @Override + public int hashCode() { + return Integer.hashCode(this.x) * 31 + Integer.hashCode(this.y); + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ")"; + } + + public static MutableVector2i zero() { + return MutableVector2i.of(0, 0); + } + + public static MutableVector2i unitX() { + return MutableVector2i.of(1, 0); + } + + public static MutableVector2i unitY() { + return MutableVector2i.of(0, 1); + } + + public static MutableVector2i one() { + return MutableVector2i.of(1, 1); + } + + public static MutableVector2i from(final double n) { + return MutableVector2i.from(GenericMath.floor(n)); + } + + public static MutableVector2i from(final int n) { + return MutableVector2i.of(n, n); + } + + public static MutableVector2i from(final MutableVector2i v) { + return MutableVector2i.of(v.x, v.y); + } + + public static MutableVector2i from(final Vector2i v) { + return MutableVector2i.of(v.x(), v.y()); + } + + public static MutableVector2i of(final double x, final double y) { + return new MutableVector2i(x, y); + } + + public static MutableVector2i of(final int x, final int y) { + return new MutableVector2i(x, y); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2l.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2l.java new file mode 100644 index 0000000..648b955 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2l.java @@ -0,0 +1,422 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector2d; +import org.spongepowered.math.vector.Vector2f; +import org.spongepowered.math.vector.Vector2i; +import org.spongepowered.math.vector.Vector2l; +import org.spongepowered.math.vector.Vectorl; + +public final class MutableVector2l implements Vectorl { + + private long x; + private long y; + + public MutableVector2l(final double x, final double y) { + this(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public MutableVector2l(final long x, final long y) { + this.x = x; + this.y = y; + } + + public long x() { + return this.x; + } + + public long y() { + return this.y; + } + + public MutableVector2l copy() { + return MutableVector2l.from(this); + } + + public MutableVector2l x(final MutableVector2l v) { + return this.x(v.x); + } + + public MutableVector2l x(final Vector2l v) { + return this.x(v.x()); + } + + public MutableVector2l x(final double a) { + return this.x(GenericMath.floorl(a)); + } + + public MutableVector2l x(final long a) { + this.x = a; + return this; + } + + public MutableVector2l y(final MutableVector2l v) { + return this.y(v.y); + } + + public MutableVector2l y(final Vector2l v) { + return this.y(v.y()); + } + + public MutableVector2l y(final double a) { + return this.y(GenericMath.floorl(a)); + } + + public MutableVector2l y(final long a) { + this.y = a; + return this; + } + + public MutableVector2l set(final MutableVector2l v) { + return this.set(v.x, v.y); + } + + public MutableVector2l set(final Vector2l v) { + return this.set(v.x(), v.y()); + } + + public MutableVector2l set(final double x, final double y) { + return this.set(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public MutableVector2l set(final long x, final long y) { + this.x = x; + this.y = y; + return this; + } + + public MutableVector2l add(final MutableVector2l v) { + return this.add(v.x, v.y); + } + + public MutableVector2l add(final Vector2l v) { + return this.add(v.x(), v.y()); + } + + public MutableVector2l add(final double x, final double y) { + return this.add(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public MutableVector2l add(final long x, final long y) { + this.x += x; + this.y += y; + return this; + } + + public MutableVector2l sub(final MutableVector2l v) { + return this.sub(v.x, v.y); + } + + public MutableVector2l sub(final Vector2l v) { + return this.sub(v.x(), v.y()); + } + + public MutableVector2l sub(final double x, final double y) { + return this.sub(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public MutableVector2l sub(final long x, final long y) { + this.x -= x; + this.y -= y; + return this; + } + + public MutableVector2l mul(final double a) { + return this.mul(GenericMath.floorl(a)); + } + + @Override + public MutableVector2l mul(final long a) { + return this.mul(a, a); + } + + public MutableVector2l mul(final MutableVector2l v) { + return this.mul(v.x, v.y); + } + + public MutableVector2l mul(final Vector2l v) { + return this.mul(v.x(), v.y()); + } + + public MutableVector2l mul(final double x, final double y) { + return this.mul(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public MutableVector2l mul(final long x, final long y) { + this.x *= x; + this.y *= y; + return this; + } + + public MutableVector2l div(final double a) { + return this.div(GenericMath.floorl(a)); + } + + @Override + public MutableVector2l div(final long a) { + return this.div(a, a); + } + + public MutableVector2l div(final MutableVector2l v) { + return this.div(v.x, v.y); + } + + public MutableVector2l div(final Vector2l v) { + return this.div(v.x(), v.y()); + } + + public MutableVector2l div(final double x, final double y) { + return this.div(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public MutableVector2l div(final long x, final long y) { + this.x /= x; + this.y /= y; + return this; + } + + public long dot(final MutableVector2l v) { + return this.dot(v.x, v.y); + } + + public long dot(final Vector2l v) { + return this.dot(v.x(), v.y()); + } + + public long dot(final double x, final double y) { + return this.dot(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public long dot(final long x, final long y) { + return this.x * x + this.y * y; + } + + public MutableVector2l project(final MutableVector2l v) { + return this.project(v.x, v.y); + } + + public MutableVector2l project(final Vector2l v) { + return this.project(v.x(), v.y()); + } + + public MutableVector2l project(final double x, final double y) { + return this.project(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public MutableVector2l project(final long x, final long y) { + final long lengthSquared = x * x + y * y; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final float a = (float) this.dot(x, y) / lengthSquared; + return this.set(a * x, a * y); + } + + public MutableVector2l pow(final double pow) { + return this.pow(GenericMath.floorl(pow)); + } + + @Override + public MutableVector2l pow(final long pow) { + return this.pow(pow, pow); + } + + public MutableVector2l pow(final MutableVector2l v) { + return this.pow(v.x, v.y); + } + + public MutableVector2l pow(final Vector2l v) { + return this.pow(v.x(), v.y()); + } + + public MutableVector2l pow(final double x, final double y) { + return this.pow(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public MutableVector2l pow(final long x, final long y) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y)); + } + + @Override + public MutableVector2l abs() { + return this.set(Math.abs(this.x), Math.abs(this.y)); + } + + @Override + public MutableVector2l negate() { + return this.set(-this.x, -this.y); + } + + public MutableVector2l min(final MutableVector2l v) { + return this.min(v.x, v.y); + } + + public MutableVector2l min(final Vector2l v) { + return this.min(v.x(), v.y()); + } + + public MutableVector2l min(final double x, final double y) { + return this.min(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public MutableVector2l min(final long x, final long y) { + return this.set(Math.min(this.x, x), Math.min(this.y, y)); + } + + public MutableVector2l max(final MutableVector2l v) { + return this.max(v.x, v.y); + } + + public MutableVector2l max(final Vector2l v) { + return this.max(v.x(), v.y()); + } + + public MutableVector2l max(final double x, final double y) { + return this.max(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public MutableVector2l max(final long x, final long y) { + return this.set(Math.max(this.x, x), Math.max(this.y, y)); + } + + public long distanceSquared(final MutableVector2l v) { + return this.distanceSquared(v.x, v.y); + } + + public long distanceSquared(final Vector2l v) { + return this.distanceSquared(v.x(), v.y()); + } + + public long distanceSquared(final double x, final double y) { + return this.distanceSquared(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public long distanceSquared(final long x, final long y) { + final long dx = this.x - x; + final long dy = this.y - y; + return dx * dx + dy * dy; + } + + public float distance(final MutableVector2l v) { + return this.distance(v.x, v.y); + } + + public float distance(final Vector2l v) { + return this.distance(v.x(), v.y()); + } + + public float distance(final double x, final double y) { + return this.distance(GenericMath.floorl(x), GenericMath.floorl(y)); + } + + public float distance(final long x, final long y) { + return (float) Math.sqrt(this.distanceSquared(x, y)); + } + + @Override + public long lengthSquared() { + return this.x * this.x + this.y * this.y; + } + + @Override + public double length() { + return Math.sqrt(this.lengthSquared()); + } + + @Override + public int minAxis() { + return this.x < this.y ? 0 : 1; + } + + @Override + public int maxAxis() { + return this.x > this.y ? 0 : 1; + } + + @Override + public long[] toArray() { + return new long[]{this.x, this.y}; + } + + @Override + public Vector2i toInt() { + return new Vector2i(this.x, this.y); + } + + @Override + public Vector2l toLong() { + return new Vector2l(this.x, this.y); + } + + @Override + public Vector2f toFloat() { + return new Vector2f(this.x, this.y); + } + + @Override + public Vector2d toDouble() { + return new Vector2d((double) this.x, (double) this.y); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector2l that)) { + return false; + } else { + return that.x == this.x + && that.y == this.y; + } + } + + @Override + public int hashCode() { + return Long.hashCode(this.x) * 31 + Long.hashCode(this.y); + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ")"; + } + + public static MutableVector2l zero() { + return MutableVector2l.of(0, 0); + } + + public static MutableVector2l unitX() { + return MutableVector2l.of(1, 0); + } + + public static MutableVector2l unitY() { + return MutableVector2l.of(0, 1); + } + + public static MutableVector2l one() { + return MutableVector2l.of(1, 1); + } + + public static MutableVector2l from(final double n) { + return MutableVector2l.from(GenericMath.floorl(n)); + } + + public static MutableVector2l from(final long n) { + return MutableVector2l.of(n, n); + } + + public static MutableVector2l from(final MutableVector2l v) { + return MutableVector2l.of(v.x, v.y); + } + + public static MutableVector2l from(final Vector2l v) { + return MutableVector2l.of(v.x(), v.y()); + } + + public static MutableVector2l of(final double x, final double y) { + return new MutableVector2l(x, y); + } + + public static MutableVector2l of(final long x, final long y) { + return new MutableVector2l(x, y); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3d.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3d.java new file mode 100644 index 0000000..88aedc5 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3d.java @@ -0,0 +1,411 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.math.vector.Vector3f; +import org.spongepowered.math.vector.Vector3i; +import org.spongepowered.math.vector.Vector3l; +import org.spongepowered.math.vector.Vectord; + +public final class MutableVector3d implements Vectord { + + private double x; + private double y; + private double z; + + public MutableVector3d(final double x, final double y, final double z) { + this.x = x; + this.y = y; + this.z = z; + } + + public double x() { + return this.x; + } + + public double y() { + return this.y; + } + + public double z() { + return this.z; + } + + public MutableVector3d copy() { + return MutableVector3d.from(this); + } + + public MutableVector3d x(final MutableVector3d v) { + return this.x(v.x); + } + + public MutableVector3d x(final Vector3d v) { + return this.x(v.x()); + } + + public MutableVector3d x(final double a) { + this.x = a; + return this; + } + + public MutableVector3d y(final MutableVector3d v) { + return this.y(v.y); + } + + public MutableVector3d y(final Vector3d v) { + return this.y(v.y()); + } + + public MutableVector3d y(final double a) { + this.y = a; + return this; + } + + public MutableVector3d z(final MutableVector3d v) { + return this.z(v.z); + } + + public MutableVector3d z(final Vector3d v) { + return this.z(v.z()); + } + + public MutableVector3d z(final double a) { + this.z = a; + return this; + } + + public MutableVector3d set(final MutableVector3d v) { + return this.set(v.x, v.y, v.z); + } + + public MutableVector3d set(final Vector3d v) { + return this.set(v.x(), v.y(), v.z()); + } + + public MutableVector3d set(final double x, final double y, final double z) { + this.x = x; + this.y = y; + this.z = z; + return this; + } + + public MutableVector3d add(final MutableVector3d v) { + return this.add(v.x, v.y, v.z); + } + + public MutableVector3d add(final Vector3d v) { + return this.add(v.x(), v.y(), v.z()); + } + + public MutableVector3d add(final double x, final double y, final double z) { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + public MutableVector3d sub(final MutableVector3d v) { + return this.sub(v.x, v.y, v.z); + } + + public MutableVector3d sub(final Vector3d v) { + return this.sub(v.x(), v.y(), v.z()); + } + + public MutableVector3d sub(final double x, final double y, final double z) { + this.x -= x; + this.y -= y; + this.z -= z; + return this; + } + + @Override + public MutableVector3d mul(final double a) { + return this.mul(a, a, a); + } + + public MutableVector3d mul(final MutableVector3d v) { + return this.mul(v.x, v.y, v.z); + } + + public MutableVector3d mul(final Vector3d v) { + return this.mul(v.x(), v.y(), v.z()); + } + + public MutableVector3d mul(final double x, final double y, final double z) { + this.x *= x; + this.y *= y; + this.z *= z; + return this; + } + + @Override + public MutableVector3d div(final double a) { + return this.div(a, a, a); + } + + public MutableVector3d div(final MutableVector3d v) { + return this.div(v.x, v.y, v.z); + } + + public MutableVector3d div(final Vector3d v) { + return this.div(v.x(), v.y(), v.z()); + } + + public MutableVector3d div(final double x, final double y, final double z) { + this.x /= x; + this.y /= y; + this.z /= z; + return this; + } + + public double dot(final MutableVector3d v) { + return this.dot(v.x, v.y, v.z); + } + + public double dot(final Vector3d v) { + return this.dot(v.x(), v.y(), v.z()); + } + + public double dot(final double x, final double y, final double z) { + return this.x * x + this.y * y + this.z * z; + } + + public MutableVector3d project(final MutableVector3d v) { + return this.project(v.x, v.y, v.z); + } + + public MutableVector3d project(final Vector3d v) { + return this.project(v.x(), v.y(), v.z()); + } + + public MutableVector3d project(final double x, final double y, final double z) { + final double lengthSquared = x * x + y * y + z * z; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final double a = this.dot(x, y, z) / lengthSquared; + return this.set(a * x, a * y, a * z); + } + + public MutableVector3d cross(final MutableVector3d v) { + return this.cross(v.x, v.y, v.z); + } + + public MutableVector3d cross(final Vector3d v) { + return this.cross(v.x(), v.y(), v.z()); + } + + public MutableVector3d cross(final double x, final double y, final double z) { + return this.set(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x); + } + + @Override + public MutableVector3d pow(final double pow) { + return this.pow(pow, pow, pow); + } + + public MutableVector3d pow(final MutableVector3d v) { + return this.pow(v.x, v.y, v.z); + } + + public MutableVector3d pow(final Vector3d v) { + return this.pow(v.x(), v.y(), v.z()); + } + + public MutableVector3d pow(final double x, final double y, final double z) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y), Math.pow(this.z, z)); + } + + @Override + public MutableVector3d ceil() { + return this.set(Math.ceil(this.x), Math.ceil(this.y), Math.ceil(this.z)); + } + + @Override + public MutableVector3d floor() { + return this.set(GenericMath.floor(this.x), GenericMath.floor(this.y), GenericMath.floor(this.z)); + } + + @Override + public MutableVector3d round() { + return this.set(Math.round(this.x), Math.round(this.y), Math.round(this.z)); + } + + @Override + public MutableVector3d abs() { + return this.set(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z)); + } + + @Override + public MutableVector3d negate() { + return this.set(-this.x, -this.y, -this.z); + } + + public MutableVector3d min(final MutableVector3d v) { + return this.min(v.x, v.y, v.z); + } + + public MutableVector3d min(final Vector3d v) { + return this.min(v.x(), v.y(), v.z()); + } + + public MutableVector3d min(final double x, final double y, final double z) { + return this.set(Math.min(this.x, x), Math.min(this.y, y), Math.min(this.z, z)); + } + + public MutableVector3d max(final MutableVector3d v) { + return this.max(v.x, v.y, v.z); + } + + public MutableVector3d max(final Vector3d v) { + return this.max(v.x(), v.y(), v.z()); + } + + public MutableVector3d max(final double x, final double y, final double z) { + return this.set(Math.max(this.x, x), Math.max(this.y, y), Math.max(this.z, z)); + } + + public double distanceSquared(final MutableVector3d v) { + return this.distanceSquared(v.x, v.y, v.z); + } + + public double distanceSquared(final Vector3d v) { + return this.distanceSquared(v.x(), v.y(), v.z()); + } + + public double distanceSquared(final double x, final double y, final double z) { + final double dx = this.x - x; + final double dy = this.y - y; + final double dz = this.z - z; + return dx * dx + dy * dy + dz * dz; + } + + public double distance(final MutableVector3d v) { + return this.distance(v.x, v.y, v.z); + } + + public double distance(final Vector3d v) { + return this.distance(v.x(), v.y(), v.z()); + } + + public double distance(final double x, final double y, final double z) { + return Math.sqrt(this.distanceSquared(x, y, z)); + } + + @Override + public double lengthSquared() { + return this.x * this.x + this.y * this.y + this.z * this.z; + } + + @Override + public double length() { + return Math.sqrt(this.lengthSquared()); + } + + @Override + public MutableVector3d normalize() { + final double length = this.length(); + if (Math.abs(length) < GenericMath.FLT_EPSILON) { + throw new ArithmeticException("Cannot normalize the zero vector"); + } + return this.set(this.x / length, this.y / length, this.z / length); + } + + @Override + public int minAxis() { + return this.x < this.y ? (this.x < this.z ? 0 : 2) : (this.y < this.z ? 1 : 2); + } + + @Override + public int maxAxis() { + return this.x < this.y ? (this.y < this.z ? 2 : 1) : (this.x < this.z ? 2 : 0); + } + + @Override + public double[] toArray() { + return new double[]{this.x, this.y, this.z}; + } + + @Override + public Vector3i toInt() { + return new Vector3i(this.x, this.y, this.z); + } + + @Override + public Vector3l toLong() { + return new Vector3l(this.x, this.y, this.z); + } + + @Override + public Vector3f toFloat() { + return new Vector3f(this.x, this.y, this.z); + } + + @Override + public Vector3d toDouble() { + return new Vector3d((double) this.x, (double) this.y, (double) this.z); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector3d that)) { + return false; + } else { + return Double.compare(that.x, this.x) == 0 + && Double.compare(that.y, this.y) == 0 + && Double.compare(that.z, this.z) == 0; + } + } + + @Override + public int hashCode() { + int result = Double.hashCode(this.x); + result = result * 31 + Double.hashCode(this.y); + result = result * 31 + Double.hashCode(this.z); + return result; + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ")"; + } + + public static MutableVector3d zero() { + return MutableVector3d.of(0, 0, 0); + } + + public static MutableVector3d unitX() { + return MutableVector3d.of(1, 0, 0); + } + + public static MutableVector3d unitY() { + return MutableVector3d.of(0, 1, 0); + } + + public static MutableVector3d unitZ() { + return MutableVector3d.of(0, 0, 1); + } + + public static MutableVector3d one() { + return MutableVector3d.of(1, 1, 1); + } + + public static MutableVector3d from(final double n) { + return MutableVector3d.of(n, n, n); + } + + public static MutableVector3d from(final MutableVector3d v) { + return MutableVector3d.of(v.x, v.y, v.z); + } + + public static MutableVector3d from(final Vector3d v) { + return MutableVector3d.of(v.x(), v.y(), v.z()); + } + + public static MutableVector3d of(final double x, final double y, final double z) { + return new MutableVector3d(x, y, z); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3f.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3f.java new file mode 100644 index 0000000..3ba8ac0 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3f.java @@ -0,0 +1,499 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.math.vector.Vector3f; +import org.spongepowered.math.vector.Vector3i; +import org.spongepowered.math.vector.Vector3l; +import org.spongepowered.math.vector.Vectorf; + +public final class MutableVector3f implements Vectorf { + + private float x; + private float y; + private float z; + + public MutableVector3f(final double x, final double y, final double z) { + this((float) x, (float) y, (float) z); + } + + public MutableVector3f(final float x, final float y, final float z) { + this.x = x; + this.y = y; + this.z = z; + } + + public float x() { + return this.x; + } + + public float y() { + return this.y; + } + + public float z() { + return this.z; + } + + public MutableVector3f copy() { + return MutableVector3f.from(this); + } + + public MutableVector3f x(final MutableVector3f v) { + return this.x(v.x); + } + + public MutableVector3f x(final Vector3f v) { + return this.x(v.x()); + } + + public MutableVector3f x(final double a) { + return this.x((float) a); + } + + public MutableVector3f x(final float a) { + this.x = a; + return this; + } + + public MutableVector3f y(final MutableVector3f v) { + return this.y(v.y); + } + + public MutableVector3f y(final Vector3f v) { + return this.y(v.y()); + } + + public MutableVector3f y(final double a) { + return this.y((float) a); + } + + public MutableVector3f y(final float a) { + this.y = a; + return this; + } + + public MutableVector3f z(final MutableVector3f v) { + return this.z(v.z); + } + + public MutableVector3f z(final Vector3f v) { + return this.z(v.z()); + } + + public MutableVector3f z(final double a) { + return this.z((float) a); + } + + public MutableVector3f z(final float a) { + this.z = a; + return this; + } + + public MutableVector3f set(final MutableVector3f v) { + return this.set(v.x, v.y, v.z); + } + + public MutableVector3f set(final Vector3f v) { + return this.set(v.x(), v.y(), v.z()); + } + + public MutableVector3f set(final double x, final double y, final double z) { + return this.set((float) x, (float) y, (float) z); + } + + public MutableVector3f set(final float x, final float y, final float z) { + this.x = x; + this.y = y; + this.z = z; + return this; + } + + public MutableVector3f add(final MutableVector3f v) { + return this.add(v.x, v.y, v.z); + } + + public MutableVector3f add(final Vector3f v) { + return this.add(v.x(), v.y(), v.z()); + } + + public MutableVector3f add(final double x, final double y, final double z) { + return this.add((float) x, (float) y, (float) z); + } + + public MutableVector3f add(final float x, final float y, final float z) { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + public MutableVector3f sub(final MutableVector3f v) { + return this.sub(v.x, v.y, v.z); + } + + public MutableVector3f sub(final Vector3f v) { + return this.sub(v.x(), v.y(), v.z()); + } + + public MutableVector3f sub(final double x, final double y, final double z) { + return this.sub((float) x, (float) y, (float) z); + } + + public MutableVector3f sub(final float x, final float y, final float z) { + this.x -= x; + this.y -= y; + this.z -= z; + return this; + } + + public MutableVector3f mul(final double a) { + return this.mul((float) a); + } + + @Override + public MutableVector3f mul(final float a) { + return this.mul(a, a, a); + } + + public MutableVector3f mul(final MutableVector3f v) { + return this.mul(v.x, v.y, v.z); + } + + public MutableVector3f mul(final Vector3f v) { + return this.mul(v.x(), v.y(), v.z()); + } + + public MutableVector3f mul(final double x, final double y, final double z) { + return this.mul((float) x, (float) y, (float) z); + } + + public MutableVector3f mul(final float x, final float y, final float z) { + this.x *= x; + this.y *= y; + this.z *= z; + return this; + } + + public MutableVector3f div(final double a) { + return this.div((float) a); + } + + @Override + public MutableVector3f div(final float a) { + return this.div(a, a, a); + } + + public MutableVector3f div(final MutableVector3f v) { + return this.div(v.x, v.y, v.z); + } + + public MutableVector3f div(final Vector3f v) { + return this.div(v.x(), v.y(), v.z()); + } + + public MutableVector3f div(final double x, final double y, final double z) { + return this.div((float) x, (float) y, (float) z); + } + + public MutableVector3f div(final float x, final float y, final float z) { + this.x /= x; + this.y /= y; + this.z /= z; + return this; + } + + public float dot(final MutableVector3f v) { + return this.dot(v.x, v.y, v.z); + } + + public float dot(final Vector3f v) { + return this.dot(v.x(), v.y(), v.z()); + } + + public float dot(final double x, final double y, final double z) { + return this.dot((float) x, (float) y, (float) z); + } + + public float dot(final float x, final float y, final float z) { + return this.x * x + this.y * y + this.z * z; + } + + public MutableVector3f project(final MutableVector3f v) { + return this.project(v.x, v.y, v.z); + } + + public MutableVector3f project(final Vector3f v) { + return this.project(v.x(), v.y(), v.z()); + } + + public MutableVector3f project(final double x, final double y, final double z) { + return this.project((float) x, (float) y, (float) z); + } + + public MutableVector3f project(final float x, final float y, final float z) { + final float lengthSquared = x * x + y * y + z * z; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final float a = this.dot(x, y, z) / lengthSquared; + return this.set(a * x, a * y, a * z); + } + + public MutableVector3f cross(final MutableVector3f v) { + return this.cross(v.x, v.y, v.z); + } + + public MutableVector3f cross(final Vector3f v) { + return this.cross(v.x(), v.y(), v.z()); + } + + public MutableVector3f cross(final double x, final double y, final double z) { + return this.cross((float) x, (float) y, (float) z); + } + + public MutableVector3f cross(final float x, final float y, final float z) { + return this.set(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x); + } + + public MutableVector3f pow(final double pow) { + return this.pow((float) pow); + } + + @Override + public MutableVector3f pow(final float pow) { + return this.pow(pow, pow, pow); + } + + public MutableVector3f pow(final MutableVector3f v) { + return this.pow(v.x, v.y, v.z); + } + + public MutableVector3f pow(final Vector3f v) { + return this.pow(v.x(), v.y(), v.z()); + } + + public MutableVector3f pow(final double x, final double y, final double z) { + return this.pow((float) x, (float) y, (float) z); + } + + public MutableVector3f pow(final float x, final float y, final float z) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y), Math.pow(this.z, z)); + } + + @Override + public MutableVector3f ceil() { + return this.set(Math.ceil(this.x), Math.ceil(this.y), Math.ceil(this.z)); + } + + @Override + public MutableVector3f floor() { + return this.set(GenericMath.floor(this.x), GenericMath.floor(this.y), GenericMath.floor(this.z)); + } + + @Override + public MutableVector3f round() { + return this.set(Math.round(this.x), Math.round(this.y), Math.round(this.z)); + } + + @Override + public MutableVector3f abs() { + return this.set(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z)); + } + + @Override + public MutableVector3f negate() { + return this.set(-this.x, -this.y, -this.z); + } + + public MutableVector3f min(final MutableVector3f v) { + return this.min(v.x, v.y, v.z); + } + + public MutableVector3f min(final Vector3f v) { + return this.min(v.x(), v.y(), v.z()); + } + + public MutableVector3f min(final double x, final double y, final double z) { + return this.min((float) x, (float) y, (float) z); + } + + public MutableVector3f min(final float x, final float y, final float z) { + return this.set(Math.min(this.x, x), Math.min(this.y, y), Math.min(this.z, z)); + } + + public MutableVector3f max(final MutableVector3f v) { + return this.max(v.x, v.y, v.z); + } + + public MutableVector3f max(final Vector3f v) { + return this.max(v.x(), v.y(), v.z()); + } + + public MutableVector3f max(final double x, final double y, final double z) { + return this.max((float) x, (float) y, (float) z); + } + + public MutableVector3f max(final float x, final float y, final float z) { + return this.set(Math.max(this.x, x), Math.max(this.y, y), Math.max(this.z, z)); + } + + public float distanceSquared(final MutableVector3f v) { + return this.distanceSquared(v.x, v.y, v.z); + } + + public float distanceSquared(final Vector3f v) { + return this.distanceSquared(v.x(), v.y(), v.z()); + } + + public float distanceSquared(final double x, final double y, final double z) { + return this.distanceSquared((float) x, (float) y, (float) z); + } + + public float distanceSquared(final float x, final float y, final float z) { + final float dx = this.x - x; + final float dy = this.y - y; + final float dz = this.z - z; + return dx * dx + dy * dy + dz * dz; + } + + public float distance(final MutableVector3f v) { + return this.distance(v.x, v.y, v.z); + } + + public float distance(final Vector3f v) { + return this.distance(v.x(), v.y(), v.z()); + } + + public float distance(final double x, final double y, final double z) { + return this.distance((float) x, (float) y, (float) z); + } + + public float distance(final float x, final float y, final float z) { + return (float) Math.sqrt(this.distanceSquared(x, y, z)); + } + + @Override + public float lengthSquared() { + return this.x * this.x + this.y * this.y + this.z * this.z; + } + + @Override + public float length() { + return (float) Math.sqrt(this.lengthSquared()); + } + + @Override + public MutableVector3f normalize() { + final float length = this.length(); + if (Math.abs(length) < GenericMath.FLT_EPSILON) { + throw new ArithmeticException("Cannot normalize the zero vector"); + } + return this.set(this.x / length, this.y / length, this.z / length); + } + + @Override + public int minAxis() { + return this.x < this.y ? (this.x < this.z ? 0 : 2) : (this.y < this.z ? 1 : 2); + } + + @Override + public int maxAxis() { + return this.x < this.y ? (this.y < this.z ? 2 : 1) : (this.x < this.z ? 2 : 0); + } + + @Override + public float[] toArray() { + return new float[]{this.x, this.y, this.z}; + } + + @Override + public Vector3i toInt() { + return new Vector3i(this.x, this.y, this.z); + } + + @Override + public Vector3l toLong() { + return new Vector3l(this.x, this.y, this.z); + } + + @Override + public Vector3f toFloat() { + return new Vector3f(this.x, this.y, this.z); + } + + @Override + public Vector3d toDouble() { + return new Vector3d((double) this.x, (double) this.y, (double) this.z); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector3f that)) { + return false; + } else { + return Float.compare(that.x, this.x) == 0 + && Float.compare(that.y, this.y) == 0 + && Float.compare(that.z, this.z) == 0; + } + } + + @Override + public int hashCode() { + int result = Float.hashCode(this.x); + result = result * 31 + Float.hashCode(this.y); + result = result * 31 + Float.hashCode(this.z); + return result; + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ")"; + } + + public static MutableVector3f zero() { + return MutableVector3f.of(0, 0, 0); + } + + public static MutableVector3f unitX() { + return MutableVector3f.of(1, 0, 0); + } + + public static MutableVector3f unitY() { + return MutableVector3f.of(0, 1, 0); + } + + public static MutableVector3f unitZ() { + return MutableVector3f.of(0, 0, 1); + } + + public static MutableVector3f one() { + return MutableVector3f.of(1, 1, 1); + } + + public static MutableVector3f from(final double n) { + return MutableVector3f.from((float) n); + } + + public static MutableVector3f from(final float n) { + return MutableVector3f.of(n, n, n); + } + + public static MutableVector3f from(final MutableVector3f v) { + return MutableVector3f.of(v.x, v.y, v.z); + } + + public static MutableVector3f from(final Vector3f v) { + return MutableVector3f.of(v.x(), v.y(), v.z()); + } + + public static MutableVector3f of(final double x, final double y, final double z) { + return new MutableVector3f(x, y, z); + } + + public static MutableVector3f of(final float x, final float y, final float z) { + return new MutableVector3f(x, y, z); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3i.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3i.java new file mode 100644 index 0000000..7055b1c --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3i.java @@ -0,0 +1,475 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.math.vector.Vector3f; +import org.spongepowered.math.vector.Vector3i; +import org.spongepowered.math.vector.Vector3l; +import org.spongepowered.math.vector.Vectori; + +public final class MutableVector3i implements Vectori { + + private int x; + private int y; + private int z; + + public MutableVector3i(final double x, final double y, final double z) { + this(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public MutableVector3i(final int x, final int y, final int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int x() { + return this.x; + } + + public int y() { + return this.y; + } + + public int z() { + return this.z; + } + + public MutableVector3i copy() { + return MutableVector3i.from(this); + } + + public MutableVector3i x(final MutableVector3i v) { + return this.x(v.x); + } + + public MutableVector3i x(final Vector3i v) { + return this.x(v.x()); + } + + public MutableVector3i x(final double a) { + return this.x(GenericMath.floor(a)); + } + + public MutableVector3i x(final int a) { + this.x = a; + return this; + } + + public MutableVector3i y(final MutableVector3i v) { + return this.y(v.y); + } + + public MutableVector3i y(final Vector3i v) { + return this.y(v.y()); + } + + public MutableVector3i y(final double a) { + return this.y(GenericMath.floor(a)); + } + + public MutableVector3i y(final int a) { + this.y = a; + return this; + } + + public MutableVector3i z(final MutableVector3i v) { + return this.z(v.z); + } + + public MutableVector3i z(final Vector3i v) { + return this.z(v.z()); + } + + public MutableVector3i z(final double a) { + return this.z(GenericMath.floor(a)); + } + + public MutableVector3i z(final int a) { + this.z = a; + return this; + } + + public MutableVector3i set(final MutableVector3i v) { + return this.set(v.x, v.y, v.z); + } + + public MutableVector3i set(final Vector3i v) { + return this.set(v.x(), v.y(), v.z()); + } + + public MutableVector3i set(final double x, final double y, final double z) { + return this.set(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public MutableVector3i set(final int x, final int y, final int z) { + this.x = x; + this.y = y; + this.z = z; + return this; + } + + public MutableVector3i add(final MutableVector3i v) { + return this.add(v.x, v.y, v.z); + } + + public MutableVector3i add(final Vector3i v) { + return this.add(v.x(), v.y(), v.z()); + } + + public MutableVector3i add(final double x, final double y, final double z) { + return this.add(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public MutableVector3i add(final int x, final int y, final int z) { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + public MutableVector3i sub(final MutableVector3i v) { + return this.sub(v.x, v.y, v.z); + } + + public MutableVector3i sub(final Vector3i v) { + return this.sub(v.x(), v.y(), v.z()); + } + + public MutableVector3i sub(final double x, final double y, final double z) { + return this.sub(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public MutableVector3i sub(final int x, final int y, final int z) { + this.x -= x; + this.y -= y; + this.z -= z; + return this; + } + + public MutableVector3i mul(final double a) { + return this.mul(GenericMath.floor(a)); + } + + @Override + public MutableVector3i mul(final int a) { + return this.mul(a, a, a); + } + + public MutableVector3i mul(final MutableVector3i v) { + return this.mul(v.x, v.y, v.z); + } + + public MutableVector3i mul(final Vector3i v) { + return this.mul(v.x(), v.y(), v.z()); + } + + public MutableVector3i mul(final double x, final double y, final double z) { + return this.mul(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public MutableVector3i mul(final int x, final int y, final int z) { + this.x *= x; + this.y *= y; + this.z *= z; + return this; + } + + public MutableVector3i div(final double a) { + return this.div(GenericMath.floor(a)); + } + + @Override + public MutableVector3i div(final int a) { + return this.div(a, a, a); + } + + public MutableVector3i div(final MutableVector3i v) { + return this.div(v.x, v.y, v.z); + } + + public MutableVector3i div(final Vector3i v) { + return this.div(v.x(), v.y(), v.z()); + } + + public MutableVector3i div(final double x, final double y, final double z) { + return this.div(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public MutableVector3i div(final int x, final int y, final int z) { + this.x /= x; + this.y /= y; + this.z /= z; + return this; + } + + public int dot(final MutableVector3i v) { + return this.dot(v.x, v.y, v.z); + } + + public int dot(final Vector3i v) { + return this.dot(v.x(), v.y(), v.z()); + } + + public int dot(final double x, final double y, final double z) { + return this.dot(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public int dot(final int x, final int y, final int z) { + return this.x * x + this.y * y + this.z * z; + } + + public MutableVector3i project(final MutableVector3i v) { + return this.project(v.x, v.y, v.z); + } + + public MutableVector3i project(final Vector3i v) { + return this.project(v.x(), v.y(), v.z()); + } + + public MutableVector3i project(final double x, final double y, final double z) { + return this.project(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public MutableVector3i project(final int x, final int y, final int z) { + final int lengthSquared = x * x + y * y + z * z; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final float a = (float) this.dot(x, y, z) / lengthSquared; + return this.set(a * x, a * y, a * z); + } + + public MutableVector3i cross(final MutableVector3i v) { + return this.cross(v.x, v.y, v.z); + } + + public MutableVector3i cross(final Vector3i v) { + return this.cross(v.x(), v.y(), v.z()); + } + + public MutableVector3i cross(final double x, final double y, final double z) { + return this.cross(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public MutableVector3i cross(final int x, final int y, final int z) { + return this.set(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x); + } + + public MutableVector3i pow(final double pow) { + return this.pow(GenericMath.floor(pow)); + } + + @Override + public MutableVector3i pow(final int pow) { + return this.pow(pow, pow, pow); + } + + public MutableVector3i pow(final MutableVector3i v) { + return this.pow(v.x, v.y, v.z); + } + + public MutableVector3i pow(final Vector3i v) { + return this.pow(v.x(), v.y(), v.z()); + } + + public MutableVector3i pow(final double x, final double y, final double z) { + return this.pow(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public MutableVector3i pow(final int x, final int y, final int z) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y), Math.pow(this.z, z)); + } + + @Override + public MutableVector3i abs() { + return this.set(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z)); + } + + @Override + public MutableVector3i negate() { + return this.set(-this.x, -this.y, -this.z); + } + + public MutableVector3i min(final MutableVector3i v) { + return this.min(v.x, v.y, v.z); + } + + public MutableVector3i min(final Vector3i v) { + return this.min(v.x(), v.y(), v.z()); + } + + public MutableVector3i min(final double x, final double y, final double z) { + return this.min(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public MutableVector3i min(final int x, final int y, final int z) { + return this.set(Math.min(this.x, x), Math.min(this.y, y), Math.min(this.z, z)); + } + + public MutableVector3i max(final MutableVector3i v) { + return this.max(v.x, v.y, v.z); + } + + public MutableVector3i max(final Vector3i v) { + return this.max(v.x(), v.y(), v.z()); + } + + public MutableVector3i max(final double x, final double y, final double z) { + return this.max(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public MutableVector3i max(final int x, final int y, final int z) { + return this.set(Math.max(this.x, x), Math.max(this.y, y), Math.max(this.z, z)); + } + + public int distanceSquared(final MutableVector3i v) { + return this.distanceSquared(v.x, v.y, v.z); + } + + public int distanceSquared(final Vector3i v) { + return this.distanceSquared(v.x(), v.y(), v.z()); + } + + public int distanceSquared(final double x, final double y, final double z) { + return this.distanceSquared(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public int distanceSquared(final int x, final int y, final int z) { + final int dx = this.x - x; + final int dy = this.y - y; + final int dz = this.z - z; + return dx * dx + dy * dy + dz * dz; + } + + public float distance(final MutableVector3i v) { + return this.distance(v.x, v.y, v.z); + } + + public float distance(final Vector3i v) { + return this.distance(v.x(), v.y(), v.z()); + } + + public float distance(final double x, final double y, final double z) { + return this.distance(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + public float distance(final int x, final int y, final int z) { + return (float) Math.sqrt(this.distanceSquared(x, y, z)); + } + + @Override + public int lengthSquared() { + return this.x * this.x + this.y * this.y + this.z * this.z; + } + + @Override + public float length() { + return (float) Math.sqrt(this.lengthSquared()); + } + + @Override + public int minAxis() { + return this.x < this.y ? (this.x < this.z ? 0 : 2) : (this.y < this.z ? 1 : 2); + } + + @Override + public int maxAxis() { + return this.x < this.y ? (this.y < this.z ? 2 : 1) : (this.x < this.z ? 2 : 0); + } + + @Override + public int[] toArray() { + return new int[]{this.x, this.y, this.z}; + } + + @Override + public Vector3i toInt() { + return new Vector3i(this.x, this.y, this.z); + } + + @Override + public Vector3l toLong() { + return new Vector3l(this.x, this.y, this.z); + } + + @Override + public Vector3f toFloat() { + return new Vector3f(this.x, this.y, this.z); + } + + @Override + public Vector3d toDouble() { + return new Vector3d((double) this.x, (double) this.y, (double) this.z); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector3i that)) { + return false; + } else { + return that.x == this.x + && that.y == this.y + && that.z == this.z; + } + } + + @Override + public int hashCode() { + int result = Integer.hashCode(this.x); + result = result * 31 + Integer.hashCode(this.y); + result = result * 31 + Integer.hashCode(this.z); + return result; + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ")"; + } + + public static MutableVector3i zero() { + return MutableVector3i.of(0, 0, 0); + } + + public static MutableVector3i unitX() { + return MutableVector3i.of(1, 0, 0); + } + + public static MutableVector3i unitY() { + return MutableVector3i.of(0, 1, 0); + } + + public static MutableVector3i unitZ() { + return MutableVector3i.of(0, 0, 1); + } + + public static MutableVector3i one() { + return MutableVector3i.of(1, 1, 1); + } + + public static MutableVector3i from(final double n) { + return MutableVector3i.from(GenericMath.floor(n)); + } + + public static MutableVector3i from(final int n) { + return MutableVector3i.of(n, n, n); + } + + public static MutableVector3i from(final MutableVector3i v) { + return MutableVector3i.of(v.x, v.y, v.z); + } + + public static MutableVector3i from(final Vector3i v) { + return MutableVector3i.of(v.x(), v.y(), v.z()); + } + + public static MutableVector3i of(final double x, final double y, final double z) { + return new MutableVector3i(x, y, z); + } + + public static MutableVector3i of(final int x, final int y, final int z) { + return new MutableVector3i(x, y, z); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3l.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3l.java new file mode 100644 index 0000000..4e50792 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3l.java @@ -0,0 +1,475 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.math.vector.Vector3f; +import org.spongepowered.math.vector.Vector3i; +import org.spongepowered.math.vector.Vector3l; +import org.spongepowered.math.vector.Vectorl; + +public final class MutableVector3l implements Vectorl { + + private long x; + private long y; + private long z; + + public MutableVector3l(final double x, final double y, final double z) { + this(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public MutableVector3l(final long x, final long y, final long z) { + this.x = x; + this.y = y; + this.z = z; + } + + public long x() { + return this.x; + } + + public long y() { + return this.y; + } + + public long z() { + return this.z; + } + + public MutableVector3l copy() { + return MutableVector3l.from(this); + } + + public MutableVector3l x(final MutableVector3l v) { + return this.x(v.x); + } + + public MutableVector3l x(final Vector3l v) { + return this.x(v.x()); + } + + public MutableVector3l x(final double a) { + return this.x(GenericMath.floorl(a)); + } + + public MutableVector3l x(final long a) { + this.x = a; + return this; + } + + public MutableVector3l y(final MutableVector3l v) { + return this.y(v.y); + } + + public MutableVector3l y(final Vector3l v) { + return this.y(v.y()); + } + + public MutableVector3l y(final double a) { + return this.y(GenericMath.floorl(a)); + } + + public MutableVector3l y(final long a) { + this.y = a; + return this; + } + + public MutableVector3l z(final MutableVector3l v) { + return this.z(v.z); + } + + public MutableVector3l z(final Vector3l v) { + return this.z(v.z()); + } + + public MutableVector3l z(final double a) { + return this.z(GenericMath.floorl(a)); + } + + public MutableVector3l z(final long a) { + this.z = a; + return this; + } + + public MutableVector3l set(final MutableVector3l v) { + return this.set(v.x, v.y, v.z); + } + + public MutableVector3l set(final Vector3l v) { + return this.set(v.x(), v.y(), v.z()); + } + + public MutableVector3l set(final double x, final double y, final double z) { + return this.set(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public MutableVector3l set(final long x, final long y, final long z) { + this.x = x; + this.y = y; + this.z = z; + return this; + } + + public MutableVector3l add(final MutableVector3l v) { + return this.add(v.x, v.y, v.z); + } + + public MutableVector3l add(final Vector3l v) { + return this.add(v.x(), v.y(), v.z()); + } + + public MutableVector3l add(final double x, final double y, final double z) { + return this.add(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public MutableVector3l add(final long x, final long y, final long z) { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + public MutableVector3l sub(final MutableVector3l v) { + return this.sub(v.x, v.y, v.z); + } + + public MutableVector3l sub(final Vector3l v) { + return this.sub(v.x(), v.y(), v.z()); + } + + public MutableVector3l sub(final double x, final double y, final double z) { + return this.sub(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public MutableVector3l sub(final long x, final long y, final long z) { + this.x -= x; + this.y -= y; + this.z -= z; + return this; + } + + public MutableVector3l mul(final double a) { + return this.mul(GenericMath.floorl(a)); + } + + @Override + public MutableVector3l mul(final long a) { + return this.mul(a, a, a); + } + + public MutableVector3l mul(final MutableVector3l v) { + return this.mul(v.x, v.y, v.z); + } + + public MutableVector3l mul(final Vector3l v) { + return this.mul(v.x(), v.y(), v.z()); + } + + public MutableVector3l mul(final double x, final double y, final double z) { + return this.mul(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public MutableVector3l mul(final long x, final long y, final long z) { + this.x *= x; + this.y *= y; + this.z *= z; + return this; + } + + public MutableVector3l div(final double a) { + return this.div(GenericMath.floorl(a)); + } + + @Override + public MutableVector3l div(final long a) { + return this.div(a, a, a); + } + + public MutableVector3l div(final MutableVector3l v) { + return this.div(v.x, v.y, v.z); + } + + public MutableVector3l div(final Vector3l v) { + return this.div(v.x(), v.y(), v.z()); + } + + public MutableVector3l div(final double x, final double y, final double z) { + return this.div(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public MutableVector3l div(final long x, final long y, final long z) { + this.x /= x; + this.y /= y; + this.z /= z; + return this; + } + + public long dot(final MutableVector3l v) { + return this.dot(v.x, v.y, v.z); + } + + public long dot(final Vector3l v) { + return this.dot(v.x(), v.y(), v.z()); + } + + public long dot(final double x, final double y, final double z) { + return this.dot(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public long dot(final long x, final long y, final long z) { + return this.x * x + this.y * y + this.z * z; + } + + public MutableVector3l project(final MutableVector3l v) { + return this.project(v.x, v.y, v.z); + } + + public MutableVector3l project(final Vector3l v) { + return this.project(v.x(), v.y(), v.z()); + } + + public MutableVector3l project(final double x, final double y, final double z) { + return this.project(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public MutableVector3l project(final long x, final long y, final long z) { + final long lengthSquared = x * x + y * y + z * z; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final double a = (double) this.dot(x, y, z) / lengthSquared; + return this.set(a * x, a * y, a * z); + } + + public MutableVector3l cross(final MutableVector3l v) { + return this.cross(v.x, v.y, v.z); + } + + public MutableVector3l cross(final Vector3l v) { + return this.cross(v.x(), v.y(), v.z()); + } + + public MutableVector3l cross(final double x, final double y, final double z) { + return this.cross(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public MutableVector3l cross(final long x, final long y, final long z) { + return this.set(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x); + } + + public MutableVector3l pow(final double pow) { + return this.pow(GenericMath.floorl(pow)); + } + + @Override + public MutableVector3l pow(final long pow) { + return this.pow(pow, pow, pow); + } + + public MutableVector3l pow(final MutableVector3l v) { + return this.pow(v.x, v.y, v.z); + } + + public MutableVector3l pow(final Vector3l v) { + return this.pow(v.x(), v.y(), v.z()); + } + + public MutableVector3l pow(final double x, final double y, final double z) { + return this.pow(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public MutableVector3l pow(final long x, final long y, final long z) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y), Math.pow(this.z, z)); + } + + @Override + public MutableVector3l abs() { + return this.set(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z)); + } + + @Override + public MutableVector3l negate() { + return this.set(-this.x, -this.y, -this.z); + } + + public MutableVector3l min(final MutableVector3l v) { + return this.min(v.x, v.y, v.z); + } + + public MutableVector3l min(final Vector3l v) { + return this.min(v.x(), v.y(), v.z()); + } + + public MutableVector3l min(final double x, final double y, final double z) { + return this.min(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public MutableVector3l min(final long x, final long y, final long z) { + return this.set(Math.min(this.x, x), Math.min(this.y, y), Math.min(this.z, z)); + } + + public MutableVector3l max(final MutableVector3l v) { + return this.max(v.x, v.y, v.z); + } + + public MutableVector3l max(final Vector3l v) { + return this.max(v.x(), v.y(), v.z()); + } + + public MutableVector3l max(final double x, final double y, final double z) { + return this.max(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public MutableVector3l max(final long x, final long y, final long z) { + return this.set(Math.max(this.x, x), Math.max(this.y, y), Math.max(this.z, z)); + } + + public long distanceSquared(final MutableVector3l v) { + return this.distanceSquared(v.x, v.y, v.z); + } + + public long distanceSquared(final Vector3l v) { + return this.distanceSquared(v.x(), v.y(), v.z()); + } + + public long distanceSquared(final double x, final double y, final double z) { + return this.distanceSquared(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public long distanceSquared(final long x, final long y, final long z) { + final long dx = this.x - x; + final long dy = this.y - y; + final long dz = this.z - z; + return dx * dx + dy * dy + dz * dz; + } + + public double distance(final MutableVector3l v) { + return this.distance(v.x, v.y, v.z); + } + + public double distance(final Vector3l v) { + return this.distance(v.x(), v.y(), v.z()); + } + + public double distance(final double x, final double y, final double z) { + return this.distance(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z)); + } + + public double distance(final long x, final long y, final long z) { + return Math.sqrt(this.distanceSquared(x, y, z)); + } + + @Override + public long lengthSquared() { + return this.x * this.x + this.y * this.y + this.z * this.z; + } + + @Override + public double length() { + return Math.sqrt(this.lengthSquared()); + } + + @Override + public int minAxis() { + return this.x < this.y ? (this.x < this.z ? 0 : 2) : (this.y < this.z ? 1 : 2); + } + + @Override + public int maxAxis() { + return this.x < this.y ? (this.y < this.z ? 2 : 1) : (this.x < this.z ? 2 : 0); + } + + @Override + public long[] toArray() { + return new long[]{this.x, this.y, this.z}; + } + + @Override + public Vector3i toInt() { + return new Vector3i(this.x, this.y, this.z); + } + + @Override + public Vector3l toLong() { + return new Vector3l(this.x, this.y, this.z); + } + + @Override + public Vector3f toFloat() { + return new Vector3f(this.x, this.y, this.z); + } + + @Override + public Vector3d toDouble() { + return new Vector3d((double) this.x, (double) this.y, (double) this.z); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector3l that)) { + return false; + } else { + return that.x == this.x + && that.y == this.y + && that.z == this.z; + } + } + + @Override + public int hashCode() { + int result = Long.hashCode(this.x); + result = result * 31 + Long.hashCode(this.y); + result = result * 31 + Long.hashCode(this.z); + return result; + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ")"; + } + + public static MutableVector3l zero() { + return MutableVector3l.of(0, 0, 0); + } + + public static MutableVector3l unitX() { + return MutableVector3l.of(1, 0, 0); + } + + public static MutableVector3l unitY() { + return MutableVector3l.of(0, 1, 0); + } + + public static MutableVector3l unitZ() { + return MutableVector3l.of(0, 0, 1); + } + + public static MutableVector3l one() { + return MutableVector3l.of(1, 1, 1); + } + + public static MutableVector3l from(final double n) { + return MutableVector3l.from(GenericMath.floorl(n)); + } + + public static MutableVector3l from(final long n) { + return MutableVector3l.of(n, n, n); + } + + public static MutableVector3l from(final MutableVector3l v) { + return MutableVector3l.of(v.x, v.y, v.z); + } + + public static MutableVector3l from(final Vector3l v) { + return MutableVector3l.of(v.x(), v.y(), v.z()); + } + + public static MutableVector3l of(final double x, final double y, final double z) { + return new MutableVector3l(x, y, z); + } + + public static MutableVector3l of(final long x, final long y, final long z) { + return new MutableVector3l(x, y, z); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4d.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4d.java new file mode 100644 index 0000000..e265741 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4d.java @@ -0,0 +1,456 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector4d; +import org.spongepowered.math.vector.Vector4f; +import org.spongepowered.math.vector.Vector4i; +import org.spongepowered.math.vector.Vector4l; +import org.spongepowered.math.vector.Vectord; + +public final class MutableVector4d implements Vectord { + + private double x; + private double y; + private double z; + private double w; + + public MutableVector4d(final double x, final double y, final double z, final double w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public double x() { + return this.x; + } + + public double y() { + return this.y; + } + + public double z() { + return this.z; + } + + public double w() { + return this.w; + } + + public MutableVector4d copy() { + return MutableVector4d.from(this); + } + + public MutableVector4d x(final MutableVector4d v) { + return this.x(v.x); + } + + public MutableVector4d x(final Vector4d v) { + return this.x(v.x()); + } + + public MutableVector4d x(final double a) { + this.x = a; + return this; + } + + public MutableVector4d y(final MutableVector4d v) { + return this.y(v.y); + } + + public MutableVector4d y(final Vector4d v) { + return this.y(v.y()); + } + + public MutableVector4d y(final double a) { + this.y = a; + return this; + } + + public MutableVector4d z(final MutableVector4d v) { + return this.z(v.z); + } + + public MutableVector4d z(final Vector4d v) { + return this.z(v.z()); + } + + public MutableVector4d z(final double a) { + this.z = a; + return this; + } + + public MutableVector4d w(final MutableVector4d v) { + return this.w(v.z); + } + + public MutableVector4d w(final Vector4d v) { + return this.w(v.z()); + } + + public MutableVector4d w(final double a) { + this.w = a; + return this; + } + + public MutableVector4d set(final MutableVector4d v) { + return this.set(v.x, v.y, v.z, v.w); + } + + public MutableVector4d set(final Vector4d v) { + return this.set(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4d set(final double x, final double y, final double z, final double w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + return this; + } + + public MutableVector4d add(final MutableVector4d v) { + return this.add(v.x, v.y, v.z, v.w); + } + + public MutableVector4d add(final Vector4d v) { + return this.add(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4d add(final double x, final double y, final double z, final double w) { + this.x += x; + this.y += y; + this.z += z; + this.w += w; + return this; + } + + public MutableVector4d sub(final MutableVector4d v) { + return this.sub(v.x, v.y, v.z, v.w); + } + + public MutableVector4d sub(final Vector4d v) { + return this.sub(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4d sub(final double x, final double y, final double z, final double w) { + this.x -= x; + this.y -= y; + this.z -= z; + this.w -= w; + return this; + } + + @Override + public MutableVector4d mul(final double a) { + return this.mul(a, a, a, a); + } + + public MutableVector4d mul(final MutableVector4d v) { + return this.mul(v.x, v.y, v.z, v.w); + } + + public MutableVector4d mul(final Vector4d v) { + return this.mul(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4d mul(final double x, final double y, final double z, final double w) { + this.x *= x; + this.y *= y; + this.z *= z; + this.w *= w; + return this; + } + + @Override + public MutableVector4d div(final double a) { + return this.div(a, a, a, a); + } + + public MutableVector4d div(final MutableVector4d v) { + return this.div(v.x, v.y, v.z, v.w); + } + + public MutableVector4d div(final Vector4d v) { + return this.div(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4d div(final double x, final double y, final double z, final double w) { + this.x /= x; + this.y /= y; + this.z /= z; + this.w /= w; + return this; + } + + public double dot(final MutableVector4d v) { + return this.dot(v.x, v.y, v.z, v.w); + } + + public double dot(final Vector4d v) { + return this.dot(v.x(), v.y(), v.z(), v.w()); + } + + public double dot(final double x, final double y, final double z, final double w) { + return this.x * x + this.y * y + this.z * z + this.w * w; + } + + public MutableVector4d project(final MutableVector4d v) { + return this.project(v.x, v.y, v.z, v.w); + } + + public MutableVector4d project(final Vector4d v) { + return this.project(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4d project(final double x, final double y, final double z, final double w) { + final double lengthSquared = x * x + y * y + z * z + w * w; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final double a = this.dot(x, y, z, w) / lengthSquared; + return this.set(a * x, a * y, a * z, a * w); + } + + @Override + public MutableVector4d pow(final double pow) { + return this.pow(pow, pow, pow, pow); + } + + public MutableVector4d pow(final MutableVector4d v) { + return this.pow(v.x, v.y, v.z, v.w); + } + + public MutableVector4d pow(final Vector4d v) { + return this.pow(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4d pow(final double x, final double y, final double z, final double w) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y), Math.pow(this.z, z), Math.pow(this.w, w)); + } + + @Override + public MutableVector4d ceil() { + return this.set(Math.ceil(this.x), Math.ceil(this.y), Math.ceil(this.z), Math.ceil(this.w)); + } + + @Override + public MutableVector4d floor() { + return this.set(GenericMath.floor(this.x), GenericMath.floor(this.y), GenericMath.floor(this.z), GenericMath.floor(this.w)); + } + + @Override + public MutableVector4d round() { + return this.set(Math.round(this.x), Math.round(this.y), Math.round(this.z), Math.round(this.w)); + } + + @Override + public MutableVector4d abs() { + return this.set(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z), Math.abs(this.w)); + } + + @Override + public MutableVector4d negate() { + return this.set(-this.x, -this.y, -this.z, -this.w); + } + + public MutableVector4d min(final MutableVector4d v) { + return this.min(v.x, v.y, v.z, v.w); + } + + public MutableVector4d min(final Vector4d v) { + return this.min(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4d min(final double x, final double y, final double z, final double w) { + return this.set(Math.min(this.x, x), Math.min(this.y, y), Math.min(this.z, z), Math.min(this.w, w)); + } + + public MutableVector4d max(final MutableVector4d v) { + return this.max(v.x, v.y, v.z, v.w); + } + + public MutableVector4d max(final Vector4d v) { + return this.max(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4d max(final double x, final double y, final double z, final double w) { + return this.set(Math.max(this.x, x), Math.max(this.y, y), Math.max(this.z, z), Math.max(this.w, w)); + } + + public double distanceSquared(final MutableVector4d v) { + return this.distanceSquared(v.x, v.y, v.z, v.w); + } + + public double distanceSquared(final Vector4d v) { + return this.distanceSquared(v.x(), v.y(), v.z(), v.w()); + } + + public double distanceSquared(final double x, final double y, final double z, final double w) { + final double dx = this.x - x; + final double dy = this.y - y; + final double dz = this.z - z; + final double dw = this.w - w; + return dx * dx + dy * dy + dz * dz + dw * dw; + } + + public double distance(final MutableVector4d v) { + return this.distance(v.x, v.y, v.z, v.w); + } + + public double distance(final Vector4d v) { + return this.distance(v.x(), v.y(), v.z(), v.w()); + } + + public double distance(final double x, final double y, final double z, final double w) { + return Math.sqrt(this.distanceSquared(x, y, z, w)); + } + + @Override + public double lengthSquared() { + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + } + + @Override + public double length() { + return Math.sqrt(this.lengthSquared()); + } + + @Override + public MutableVector4d normalize() { + final double length = this.length(); + if (Math.abs(length) < GenericMath.FLT_EPSILON) { + throw new ArithmeticException("Cannot normalize the zero vector"); + } + return this.set(this.x / length, this.y / length, this.z / length, this.w / length); + } + + @Override + public int minAxis() { + double value = this.x; + int axis = 0; + if (this.y < value) { + value = this.y; + axis = 1; + } + if (this.z < value) { + value = this.z; + axis = 2; + } + if (this.w < value) { + axis = 3; + } + return axis; + } + + @Override + public int maxAxis() { + double value = this.x; + int axis = 0; + if (this.y > value) { + value = this.y; + axis = 1; + } + if (this.z > value) { + value = this.z; + axis = 2; + } + if (this.w > value) { + axis = 3; + } + return axis; + } + + @Override + public double[] toArray() { + return new double[]{this.x, this.y, this.z, this.w}; + } + + @Override + public Vector4i toInt() { + return new Vector4i(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4l toLong() { + return new Vector4l(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4f toFloat() { + return new Vector4f(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4d toDouble() { + return new Vector4d((double) this.x, (double) this.y, (double) this.z, (double) this.w); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector4d that)) { + return false; + } else { + return Double.compare(that.x, this.x) == 0 + && Double.compare(that.y, this.y) == 0 + && Double.compare(that.z, this.z) == 0 + && Double.compare(that.w, this.w) == 0; + } + } + + @Override + public int hashCode() { + int result = Double.hashCode(this.x); + result = result * 31 + Double.hashCode(this.y); + result = result * 31 + Double.hashCode(this.z); + result = result * 31 + Double.hashCode(this.w); + return result; + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ", " + this.w + ")"; + } + + public static MutableVector4d zero() { + return MutableVector4d.of(0, 0, 0, 0); + } + + public static MutableVector4d unitX() { + return MutableVector4d.of(1, 0, 0, 0); + } + + public static MutableVector4d unitY() { + return MutableVector4d.of(0, 1, 0, 0); + } + + public static MutableVector4d unitZ() { + return MutableVector4d.of(0, 0, 1, 0); + } + + public static MutableVector4d unitW() { + return MutableVector4d.of(0, 0, 0, 1); + } + + public static MutableVector4d one() { + return MutableVector4d.of(1, 1, 1, 1); + } + + public static MutableVector4d from(final double n) { + return MutableVector4d.of(n, n, n, n); + } + + public static MutableVector4d from(final MutableVector4d v) { + return MutableVector4d.of(v.x, v.y, v.z, v.w); + } + + public static MutableVector4d from(final Vector4d v) { + return MutableVector4d.of(v.x(), v.y(), v.z(), v.w()); + } + + public static MutableVector4d of(final double x, final double y, final double z, final double w) { + return new MutableVector4d(x, y, z, w); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4f.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4f.java new file mode 100644 index 0000000..799e088 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4f.java @@ -0,0 +1,544 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector4d; +import org.spongepowered.math.vector.Vector4f; +import org.spongepowered.math.vector.Vector4i; +import org.spongepowered.math.vector.Vector4l; +import org.spongepowered.math.vector.Vectorf; + +public final class MutableVector4f implements Vectorf { + + private float x; + private float y; + private float z; + private float w; + + public MutableVector4f(final double x, final double y, final double z, final double w) { + this((float) x, (float) y, (float) z, (float) w); + } + + public MutableVector4f(final float x, final float y, final float z, final float w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public float x() { + return this.x; + } + + public float y() { + return this.y; + } + + public float z() { + return this.z; + } + + public float w() { + return this.w; + } + + public MutableVector4f copy() { + return MutableVector4f.from(this); + } + + public MutableVector4f x(final MutableVector4f v) { + return this.x(v.x); + } + + public MutableVector4f x(final Vector4f v) { + return this.x(v.x()); + } + + public MutableVector4f x(final double a) { + return this.x((float) a); + } + + public MutableVector4f x(final float a) { + this.x = a; + return this; + } + + public MutableVector4f y(final MutableVector4f v) { + return this.y(v.y); + } + + public MutableVector4f y(final Vector4f v) { + return this.y(v.y()); + } + + public MutableVector4f y(final double a) { + return this.y((float) a); + } + + public MutableVector4f y(final float a) { + this.y = a; + return this; + } + + public MutableVector4f z(final MutableVector4f v) { + return this.z(v.z); + } + + public MutableVector4f z(final Vector4f v) { + return this.z(v.z()); + } + + public MutableVector4f z(final double a) { + return this.z((float) a); + } + + public MutableVector4f z(final float a) { + this.z = a; + return this; + } + + public MutableVector4f w(final MutableVector4f v) { + return this.w(v.z); + } + + public MutableVector4f w(final Vector4f v) { + return this.w(v.z()); + } + + public MutableVector4f w(final double a) { + return this.w((float) a); + } + + public MutableVector4f w(final float a) { + this.w = a; + return this; + } + + public MutableVector4f set(final MutableVector4f v) { + return this.set(v.x, v.y, v.z, v.w); + } + + public MutableVector4f set(final Vector4f v) { + return this.set(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4f set(final double x, final double y, final double z, final double w) { + return this.set((float) x, (float) y, (float) z, (float) w); + } + + public MutableVector4f set(final float x, final float y, final float z, final float w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + return this; + } + + public MutableVector4f add(final MutableVector4f v) { + return this.add(v.x, v.y, v.z, v.w); + } + + public MutableVector4f add(final Vector4f v) { + return this.add(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4f add(final double x, final double y, final double z, final double w) { + return this.add((float) x, (float) y, (float) z, (float) w); + } + + public MutableVector4f add(final float x, final float y, final float z, final float w) { + this.x += x; + this.y += y; + this.z += z; + this.w += w; + return this; + } + + public MutableVector4f sub(final MutableVector4f v) { + return this.sub(v.x, v.y, v.z, v.w); + } + + public MutableVector4f sub(final Vector4f v) { + return this.sub(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4f sub(final double x, final double y, final double z, final double w) { + return this.sub((float) x, (float) y, (float) z, (float) w); + } + + public MutableVector4f sub(final float x, final float y, final float z, final float w) { + this.x -= x; + this.y -= y; + this.z -= z; + this.w -= w; + return this; + } + + public MutableVector4f mul(final double a) { + return this.mul((float) a); + } + + @Override + public MutableVector4f mul(final float a) { + return this.mul(a, a, a, a); + } + + public MutableVector4f mul(final MutableVector4f v) { + return this.mul(v.x, v.y, v.z, v.w); + } + + public MutableVector4f mul(final Vector4f v) { + return this.mul(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4f mul(final double x, final double y, final double z, final double w) { + return this.mul((float) x, (float) y, (float) z, (float) w); + } + + public MutableVector4f mul(final float x, final float y, final float z, final float w) { + this.x *= x; + this.y *= y; + this.z *= z; + this.w *= w; + return this; + } + + public MutableVector4f div(final double a) { + return this.div((float) a); + } + + @Override + public MutableVector4f div(final float a) { + return this.div(a, a, a, a); + } + + public MutableVector4f div(final MutableVector4f v) { + return this.div(v.x, v.y, v.z, v.w); + } + + public MutableVector4f div(final Vector4f v) { + return this.div(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4f div(final double x, final double y, final double z, final double w) { + return this.div((float) x, (float) y, (float) z, (float) w); + } + + public MutableVector4f div(final float x, final float y, final float z, final float w) { + this.x /= x; + this.y /= y; + this.z /= z; + this.w /= w; + return this; + } + + public float dot(final MutableVector4f v) { + return this.dot(v.x, v.y, v.z, v.w); + } + + public float dot(final Vector4f v) { + return this.dot(v.x(), v.y(), v.z(), v.w()); + } + + public float dot(final double x, final double y, final double z, final double w) { + return this.dot((float) x, (float) y, (float) z, (float) w); + } + + public float dot(final float x, final float y, final float z, final float w) { + return this.x * x + this.y * y + this.z * z + this.w * w; + } + + public MutableVector4f project(final MutableVector4f v) { + return this.project(v.x, v.y, v.z, v.w); + } + + public MutableVector4f project(final Vector4f v) { + return this.project(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4f project(final double x, final double y, final double z, final double w) { + return this.project((float) x, (float) y, (float) z, (float) w); + } + + public MutableVector4f project(final float x, final float y, final float z, final float w) { + final float lengthSquared = x * x + y * y + z * z + w * w; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final float a = this.dot(x, y, z, w) / lengthSquared; + return this.set(a * x, a * y, a * z, a * w); + } + + public MutableVector4f pow(final double pow) { + return this.pow((float) pow); + } + + @Override + public MutableVector4f pow(final float pow) { + return this.pow(pow, pow, pow, pow); + } + + public MutableVector4f pow(final MutableVector4f v) { + return this.pow(v.x, v.y, v.z, v.w); + } + + public MutableVector4f pow(final Vector4f v) { + return this.pow(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4f pow(final double x, final double y, final double z, final double w) { + return this.pow((float) x, (float) y, (float) z, (float) w); + } + + public MutableVector4f pow(final float x, final float y, final float z, final float w) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y), Math.pow(this.z, z), Math.pow(this.w, w)); + } + + @Override + public MutableVector4f ceil() { + return this.set(Math.ceil(this.x), Math.ceil(this.y), Math.ceil(this.z), Math.ceil(this.w)); + } + + @Override + public MutableVector4f floor() { + return this.set(GenericMath.floor(this.x), GenericMath.floor(this.y), GenericMath.floor(this.z), GenericMath.floor(this.w)); + } + + @Override + public MutableVector4f round() { + return this.set(Math.round(this.x), Math.round(this.y), Math.round(this.z), Math.round(this.w)); + } + + @Override + public MutableVector4f abs() { + return this.set(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z), Math.abs(this.w)); + } + + @Override + public MutableVector4f negate() { + return this.set(-this.x, -this.y, -this.z, -this.w); + } + + public MutableVector4f min(final MutableVector4f v) { + return this.min(v.x, v.y, v.z, v.w); + } + + public MutableVector4f min(final Vector4f v) { + return this.min(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4f min(final double x, final double y, final double z, final double w) { + return this.min((float) x, (float) y, (float) z, (float) w); + } + + public MutableVector4f min(final float x, final float y, final float z, final float w) { + return this.set(Math.min(this.x, x), Math.min(this.y, y), Math.min(this.z, z), Math.min(this.w, w)); + } + + public MutableVector4f max(final MutableVector4f v) { + return this.max(v.x, v.y, v.z, v.w); + } + + public MutableVector4f max(final Vector4f v) { + return this.max(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4f max(final double x, final double y, final double z, final double w) { + return this.max((float) x, (float) y, (float) z, (float) w); + } + + public MutableVector4f max(final float x, final float y, final float z, final float w) { + return this.set(Math.max(this.x, x), Math.max(this.y, y), Math.max(this.z, z), Math.max(this.w, w)); + } + + public float distanceSquared(final MutableVector4f v) { + return this.distanceSquared(v.x, v.y, v.z, v.w); + } + + public float distanceSquared(final Vector4f v) { + return this.distanceSquared(v.x(), v.y(), v.z(), v.w()); + } + + public float distanceSquared(final double x, final double y, final double z, final double w) { + return this.distanceSquared((float) x, (float) y, (float) z, (float) w); + } + + public float distanceSquared(final float x, final float y, final float z, final float w) { + final float dx = this.x - x; + final float dy = this.y - y; + final float dz = this.z - z; + final float dw = this.w - w; + return dx * dx + dy * dy + dz * dz + dw * dw; + } + + public float distance(final MutableVector4f v) { + return this.distance(v.x, v.y, v.z, v.w); + } + + public float distance(final Vector4f v) { + return this.distance(v.x(), v.y(), v.z(), v.w()); + } + + public float distance(final double x, final double y, final double z, final double w) { + return this.distance((float) x, (float) y, (float) z, (float) w); + } + + public float distance(final float x, final float y, final float z, final float w) { + return (float) Math.sqrt(this.distanceSquared(x, y, z, w)); + } + + @Override + public float lengthSquared() { + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + } + + @Override + public float length() { + return (float) Math.sqrt(this.lengthSquared()); + } + + @Override + public MutableVector4f normalize() { + final float length = this.length(); + if (Math.abs(length) < GenericMath.FLT_EPSILON) { + throw new ArithmeticException("Cannot normalize the zero vector"); + } + return this.set(this.x / length, this.y / length, this.z / length, this.w / length); + } + + @Override + public int minAxis() { + float value = this.x; + int axis = 0; + if (this.y < value) { + value = this.y; + axis = 1; + } + if (this.z < value) { + value = this.z; + axis = 2; + } + if (this.w < value) { + axis = 3; + } + return axis; + } + + @Override + public int maxAxis() { + float value = this.x; + int axis = 0; + if (this.y > value) { + value = this.y; + axis = 1; + } + if (this.z > value) { + value = this.z; + axis = 2; + } + if (this.w > value) { + axis = 3; + } + return axis; + } + + @Override + public float[] toArray() { + return new float[]{this.x, this.y, this.z, this.w}; + } + + @Override + public Vector4i toInt() { + return new Vector4i(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4l toLong() { + return new Vector4l(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4f toFloat() { + return new Vector4f(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4d toDouble() { + return new Vector4d((double) this.x, (double) this.y, (double) this.z, (double) this.w); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector4f that)) { + return false; + } else { + return Float.compare(that.x, this.x) == 0 + && Float.compare(that.y, this.y) == 0 + && Float.compare(that.z, this.z) == 0 + && Float.compare(that.w, this.w) == 0; + } + } + + @Override + public int hashCode() { + int result = Float.hashCode(this.x); + result = result * 31 + Float.hashCode(this.y); + result = result * 31 + Float.hashCode(this.z); + result = result * 31 + Float.hashCode(this.w); + return result; + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ", " + this.w + ")"; + } + + public static MutableVector4f zero() { + return MutableVector4f.of(0, 0, 0, 0); + } + + public static MutableVector4f unitX() { + return MutableVector4f.of(1, 0, 0, 0); + } + + public static MutableVector4f unitY() { + return MutableVector4f.of(0, 1, 0, 0); + } + + public static MutableVector4f unitZ() { + return MutableVector4f.of(0, 0, 1, 0); + } + + public static MutableVector4f unitW() { + return MutableVector4f.of(0, 0, 0, 1); + } + + public static MutableVector4f one() { + return MutableVector4f.of(1, 1, 1, 1); + } + + public static MutableVector4f from(final double n) { + return MutableVector4f.from((float) n); + } + + public static MutableVector4f from(final float n) { + return MutableVector4f.of(n, n, n, n); + } + + public static MutableVector4f from(final MutableVector4f v) { + return MutableVector4f.of(v.x, v.y, v.z, v.w); + } + + public static MutableVector4f from(final Vector4f v) { + return MutableVector4f.of(v.x(), v.y(), v.z(), v.w()); + } + + public static MutableVector4f of(final double x, final double y, final double z, final double w) { + return new MutableVector4f(x, y, z, w); + } + + public static MutableVector4f of(final float x, final float y, final float z, final float w) { + return new MutableVector4f(x, y, z, w); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4i.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4i.java new file mode 100644 index 0000000..9b98f7a --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4i.java @@ -0,0 +1,520 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector4d; +import org.spongepowered.math.vector.Vector4f; +import org.spongepowered.math.vector.Vector4i; +import org.spongepowered.math.vector.Vector4l; +import org.spongepowered.math.vector.Vectori; + +public final class MutableVector4i implements Vectori { + + private int x; + private int y; + private int z; + private int w; + + public MutableVector4i(final double x, final double y, final double z, final double w) { + this(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public MutableVector4i(final int x, final int y, final int z, final int w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public int x() { + return this.x; + } + + public int y() { + return this.y; + } + + public int z() { + return this.z; + } + + public int w() { + return this.w; + } + + public MutableVector4i copy() { + return MutableVector4i.from(this); + } + + public MutableVector4i x(final MutableVector4i v) { + return this.x(v.x); + } + + public MutableVector4i x(final Vector4i v) { + return this.x(v.x()); + } + + public MutableVector4i x(final double a) { + return this.x(GenericMath.floor(a)); + } + + public MutableVector4i x(final int a) { + this.x = a; + return this; + } + + public MutableVector4i y(final MutableVector4i v) { + return this.y(v.y); + } + + public MutableVector4i y(final Vector4i v) { + return this.y(v.y()); + } + + public MutableVector4i y(final double a) { + return this.y(GenericMath.floor(a)); + } + + public MutableVector4i y(final int a) { + this.y = a; + return this; + } + + public MutableVector4i z(final MutableVector4i v) { + return this.z(v.z); + } + + public MutableVector4i z(final Vector4i v) { + return this.z(v.z()); + } + + public MutableVector4i z(final double a) { + return this.z(GenericMath.floor(a)); + } + + public MutableVector4i z(final int a) { + this.z = a; + return this; + } + + public MutableVector4i w(final MutableVector4i v) { + return this.w(v.z); + } + + public MutableVector4i w(final Vector4i v) { + return this.w(v.z()); + } + + public MutableVector4i w(final double a) { + return this.w(GenericMath.floor(a)); + } + + public MutableVector4i w(final int a) { + this.w = a; + return this; + } + + public MutableVector4i set(final MutableVector4i v) { + return this.set(v.x, v.y, v.z, v.w); + } + + public MutableVector4i set(final Vector4i v) { + return this.set(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4i set(final double x, final double y, final double z, final double w) { + return this.set(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public MutableVector4i set(final int x, final int y, final int z, final int w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + return this; + } + + public MutableVector4i add(final MutableVector4i v) { + return this.add(v.x, v.y, v.z, v.w); + } + + public MutableVector4i add(final Vector4i v) { + return this.add(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4i add(final double x, final double y, final double z, final double w) { + return this.add(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public MutableVector4i add(final int x, final int y, final int z, final int w) { + this.x += x; + this.y += y; + this.z += z; + this.w += w; + return this; + } + + public MutableVector4i sub(final MutableVector4i v) { + return this.sub(v.x, v.y, v.z, v.w); + } + + public MutableVector4i sub(final Vector4i v) { + return this.sub(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4i sub(final double x, final double y, final double z, final double w) { + return this.sub(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public MutableVector4i sub(final int x, final int y, final int z, final int w) { + this.x -= x; + this.y -= y; + this.z -= z; + this.w -= w; + return this; + } + + public MutableVector4i mul(final double a) { + return this.mul(GenericMath.floor(a)); + } + + @Override + public MutableVector4i mul(final int a) { + return this.mul(a, a, a, a); + } + + public MutableVector4i mul(final MutableVector4i v) { + return this.mul(v.x, v.y, v.z, v.w); + } + + public MutableVector4i mul(final Vector4i v) { + return this.mul(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4i mul(final double x, final double y, final double z, final double w) { + return this.mul(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public MutableVector4i mul(final int x, final int y, final int z, final int w) { + this.x *= x; + this.y *= y; + this.z *= z; + this.w *= w; + return this; + } + + public MutableVector4i div(final double a) { + return this.div(GenericMath.floor(a)); + } + + @Override + public MutableVector4i div(final int a) { + return this.div(a, a, a, a); + } + + public MutableVector4i div(final MutableVector4i v) { + return this.div(v.x, v.y, v.z, v.w); + } + + public MutableVector4i div(final Vector4i v) { + return this.div(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4i div(final double x, final double y, final double z, final double w) { + return this.div(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public MutableVector4i div(final int x, final int y, final int z, final int w) { + this.x /= x; + this.y /= y; + this.z /= z; + this.w /= w; + return this; + } + + public int dot(final MutableVector4i v) { + return this.dot(v.x, v.y, v.z, v.w); + } + + public int dot(final Vector4i v) { + return this.dot(v.x(), v.y(), v.z(), v.w()); + } + + public int dot(final double x, final double y, final double z, final double w) { + return this.dot(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public int dot(final int x, final int y, final int z, final int w) { + return this.x * x + this.y * y + this.z * z + this.w * w; + } + + public MutableVector4i project(final MutableVector4i v) { + return this.project(v.x, v.y, v.z, v.w); + } + + public MutableVector4i project(final Vector4i v) { + return this.project(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4i project(final double x, final double y, final double z, final double w) { + return this.project(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public MutableVector4i project(final int x, final int y, final int z, final int w) { + final int lengthSquared = x * x + y * y + z * z + w * w; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final float a = (float) this.dot(x, y, z, w) / lengthSquared; + return this.set(a * x, a * y, a * z, a * w); + } + + public MutableVector4i pow(final double pow) { + return this.pow(GenericMath.floor(pow)); + } + + @Override + public MutableVector4i pow(final int pow) { + return this.pow(pow, pow, pow, pow); + } + + public MutableVector4i pow(final MutableVector4i v) { + return this.pow(v.x, v.y, v.z, v.w); + } + + public MutableVector4i pow(final Vector4i v) { + return this.pow(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4i pow(final double x, final double y, final double z, final double w) { + return this.pow(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public MutableVector4i pow(final int x, final int y, final int z, final int w) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y), Math.pow(this.z, z), Math.pow(this.w, w)); + } + + @Override + public MutableVector4i abs() { + return this.set(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z), Math.abs(this.w)); + } + + @Override + public MutableVector4i negate() { + return this.set(-this.x, -this.y, -this.z, -this.w); + } + + public MutableVector4i min(final MutableVector4i v) { + return this.min(v.x, v.y, v.z, v.w); + } + + public MutableVector4i min(final Vector4i v) { + return this.min(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4i min(final double x, final double y, final double z, final double w) { + return this.min(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public MutableVector4i min(final int x, final int y, final int z, final int w) { + return this.set(Math.min(this.x, x), Math.min(this.y, y), Math.min(this.z, z), Math.min(this.w, w)); + } + + public MutableVector4i max(final MutableVector4i v) { + return this.max(v.x, v.y, v.z, v.w); + } + + public MutableVector4i max(final Vector4i v) { + return this.max(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4i max(final double x, final double y, final double z, final double w) { + return this.max(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public MutableVector4i max(final int x, final int y, final int z, final int w) { + return this.set(Math.max(this.x, x), Math.max(this.y, y), Math.max(this.z, z), Math.max(this.w, w)); + } + + public int distanceSquared(final MutableVector4i v) { + return this.distanceSquared(v.x, v.y, v.z, v.w); + } + + public int distanceSquared(final Vector4i v) { + return this.distanceSquared(v.x(), v.y(), v.z(), v.w()); + } + + public int distanceSquared(final double x, final double y, final double z, final double w) { + return this.distanceSquared(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public int distanceSquared(final int x, final int y, final int z, final int w) { + final int dx = this.x - x; + final int dy = this.y - y; + final int dz = this.z - z; + final int dw = this.w - w; + return dx * dx + dy * dy + dz * dz + dw * dw; + } + + public float distance(final MutableVector4i v) { + return this.distance(v.x, v.y, v.z, v.w); + } + + public float distance(final Vector4i v) { + return this.distance(v.x(), v.y(), v.z(), v.w()); + } + + public float distance(final double x, final double y, final double z, final double w) { + return this.distance(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z), GenericMath.floor(w)); + } + + public float distance(final int x, final int y, final int z, final int w) { + return (float) Math.sqrt(this.distanceSquared(x, y, z, w)); + } + + @Override + public int lengthSquared() { + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + } + + @Override + public float length() { + return (float) Math.sqrt(this.lengthSquared()); + } + + @Override + public int minAxis() { + int value = this.x; + int axis = 0; + if (this.y < value) { + value = this.y; + axis = 1; + } + if (this.z < value) { + value = this.z; + axis = 2; + } + if (this.w < value) { + axis = 3; + } + return axis; + } + + @Override + public int maxAxis() { + int value = this.x; + int axis = 0; + if (this.y > value) { + value = this.y; + axis = 1; + } + if (this.z > value) { + value = this.z; + axis = 2; + } + if (this.w > value) { + axis = 3; + } + return axis; + } + + @Override + public int[] toArray() { + return new int[]{this.x, this.y, this.z, this.w}; + } + + @Override + public Vector4i toInt() { + return new Vector4i(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4l toLong() { + return new Vector4l(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4f toFloat() { + return new Vector4f(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4d toDouble() { + return new Vector4d((double) this.x, (double) this.y, (double) this.z, (double) this.w); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector4i that)) { + return false; + } else { + return that.x == this.x + && that.y == this.y + && that.z == this.z + && that.w == this.w; + } + } + + @Override + public int hashCode() { + int result = Integer.hashCode(this.x); + result = result * 31 + Integer.hashCode(this.y); + result = result * 31 + Integer.hashCode(this.z); + result = result * 31 + Integer.hashCode(this.w); + return result; + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ", " + this.w + ")"; + } + + public static MutableVector4i zero() { + return MutableVector4i.of(0, 0, 0, 0); + } + + public static MutableVector4i unitX() { + return MutableVector4i.of(1, 0, 0, 0); + } + + public static MutableVector4i unitY() { + return MutableVector4i.of(0, 1, 0, 0); + } + + public static MutableVector4i unitZ() { + return MutableVector4i.of(0, 0, 1, 0); + } + + public static MutableVector4i unitW() { + return MutableVector4i.of(0, 0, 0, 1); + } + + public static MutableVector4i one() { + return MutableVector4i.of(1, 1, 1, 1); + } + + public static MutableVector4i from(final double n) { + return MutableVector4i.from(GenericMath.floor(n)); + } + + public static MutableVector4i from(final int n) { + return MutableVector4i.of(n, n, n, n); + } + + public static MutableVector4i from(final MutableVector4i v) { + return MutableVector4i.of(v.x, v.y, v.z, v.w); + } + + public static MutableVector4i from(final Vector4i v) { + return MutableVector4i.of(v.x(), v.y(), v.z(), v.w()); + } + + public static MutableVector4i of(final double x, final double y, final double z, final double w) { + return new MutableVector4i(x, y, z, w); + } + + public static MutableVector4i of(final int x, final int y, final int z, final int w) { + return new MutableVector4i(x, y, z, w); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4l.java b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4l.java new file mode 100644 index 0000000..24f9b91 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4l.java @@ -0,0 +1,520 @@ +package net.hellheim.spongetools.math.mutable.vector; + +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector4d; +import org.spongepowered.math.vector.Vector4f; +import org.spongepowered.math.vector.Vector4i; +import org.spongepowered.math.vector.Vector4l; +import org.spongepowered.math.vector.Vectorl; + +public final class MutableVector4l implements Vectorl { + + private long x; + private long y; + private long z; + private long w; + + public MutableVector4l(final double x, final double y, final double z, final double w) { + this(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public MutableVector4l(final long x, final long y, final long z, final long w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public long x() { + return this.x; + } + + public long y() { + return this.y; + } + + public long z() { + return this.z; + } + + public long w() { + return this.w; + } + + public MutableVector4l copy() { + return MutableVector4l.from(this); + } + + public MutableVector4l x(final MutableVector4l v) { + return this.x(v.x); + } + + public MutableVector4l x(final Vector4l v) { + return this.x(v.x()); + } + + public MutableVector4l x(final double a) { + return this.x(GenericMath.floorl(a)); + } + + public MutableVector4l x(final long a) { + this.x = a; + return this; + } + + public MutableVector4l y(final MutableVector4l v) { + return this.y(v.y); + } + + public MutableVector4l y(final Vector4l v) { + return this.y(v.y()); + } + + public MutableVector4l y(final double a) { + return this.y(GenericMath.floorl(a)); + } + + public MutableVector4l y(final long a) { + this.y = a; + return this; + } + + public MutableVector4l z(final MutableVector4l v) { + return this.z(v.z); + } + + public MutableVector4l z(final Vector4l v) { + return this.z(v.z()); + } + + public MutableVector4l z(final double a) { + return this.z(GenericMath.floorl(a)); + } + + public MutableVector4l z(final long a) { + this.z = a; + return this; + } + + public MutableVector4l w(final MutableVector4l v) { + return this.w(v.z); + } + + public MutableVector4l w(final Vector4l v) { + return this.w(v.z()); + } + + public MutableVector4l w(final double a) { + return this.w(GenericMath.floorl(a)); + } + + public MutableVector4l w(final long a) { + this.w = a; + return this; + } + + public MutableVector4l set(final MutableVector4l v) { + return this.set(v.x, v.y, v.z, v.w); + } + + public MutableVector4l set(final Vector4l v) { + return this.set(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4l set(final double x, final double y, final double z, final double w) { + return this.set(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public MutableVector4l set(final long x, final long y, final long z, final long w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + return this; + } + + public MutableVector4l add(final MutableVector4l v) { + return this.add(v.x, v.y, v.z, v.w); + } + + public MutableVector4l add(final Vector4l v) { + return this.add(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4l add(final double x, final double y, final double z, final double w) { + return this.add(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public MutableVector4l add(final long x, final long y, final long z, final long w) { + this.x += x; + this.y += y; + this.z += z; + this.w += w; + return this; + } + + public MutableVector4l sub(final MutableVector4l v) { + return this.sub(v.x, v.y, v.z, v.w); + } + + public MutableVector4l sub(final Vector4l v) { + return this.sub(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4l sub(final double x, final double y, final double z, final double w) { + return this.sub(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public MutableVector4l sub(final long x, final long y, final long z, final long w) { + this.x -= x; + this.y -= y; + this.z -= z; + this.w -= w; + return this; + } + + public MutableVector4l mul(final double a) { + return this.mul(GenericMath.floorl(a)); + } + + @Override + public MutableVector4l mul(final long a) { + return this.mul(a, a, a, a); + } + + public MutableVector4l mul(final MutableVector4l v) { + return this.mul(v.x, v.y, v.z, v.w); + } + + public MutableVector4l mul(final Vector4l v) { + return this.mul(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4l mul(final double x, final double y, final double z, final double w) { + return this.mul(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public MutableVector4l mul(final long x, final long y, final long z, final long w) { + this.x *= x; + this.y *= y; + this.z *= z; + this.w *= w; + return this; + } + + public MutableVector4l div(final double a) { + return this.div(GenericMath.floorl(a)); + } + + @Override + public MutableVector4l div(final long a) { + return this.div(a, a, a, a); + } + + public MutableVector4l div(final MutableVector4l v) { + return this.div(v.x, v.y, v.z, v.w); + } + + public MutableVector4l div(final Vector4l v) { + return this.div(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4l div(final double x, final double y, final double z, final double w) { + return this.div(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public MutableVector4l div(final long x, final long y, final long z, final long w) { + this.x /= x; + this.y /= y; + this.z /= z; + this.w /= w; + return this; + } + + public long dot(final MutableVector4l v) { + return this.dot(v.x, v.y, v.z, v.w); + } + + public long dot(final Vector4l v) { + return this.dot(v.x(), v.y(), v.z(), v.w()); + } + + public long dot(final double x, final double y, final double z, final double w) { + return this.dot(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public long dot(final long x, final long y, final long z, final long w) { + return this.x * x + this.y * y + this.z * z + this.w * w; + } + + public MutableVector4l project(final MutableVector4l v) { + return this.project(v.x, v.y, v.z, v.w); + } + + public MutableVector4l project(final Vector4l v) { + return this.project(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4l project(final double x, final double y, final double z, final double w) { + return this.project(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public MutableVector4l project(final long x, final long y, final long z, final long w) { + final long lengthSquared = x * x + y * y + z * z + w * w; + if (lengthSquared == 0) { + throw new ArithmeticException("Cannot project onto the zero vector"); + } + final double a = (double) this.dot(x, y, z, w) / lengthSquared; + return this.set(a * x, a * y, a * z, a * w); + } + + public MutableVector4l pow(final double pow) { + return this.pow(GenericMath.floorl(pow)); + } + + @Override + public MutableVector4l pow(final long pow) { + return this.pow(pow, pow, pow, pow); + } + + public MutableVector4l pow(final MutableVector4l v) { + return this.pow(v.x, v.y, v.z, v.w); + } + + public MutableVector4l pow(final Vector4l v) { + return this.pow(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4l pow(final double x, final double y, final double z, final double w) { + return this.pow(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public MutableVector4l pow(final long x, final long y, final long z, final long w) { + return this.set(Math.pow(this.x, x), Math.pow(this.y, y), Math.pow(this.z, z), Math.pow(this.w, w)); + } + + @Override + public MutableVector4l abs() { + return this.set(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z), Math.abs(this.w)); + } + + @Override + public MutableVector4l negate() { + return this.set(-this.x, -this.y, -this.z, -this.w); + } + + public MutableVector4l min(final MutableVector4l v) { + return this.min(v.x, v.y, v.z, v.w); + } + + public MutableVector4l min(final Vector4l v) { + return this.min(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4l min(final double x, final double y, final double z, final double w) { + return this.min(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public MutableVector4l min(final long x, final long y, final long z, final long w) { + return this.set(Math.min(this.x, x), Math.min(this.y, y), Math.min(this.z, z), Math.min(this.w, w)); + } + + public MutableVector4l max(final MutableVector4l v) { + return this.max(v.x, v.y, v.z, v.w); + } + + public MutableVector4l max(final Vector4l v) { + return this.max(v.x(), v.y(), v.z(), v.w()); + } + + public MutableVector4l max(final double x, final double y, final double z, final double w) { + return this.max(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public MutableVector4l max(final long x, final long y, final long z, final long w) { + return this.set(Math.max(this.x, x), Math.max(this.y, y), Math.max(this.z, z), Math.max(this.w, w)); + } + + public long distanceSquared(final MutableVector4l v) { + return this.distanceSquared(v.x, v.y, v.z, v.w); + } + + public long distanceSquared(final Vector4l v) { + return this.distanceSquared(v.x(), v.y(), v.z(), v.w()); + } + + public long distanceSquared(final double x, final double y, final double z, final double w) { + return this.distanceSquared(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public long distanceSquared(final long x, final long y, final long z, final long w) { + final long dx = this.x - x; + final long dy = this.y - y; + final long dz = this.z - z; + final long dw = this.w - w; + return dx * dx + dy * dy + dz * dz + dw * dw; + } + + public double distance(final MutableVector4l v) { + return this.distance(v.x, v.y, v.z, v.w); + } + + public double distance(final Vector4l v) { + return this.distance(v.x(), v.y(), v.z(), v.w()); + } + + public double distance(final double x, final double y, final double z, final double w) { + return this.distance(GenericMath.floorl(x), GenericMath.floorl(y), GenericMath.floorl(z), GenericMath.floorl(w)); + } + + public double distance(final long x, final long y, final long z, final long w) { + return Math.sqrt(this.distanceSquared(x, y, z, w)); + } + + @Override + public long lengthSquared() { + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + } + + @Override + public double length() { + return Math.sqrt(this.lengthSquared()); + } + + @Override + public int minAxis() { + long value = this.x; + int axis = 0; + if (this.y < value) { + value = this.y; + axis = 1; + } + if (this.z < value) { + value = this.z; + axis = 2; + } + if (this.w < value) { + axis = 3; + } + return axis; + } + + @Override + public int maxAxis() { + long value = this.x; + int axis = 0; + if (this.y > value) { + value = this.y; + axis = 1; + } + if (this.z > value) { + value = this.z; + axis = 2; + } + if (this.w > value) { + axis = 3; + } + return axis; + } + + @Override + public long[] toArray() { + return new long[]{this.x, this.y, this.z, this.w}; + } + + @Override + public Vector4i toInt() { + return new Vector4i(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4l toLong() { + return new Vector4l(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4f toFloat() { + return new Vector4f(this.x, this.y, this.z, this.w); + } + + @Override + public Vector4d toDouble() { + return new Vector4d((double) this.x, (double) this.y, (double) this.z, (double) this.w); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final MutableVector4l that)) { + return false; + } else { + return that.x == this.x + && that.y == this.y + && that.z == this.z + && that.w == this.w; + } + } + + @Override + public int hashCode() { + int result = Long.hashCode(this.x); + result = result * 31 + Long.hashCode(this.y); + result = result * 31 + Long.hashCode(this.z); + result = result * 31 + Long.hashCode(this.w); + return result; + } + + @Override + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ", " + this.w + ")"; + } + + public static MutableVector4l zero() { + return MutableVector4l.of(0, 0, 0, 0); + } + + public static MutableVector4l unitX() { + return MutableVector4l.of(1, 0, 0, 0); + } + + public static MutableVector4l unitY() { + return MutableVector4l.of(0, 1, 0, 0); + } + + public static MutableVector4l unitZ() { + return MutableVector4l.of(0, 0, 1, 0); + } + + public static MutableVector4l unitW() { + return MutableVector4l.of(0, 0, 0, 1); + } + + public static MutableVector4l one() { + return MutableVector4l.of(1, 1, 1, 1); + } + + public static MutableVector4l from(final double n) { + return MutableVector4l.from(GenericMath.floorl(n)); + } + + public static MutableVector4l from(final long n) { + return MutableVector4l.of(n, n, n, n); + } + + public static MutableVector4l from(final MutableVector4l v) { + return MutableVector4l.of(v.x, v.y, v.z, v.w); + } + + public static MutableVector4l from(final Vector4l v) { + return MutableVector4l.of(v.x(), v.y(), v.z(), v.w()); + } + + public static MutableVector4l of(final double x, final double y, final double z, final double w) { + return new MutableVector4l(x, y, z, w); + } + + public static MutableVector4l of(final long x, final long y, final long z, final long w) { + return new MutableVector4l(x, y, z, w); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/optional/package-info.java b/src/main/java/net/hellheim/spongetools/math/optional/package-info.java new file mode 100644 index 0000000..9ca9cc0 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/optional/package-info.java @@ -0,0 +1,7 @@ +/** + * This package provides variants of objects from SpongePowered + * math with some of their components possibly omitted. + * + * @see org.spongepowered.math + */ +package net.hellheim.spongetools.math.optional; diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2d.java b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2d.java new file mode 100644 index 0000000..10cdd5a --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2d.java @@ -0,0 +1,219 @@ +package net.hellheim.spongetools.math.optional.vector; + +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalDouble; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.math.vector.Vector2d; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector2d; + +public final class OptionalVector2d { + + private final OptionalDouble x; + private final OptionalDouble y; + private final Transformer transformer; + + private OptionalVector2d(final OptionalDouble x, final OptionalDouble y) { + this.x = x; + this.y = y; + + if (this.x.isPresent()) { + final double x0 = this.x.getAsDouble(); + if (this.y.isPresent()) { + final double y0 = this.y.getAsDouble(); + this.transformer = (o, v) -> o.apply(x0, y0); + } else { + this.transformer = (o, v) -> o.apply(x0, v); + } + } else if (this.y.isPresent()) { + final double y0 = this.y.getAsDouble(); + this.transformer = (o, v) -> o.apply(v, y0); + } else { + this.transformer = (o, v) -> o; + } + } + + public OptionalDouble x() { + return this.x; + } + + public OptionalDouble y() { + return this.y; + } + + @SuppressWarnings("unchecked") + private V apply(final Operator operator, final double neutralValue) { + return (V) this.transformer.apply(operator, neutralValue); + } + + public MutableVector2d set(final MutableVector2d v) { + this.x.ifPresent(v::x); + this.y.ifPresent(v::y); + return v; + } + + public Vector2d set(final Vector2d v) { + final double x = this.x.orElse(v.x()); + final double y = this.y.orElse(v.y()); + return new Vector2d(x, y); + } + + public MutableVector2d add(final MutableVector2d v) { + return this.apply(v::add, 0); + } + + public Vector2d add(final Vector2d v) { + return this.apply(v::add, 0); + } + + public MutableVector2d sub(final MutableVector2d v) { + return this.apply(v::sub, 0); + } + + public Vector2d sub(final Vector2d v) { + return this.apply(v::sub, 0); + } + + public MutableVector2d mul(final MutableVector2d v) { + return this.apply(v::mul, 1); + } + + public Vector2d mul(final Vector2d v) { + return this.apply(v::mul, 1); + } + + public MutableVector2d div(final MutableVector2d v) { + return this.apply(v::div, 1); + } + + public Vector2d div(final Vector2d v) { + return this.apply(v::div, 1); + } + + public MutableVector2d pow(final MutableVector2d v) { + return this.apply(v::pow, 1); + } + + public Vector2d pow(final Vector2d v) { + final double x = Math.pow(v.x(), this.x.orElse(1)); + final double y = Math.pow(v.y(), this.y.orElse(1)); + return new Vector2d(x, y); + } + + public MutableVector2d min(final MutableVector2d v) { + return this.apply(v::min, Double.POSITIVE_INFINITY); + } + + public Vector2d min(final Vector2d v) { + return this.apply(v::min, Double.POSITIVE_INFINITY); + } + + public MutableVector2d max(final MutableVector2d v) { + return this.apply(v::max, Double.NEGATIVE_INFINITY); + } + + public Vector2d max(final Vector2d v) { + return this.apply(v::max, Double.NEGATIVE_INFINITY); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final OptionalVector2d that)) { + return false; + } else { + return this.x.equals(that.x) + && this.y.equals(that.y); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.x, this.y); + } + + @Override + public String toString() { + return "(" + + "x=" + (this.x.isPresent() ? this.x.getAsDouble() : "?") + + "y=" + (this.y.isPresent() ? this.y.getAsDouble() : "?") + + ")"; + } + + public static OptionalVector2d x(final double x) { + return OptionalVector2d.x(convert(x)); + } + + public static OptionalVector2d x(final @Nullable Double x) { + return OptionalVector2d.x(convert(x)); + } + + public static OptionalVector2d x(final Optional x) { + return OptionalVector2d.x(convert(x)); + } + + public static OptionalVector2d x(final OptionalDouble x) { + return OptionalVector2d.of(x, empty()); + } + + public static OptionalVector2d y(final double y) { + return OptionalVector2d.y(convert(y)); + } + + public static OptionalVector2d y(final @Nullable Double y) { + return OptionalVector2d.y(convert(y)); + } + + public static OptionalVector2d y(final Optional y) { + return OptionalVector2d.y(convert(y)); + } + + public static OptionalVector2d y(final OptionalDouble y) { + return OptionalVector2d.of(empty(), y); + } + + public static OptionalVector2d of(final double x, final double y) { + return OptionalVector2d.of(convert(x), convert(y)); + } + + public static OptionalVector2d of(final @Nullable Double x, final @Nullable Double y) { + return OptionalVector2d.of(convert(x), convert(y)); + } + + public static OptionalVector2d of(final Optional x, final Optional y) { + return OptionalVector2d.of(convert(x), convert(y)); + } + + public static OptionalVector2d of(final OptionalDouble x, final OptionalDouble y) { + return new OptionalVector2d(x, y); + } + + private static OptionalDouble empty() { + return OptionalDouble.empty(); + } + + private static OptionalDouble convert(final double a) { + return OptionalDouble.of(a); + } + + private static OptionalDouble convert(final @Nullable Double a) { + return a == null ? empty() : OptionalDouble.of(a.doubleValue()); + } + + private static OptionalDouble convert(final Optional a) { + return a.map(OptionalDouble::of).orElseGet(OptionalVector2d::empty); + } + + private interface Transformer { + + Object apply(Operator operator, double neutralValue); + } + + private interface Operator { + + V apply(double x, double y); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2i.java b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2i.java new file mode 100644 index 0000000..c16b0a6 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2i.java @@ -0,0 +1,220 @@ +package net.hellheim.spongetools.math.optional.vector; + +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalInt; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector2i; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector2i; + +public final class OptionalVector2i { + + private final OptionalInt x; + private final OptionalInt y; + private final Transformer transformer; + + private OptionalVector2i(final OptionalInt x, final OptionalInt y) { + this.x = x; + this.y = y; + + if (this.x.isPresent()) { + final int x0 = this.x.getAsInt(); + if (this.y.isPresent()) { + final int y0 = this.y.getAsInt(); + this.transformer = (o, v) -> o.apply(x0, y0); + } else { + this.transformer = (o, v) -> o.apply(x0, v); + } + } else if (this.y.isPresent()) { + final int y0 = this.y.getAsInt(); + this.transformer = (o, v) -> o.apply(v, y0); + } else { + this.transformer = (o, v) -> o; + } + } + + public OptionalInt x() { + return this.x; + } + + public OptionalInt y() { + return this.y; + } + + @SuppressWarnings("unchecked") + private V apply(final Operator operator, final int neutralValue) { + return (V) this.transformer.apply(operator, neutralValue); + } + + public MutableVector2i set(final MutableVector2i v) { + this.x.ifPresent(v::x); + this.y.ifPresent(v::y); + return v; + } + + public Vector2i set(final Vector2i v) { + final int x = this.x.orElse(v.x()); + final int y = this.y.orElse(v.y()); + return new Vector2i(x, y); + } + + public MutableVector2i add(final MutableVector2i v) { + return this.apply(v::add, 0); + } + + public Vector2i add(final Vector2i v) { + return this.apply(v::add, 0); + } + + public MutableVector2i sub(final MutableVector2i v) { + return this.apply(v::sub, 0); + } + + public Vector2i sub(final Vector2i v) { + return this.apply(v::sub, 0); + } + + public MutableVector2i mul(final MutableVector2i v) { + return this.apply(v::mul, 1); + } + + public Vector2i mul(final Vector2i v) { + return this.apply(v::mul, 1); + } + + public MutableVector2i div(final MutableVector2i v) { + return this.apply(v::div, 1); + } + + public Vector2i div(final Vector2i v) { + return this.apply(v::div, 1); + } + + public MutableVector2i pow(final MutableVector2i v) { + return this.apply(v::pow, 1); + } + + public Vector2i pow(final Vector2i v) { + final int x = GenericMath.floor(Math.pow(v.x(), this.x.orElse(1))); + final int y = GenericMath.floor(Math.pow(v.y(), this.y.orElse(1))); + return new Vector2i(x, y); + } + + public MutableVector2i min(final MutableVector2i v) { + return this.apply(v::min, Integer.MAX_VALUE); + } + + public Vector2i min(final Vector2i v) { + return this.apply(v::min, Integer.MAX_VALUE); + } + + public MutableVector2i max(final MutableVector2i v) { + return this.apply(v::max, Integer.MIN_VALUE); + } + + public Vector2i max(final Vector2i v) { + return this.apply(v::max, Integer.MIN_VALUE); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final OptionalVector2i that)) { + return false; + } else { + return this.x.equals(that.x) + && this.y.equals(that.y); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.x, this.y); + } + + @Override + public String toString() { + return "(" + + "x=" + (this.x.isPresent() ? this.x.getAsInt() : "?") + + "y=" + (this.y.isPresent() ? this.y.getAsInt() : "?") + + ")"; + } + + public static OptionalVector2i x(final int x) { + return OptionalVector2i.x(convert(x)); + } + + public static OptionalVector2i x(final @Nullable Integer x) { + return OptionalVector2i.x(convert(x)); + } + + public static OptionalVector2i x(final Optional x) { + return OptionalVector2i.x(convert(x)); + } + + public static OptionalVector2i x(final OptionalInt x) { + return OptionalVector2i.of(x, empty()); + } + + public static OptionalVector2i y(final int y) { + return OptionalVector2i.y(convert(y)); + } + + public static OptionalVector2i y(final @Nullable Integer y) { + return OptionalVector2i.y(convert(y)); + } + + public static OptionalVector2i y(final Optional y) { + return OptionalVector2i.y(convert(y)); + } + + public static OptionalVector2i y(final OptionalInt y) { + return OptionalVector2i.of(empty(), y); + } + + public static OptionalVector2i of(final int x, final int y) { + return OptionalVector2i.of(convert(x), convert(y)); + } + + public static OptionalVector2i of(final @Nullable Integer x, final @Nullable Integer y) { + return OptionalVector2i.of(convert(x), convert(y)); + } + + public static OptionalVector2i of(final Optional x, final Optional y) { + return OptionalVector2i.of(convert(x), convert(y)); + } + + public static OptionalVector2i of(final OptionalInt x, final OptionalInt y) { + return new OptionalVector2i(x, y); + } + + private static OptionalInt empty() { + return OptionalInt.empty(); + } + + private static OptionalInt convert(final int a) { + return OptionalInt.of(a); + } + + private static OptionalInt convert(final @Nullable Integer a) { + return a == null ? empty() : OptionalInt.of(a.intValue()); + } + + private static OptionalInt convert(final Optional a) { + return a.map(OptionalInt::of).orElseGet(OptionalVector2i::empty); + } + + private interface Transformer { + + Object apply(Operator operator, int neutralValue); + } + + private interface Operator { + + V apply(int x, int y); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2l.java b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2l.java new file mode 100644 index 0000000..fb1f6e9 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2l.java @@ -0,0 +1,220 @@ +package net.hellheim.spongetools.math.optional.vector; + +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalLong; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector2l; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector2l; + +public final class OptionalVector2l { + + private final OptionalLong x; + private final OptionalLong y; + private final Transformer transformer; + + private OptionalVector2l(final OptionalLong x, final OptionalLong y) { + this.x = x; + this.y = y; + + if (this.x.isPresent()) { + final long x0 = this.x.getAsLong(); + if (this.y.isPresent()) { + final long y0 = this.y.getAsLong(); + this.transformer = (o, v) -> o.apply(x0, y0); + } else { + this.transformer = (o, v) -> o.apply(x0, v); + } + } else if (this.y.isPresent()) { + final long y0 = this.y.getAsLong(); + this.transformer = (o, v) -> o.apply(v, y0); + } else { + this.transformer = (o, v) -> o; + } + } + + public OptionalLong x() { + return this.x; + } + + public OptionalLong y() { + return this.y; + } + + @SuppressWarnings("unchecked") + private V apply(final Operator operator, final long neutralValue) { + return (V) this.transformer.apply(operator, neutralValue); + } + + public MutableVector2l set(final MutableVector2l v) { + this.x.ifPresent(v::x); + this.y.ifPresent(v::y); + return v; + } + + public Vector2l set(final Vector2l v) { + final long x = this.x.orElse(v.x()); + final long y = this.y.orElse(v.y()); + return new Vector2l(x, y); + } + + public MutableVector2l add(final MutableVector2l v) { + return this.apply(v::add, 0); + } + + public Vector2l add(final Vector2l v) { + return this.apply(v::add, 0); + } + + public MutableVector2l sub(final MutableVector2l v) { + return this.apply(v::sub, 0); + } + + public Vector2l sub(final Vector2l v) { + return this.apply(v::sub, 0); + } + + public MutableVector2l mul(final MutableVector2l v) { + return this.apply(v::mul, 1); + } + + public Vector2l mul(final Vector2l v) { + return this.apply(v::mul, 1); + } + + public MutableVector2l div(final MutableVector2l v) { + return this.apply(v::div, 1); + } + + public Vector2l div(final Vector2l v) { + return this.apply(v::div, 1); + } + + public MutableVector2l pow(final MutableVector2l v) { + return this.apply(v::pow, 1); + } + + public Vector2l pow(final Vector2l v) { + final long x = GenericMath.floorl(Math.pow(v.x(), this.x.orElse(1))); + final long y = GenericMath.floorl(Math.pow(v.y(), this.y.orElse(1))); + return new Vector2l(x, y); + } + + public MutableVector2l min(final MutableVector2l v) { + return this.apply(v::min, Long.MAX_VALUE); + } + + public Vector2l min(final Vector2l v) { + return this.apply(v::min, Long.MAX_VALUE); + } + + public MutableVector2l max(final MutableVector2l v) { + return this.apply(v::max, Long.MIN_VALUE); + } + + public Vector2l max(final Vector2l v) { + return this.apply(v::max, Long.MIN_VALUE); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final OptionalVector2l that)) { + return false; + } else { + return this.x.equals(that.x) + && this.y.equals(that.y); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.x, this.y); + } + + @Override + public String toString() { + return "(" + + "x=" + (this.x.isPresent() ? this.x.getAsLong() : "?") + + "y=" + (this.y.isPresent() ? this.y.getAsLong() : "?") + + ")"; + } + + public static OptionalVector2l x(final long x) { + return OptionalVector2l.x(convert(x)); + } + + public static OptionalVector2l x(final @Nullable Long x) { + return OptionalVector2l.x(convert(x)); + } + + public static OptionalVector2l x(final Optional x) { + return OptionalVector2l.x(convert(x)); + } + + public static OptionalVector2l x(final OptionalLong x) { + return OptionalVector2l.of(x, empty()); + } + + public static OptionalVector2l y(final long y) { + return OptionalVector2l.y(convert(y)); + } + + public static OptionalVector2l y(final @Nullable Long y) { + return OptionalVector2l.y(convert(y)); + } + + public static OptionalVector2l y(final Optional y) { + return OptionalVector2l.y(convert(y)); + } + + public static OptionalVector2l y(final OptionalLong y) { + return OptionalVector2l.of(empty(), y); + } + + public static OptionalVector2l of(final long x, final long y) { + return OptionalVector2l.of(convert(x), convert(y)); + } + + public static OptionalVector2l of(final @Nullable Long x, final @Nullable Long y) { + return OptionalVector2l.of(convert(x), convert(y)); + } + + public static OptionalVector2l of(final Optional x, final Optional y) { + return OptionalVector2l.of(convert(x), convert(y)); + } + + public static OptionalVector2l of(final OptionalLong x, final OptionalLong y) { + return new OptionalVector2l(x, y); + } + + private static OptionalLong empty() { + return OptionalLong.empty(); + } + + private static OptionalLong convert(final long a) { + return OptionalLong.of(a); + } + + private static OptionalLong convert(final @Nullable Long a) { + return a == null ? empty() : OptionalLong.of(a.longValue()); + } + + private static OptionalLong convert(final Optional a) { + return a.map(OptionalLong::of).orElseGet(OptionalVector2l::empty); + } + + private interface Transformer { + + Object apply(Operator operator, long neutralValue); + } + + private interface Operator { + + V apply(long x, long y); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3d.java b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3d.java new file mode 100644 index 0000000..db1dd17 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3d.java @@ -0,0 +1,310 @@ +package net.hellheim.spongetools.math.optional.vector; + +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalDouble; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.math.vector.Vector3d; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector3d; + +public final class OptionalVector3d { + + private final OptionalDouble x; + private final OptionalDouble y; + private final OptionalDouble z; + private final Transformer transformer; + + private OptionalVector3d(final OptionalDouble x, final OptionalDouble y, final OptionalDouble z) { + this.x = x; + this.y = y; + this.z = z; + + if (this.x.isPresent()) { + final double x0 = this.x.getAsDouble(); + if (this.y.isPresent()) { + final double y0 = this.y.getAsDouble(); + if (this.z.isPresent()) { + final double z0 = this.z.getAsDouble(); + this.transformer = (o, v) -> o.apply(x0, y0, z0); + } else { + this.transformer = (o, v) -> o.apply(x0, y0, v); + } + } else if (this.z.isPresent()) { + final double z0 = this.z.getAsDouble(); + this.transformer = (o, v) -> o.apply(x0, v, z0); + } else { + this.transformer = (o, v) -> o.apply(x0, v, v); + } + } else if (this.y.isPresent()) { + final double y0 = this.y.getAsDouble(); + if (this.z.isPresent()) { + final double z0 = this.z.getAsDouble(); + this.transformer = (o, v) -> o.apply(v, y0, z0); + } else { + this.transformer = (o, v) -> o.apply(v, y0, v); + } + } else if (this.z.isPresent()) { + final double z0 = this.z.getAsDouble(); + this.transformer = (o, v) -> o.apply(v, v, z0); + } else { + this.transformer = (o, v) -> o; + } + } + + public OptionalDouble x() { + return this.x; + } + + public OptionalDouble y() { + return this.y; + } + + public OptionalDouble z() { + return this.z; + } + + @SuppressWarnings("unchecked") + private V apply(final Operator operator, final double neutralValue) { + return (V) this.transformer.apply(operator, neutralValue); + } + + public MutableVector3d set(final MutableVector3d v) { + this.x.ifPresent(v::x); + this.y.ifPresent(v::y); + this.z.ifPresent(v::z); + return v; + } + + public Vector3d set(final Vector3d v) { + final double x = this.x.orElse(v.x()); + final double y = this.y.orElse(v.y()); + final double z = this.z.orElse(v.z()); + return new Vector3d(x, y, z); + } + + public MutableVector3d add(final MutableVector3d v) { + return this.apply(v::add, 0); + } + + public Vector3d add(final Vector3d v) { + return this.apply(v::add, 0); + } + + public MutableVector3d sub(final MutableVector3d v) { + return this.apply(v::sub, 0); + } + + public Vector3d sub(final Vector3d v) { + return this.apply(v::sub, 0); + } + + public MutableVector3d mul(final MutableVector3d v) { + return this.apply(v::mul, 1); + } + + public Vector3d mul(final Vector3d v) { + return this.apply(v::mul, 1); + } + + public MutableVector3d div(final MutableVector3d v) { + return this.apply(v::div, 1); + } + + public Vector3d div(final Vector3d v) { + return this.apply(v::div, 1); + } + + public MutableVector3d pow(final MutableVector3d v) { + return this.apply(v::pow, 1); + } + + public Vector3d pow(final Vector3d v) { + final double x = Math.pow(v.x(), this.x.orElse(1)); + final double y = Math.pow(v.y(), this.y.orElse(1)); + final double z = Math.pow(v.z(), this.z.orElse(1)); + return new Vector3d(x, y, z); + } + + public MutableVector3d min(final MutableVector3d v) { + return this.apply(v::min, Double.POSITIVE_INFINITY); + } + + public Vector3d min(final Vector3d v) { + return this.apply(v::min, Double.POSITIVE_INFINITY); + } + + public MutableVector3d max(final MutableVector3d v) { + return this.apply(v::max, Double.NEGATIVE_INFINITY); + } + + public Vector3d max(final Vector3d v) { + return this.apply(v::max, Double.NEGATIVE_INFINITY); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final OptionalVector3d that)) { + return false; + } else { + return this.x.equals(that.x) + && this.y.equals(that.y) + && this.z.equals(that.z); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.x, this.y, this.z); + } + + @Override + public String toString() { + return "(" + + "x=" + (this.x.isPresent() ? this.x.getAsDouble() : "?") + + "y=" + (this.y.isPresent() ? this.y.getAsDouble() : "?") + + "z=" + (this.z.isPresent() ? this.z.getAsDouble() : "?") + + ")"; + } + + public static OptionalVector3d x(final double x) { + return OptionalVector3d.x(convert(x)); + } + + public static OptionalVector3d x(final @Nullable Double x) { + return OptionalVector3d.x(convert(x)); + } + + public static OptionalVector3d x(final Optional x) { + return OptionalVector3d.x(convert(x)); + } + + public static OptionalVector3d x(final OptionalDouble x) { + return OptionalVector3d.of(x, empty(), empty()); + } + + public static OptionalVector3d y(final double y) { + return OptionalVector3d.y(convert(y)); + } + + public static OptionalVector3d y(final @Nullable Double y) { + return OptionalVector3d.y(convert(y)); + } + + public static OptionalVector3d y(final Optional y) { + return OptionalVector3d.y(convert(y)); + } + + public static OptionalVector3d y(final OptionalDouble y) { + return OptionalVector3d.of(empty(), y, empty()); + } + + public static OptionalVector3d z(final double z) { + return OptionalVector3d.z(convert(z)); + } + + public static OptionalVector3d z(final @Nullable Double z) { + return OptionalVector3d.z(convert(z)); + } + + public static OptionalVector3d z(final Optional z) { + return OptionalVector3d.z(convert(z)); + } + + public static OptionalVector3d z(final OptionalDouble z) { + return OptionalVector3d.of(empty(), empty(), z); + } + + public static OptionalVector3d xy(final double x, final double y) { + return OptionalVector3d.xy(convert(x), convert(y)); + } + + public static OptionalVector3d xy(final @Nullable Double x, final @Nullable Double y) { + return OptionalVector3d.xy(convert(x), convert(y)); + } + + public static OptionalVector3d xy(final Optional x, final Optional y) { + return OptionalVector3d.xy(convert(x), convert(y)); + } + + public static OptionalVector3d xy(final OptionalDouble x, final OptionalDouble y) { + return OptionalVector3d.of(x, y, empty()); + } + + public static OptionalVector3d xz(final double x, final double z) { + return OptionalVector3d.xz(convert(x), convert(z)); + } + + public static OptionalVector3d xz(final @Nullable Double x, final @Nullable Double z) { + return OptionalVector3d.xz(convert(x), convert(z)); + } + + public static OptionalVector3d xz(final Optional x, final Optional z) { + return OptionalVector3d.xz(convert(x), convert(z)); + } + + public static OptionalVector3d xz(final OptionalDouble x, final OptionalDouble z) { + return OptionalVector3d.of(x, empty(), z); + } + + public static OptionalVector3d yz(final double y, final double z) { + return OptionalVector3d.yz(convert(y), convert(z)); + } + + public static OptionalVector3d yz(final @Nullable Double y, final @Nullable Double z) { + return OptionalVector3d.yz(convert(y), convert(z)); + } + + public static OptionalVector3d yz(final Optional y, final Optional z) { + return OptionalVector3d.yz(convert(y), convert(z)); + } + + public static OptionalVector3d yz(final OptionalDouble y, final OptionalDouble z) { + return OptionalVector3d.of(empty(), y, z); + } + + public static OptionalVector3d of(final double x, final double y, final double z) { + return OptionalVector3d.of(convert(x), convert(y), convert(z)); + } + + public static OptionalVector3d of(final @Nullable Double x, final @Nullable Double y, final @Nullable Double z) { + return OptionalVector3d.of(convert(x), convert(y), convert(z)); + } + + public static OptionalVector3d of(final Optional x, final Optional y, final Optional z) { + return OptionalVector3d.of(convert(x), convert(y), convert(z)); + } + + public static OptionalVector3d of(final OptionalDouble x, final OptionalDouble y, final OptionalDouble z) { + return new OptionalVector3d(x, y, z); + } + + private static OptionalDouble empty() { + return OptionalDouble.empty(); + } + + private static OptionalDouble convert(final double a) { + return OptionalDouble.of(a); + } + + private static OptionalDouble convert(final @Nullable Double a) { + return a == null ? empty() : OptionalDouble.of(a.doubleValue()); + } + + private static OptionalDouble convert(final Optional a) { + return a.map(OptionalDouble::of).orElseGet(OptionalVector3d::empty); + } + + private interface Transformer { + + Object apply(Operator operator, double neutralValue); + } + + private interface Operator { + + V apply(double x, double y, double z); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3i.java b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3i.java new file mode 100644 index 0000000..ca4bdd8 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3i.java @@ -0,0 +1,311 @@ +package net.hellheim.spongetools.math.optional.vector; + +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalInt; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector3i; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector3i; + +public final class OptionalVector3i { + + private final OptionalInt x; + private final OptionalInt y; + private final OptionalInt z; + private final Transformer transformer; + + private OptionalVector3i(final OptionalInt x, final OptionalInt y, final OptionalInt z) { + this.x = x; + this.y = y; + this.z = z; + + if (this.x.isPresent()) { + final int x0 = this.x.getAsInt(); + if (this.y.isPresent()) { + final int y0 = this.y.getAsInt(); + if (this.z.isPresent()) { + final int z0 = this.z.getAsInt(); + this.transformer = (o, v) -> o.apply(x0, y0, z0); + } else { + this.transformer = (o, v) -> o.apply(x0, y0, v); + } + } else if (this.z.isPresent()) { + final int z0 = this.z.getAsInt(); + this.transformer = (o, v) -> o.apply(x0, v, z0); + } else { + this.transformer = (o, v) -> o.apply(x0, v, v); + } + } else if (this.y.isPresent()) { + final int y0 = this.y.getAsInt(); + if (this.z.isPresent()) { + final int z0 = this.z.getAsInt(); + this.transformer = (o, v) -> o.apply(v, y0, z0); + } else { + this.transformer = (o, v) -> o.apply(v, y0, v); + } + } else if (this.z.isPresent()) { + final int z0 = this.z.getAsInt(); + this.transformer = (o, v) -> o.apply(v, v, z0); + } else { + this.transformer = (o, v) -> o; + } + } + + public OptionalInt x() { + return this.x; + } + + public OptionalInt y() { + return this.y; + } + + public OptionalInt z() { + return this.z; + } + + @SuppressWarnings("unchecked") + private V apply(final Operator operator, final int neutralValue) { + return (V) this.transformer.apply(operator, neutralValue); + } + + public MutableVector3i set(final MutableVector3i v) { + this.x.ifPresent(v::x); + this.y.ifPresent(v::y); + this.z.ifPresent(v::z); + return v; + } + + public Vector3i set(final Vector3i v) { + final int x = this.x.orElse(v.x()); + final int y = this.y.orElse(v.y()); + final int z = this.z.orElse(v.z()); + return new Vector3i(x, y, z); + } + + public MutableVector3i add(final MutableVector3i v) { + return this.apply(v::add, 0); + } + + public Vector3i add(final Vector3i v) { + return this.apply(v::add, 0); + } + + public MutableVector3i sub(final MutableVector3i v) { + return this.apply(v::sub, 0); + } + + public Vector3i sub(final Vector3i v) { + return this.apply(v::sub, 0); + } + + public MutableVector3i mul(final MutableVector3i v) { + return this.apply(v::mul, 1); + } + + public Vector3i mul(final Vector3i v) { + return this.apply(v::mul, 1); + } + + public MutableVector3i div(final MutableVector3i v) { + return this.apply(v::div, 1); + } + + public Vector3i div(final Vector3i v) { + return this.apply(v::div, 1); + } + + public MutableVector3i pow(final MutableVector3i v) { + return this.apply(v::pow, 1); + } + + public Vector3i pow(final Vector3i v) { + final int x = GenericMath.floor(Math.pow(v.x(), this.x.orElse(1))); + final int y = GenericMath.floor(Math.pow(v.y(), this.y.orElse(1))); + final int z = GenericMath.floor(Math.pow(v.z(), this.z.orElse(1))); + return new Vector3i(x, y, z); + } + + public MutableVector3i min(final MutableVector3i v) { + return this.apply(v::min, Integer.MAX_VALUE); + } + + public Vector3i min(final Vector3i v) { + return this.apply(v::min, Integer.MAX_VALUE); + } + + public MutableVector3i max(final MutableVector3i v) { + return this.apply(v::max, Integer.MIN_VALUE); + } + + public Vector3i max(final Vector3i v) { + return this.apply(v::max, Integer.MIN_VALUE); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final OptionalVector3i that)) { + return false; + } else { + return this.x.equals(that.x) + && this.y.equals(that.y) + && this.z.equals(that.z); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.x, this.y, this.z); + } + + @Override + public String toString() { + return "(" + + "x=" + (this.x.isPresent() ? this.x.getAsInt() : "?") + + "y=" + (this.y.isPresent() ? this.y.getAsInt() : "?") + + "z=" + (this.z.isPresent() ? this.z.getAsInt() : "?") + + ")"; + } + + public static OptionalVector3i x(final int x) { + return OptionalVector3i.x(convert(x)); + } + + public static OptionalVector3i x(final @Nullable Integer x) { + return OptionalVector3i.x(convert(x)); + } + + public static OptionalVector3i x(final Optional x) { + return OptionalVector3i.x(convert(x)); + } + + public static OptionalVector3i x(final OptionalInt x) { + return OptionalVector3i.of(x, empty(), empty()); + } + + public static OptionalVector3i y(final int y) { + return OptionalVector3i.y(convert(y)); + } + + public static OptionalVector3i y(final @Nullable Integer y) { + return OptionalVector3i.y(convert(y)); + } + + public static OptionalVector3i y(final Optional y) { + return OptionalVector3i.y(convert(y)); + } + + public static OptionalVector3i y(final OptionalInt y) { + return OptionalVector3i.of(empty(), y, empty()); + } + + public static OptionalVector3i z(final int z) { + return OptionalVector3i.z(convert(z)); + } + + public static OptionalVector3i z(final @Nullable Integer z) { + return OptionalVector3i.z(convert(z)); + } + + public static OptionalVector3i z(final Optional z) { + return OptionalVector3i.z(convert(z)); + } + + public static OptionalVector3i z(final OptionalInt z) { + return OptionalVector3i.of(empty(), empty(), z); + } + + public static OptionalVector3i xy(final int x, final int y) { + return OptionalVector3i.xy(convert(x), convert(y)); + } + + public static OptionalVector3i xy(final @Nullable Integer x, final @Nullable Integer y) { + return OptionalVector3i.xy(convert(x), convert(y)); + } + + public static OptionalVector3i xy(final Optional x, final Optional y) { + return OptionalVector3i.xy(convert(x), convert(y)); + } + + public static OptionalVector3i xy(final OptionalInt x, final OptionalInt y) { + return OptionalVector3i.of(x, y, empty()); + } + + public static OptionalVector3i xz(final int x, final int z) { + return OptionalVector3i.xz(convert(x), convert(z)); + } + + public static OptionalVector3i xz(final @Nullable Integer x, final @Nullable Integer z) { + return OptionalVector3i.xz(convert(x), convert(z)); + } + + public static OptionalVector3i xz(final Optional x, final Optional z) { + return OptionalVector3i.xz(convert(x), convert(z)); + } + + public static OptionalVector3i xz(final OptionalInt x, final OptionalInt z) { + return OptionalVector3i.of(x, empty(), z); + } + + public static OptionalVector3i yz(final int y, final int z) { + return OptionalVector3i.yz(convert(y), convert(z)); + } + + public static OptionalVector3i yz(final @Nullable Integer y, final @Nullable Integer z) { + return OptionalVector3i.yz(convert(y), convert(z)); + } + + public static OptionalVector3i yz(final Optional y, final Optional z) { + return OptionalVector3i.yz(convert(y), convert(z)); + } + + public static OptionalVector3i yz(final OptionalInt y, final OptionalInt z) { + return OptionalVector3i.of(empty(), y, z); + } + + public static OptionalVector3i of(final int x, final int y, final int z) { + return OptionalVector3i.of(convert(x), convert(y), convert(z)); + } + + public static OptionalVector3i of(final @Nullable Integer x, final @Nullable Integer y, final @Nullable Integer z) { + return OptionalVector3i.of(convert(x), convert(y), convert(z)); + } + + public static OptionalVector3i of(final Optional x, final Optional y, final Optional z) { + return OptionalVector3i.of(convert(x), convert(y), convert(z)); + } + + public static OptionalVector3i of(final OptionalInt x, final OptionalInt y, final OptionalInt z) { + return new OptionalVector3i(x, y, z); + } + + private static OptionalInt empty() { + return OptionalInt.empty(); + } + + private static OptionalInt convert(final int a) { + return OptionalInt.of(a); + } + + private static OptionalInt convert(final @Nullable Integer a) { + return a == null ? empty() : OptionalInt.of(a.intValue()); + } + + private static OptionalInt convert(final Optional a) { + return a.map(OptionalInt::of).orElseGet(OptionalVector3i::empty); + } + + private interface Transformer { + + Object apply(Operator operator, int neutralValue); + } + + private interface Operator { + + V apply(int x, int y, int z); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3l.java b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3l.java new file mode 100644 index 0000000..64a7837 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3l.java @@ -0,0 +1,311 @@ +package net.hellheim.spongetools.math.optional.vector; + +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalLong; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector3l; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector3l; + +public final class OptionalVector3l { + + private final OptionalLong x; + private final OptionalLong y; + private final OptionalLong z; + private final Transformer transformer; + + private OptionalVector3l(final OptionalLong x, final OptionalLong y, final OptionalLong z) { + this.x = x; + this.y = y; + this.z = z; + + if (this.x.isPresent()) { + final long x0 = this.x.getAsLong(); + if (this.y.isPresent()) { + final long y0 = this.y.getAsLong(); + if (this.z.isPresent()) { + final long z0 = this.z.getAsLong(); + this.transformer = (o, v) -> o.apply(x0, y0, z0); + } else { + this.transformer = (o, v) -> o.apply(x0, y0, v); + } + } else if (this.z.isPresent()) { + final long z0 = this.z.getAsLong(); + this.transformer = (o, v) -> o.apply(x0, v, z0); + } else { + this.transformer = (o, v) -> o.apply(x0, v, v); + } + } else if (this.y.isPresent()) { + final long y0 = this.y.getAsLong(); + if (this.z.isPresent()) { + final long z0 = this.z.getAsLong(); + this.transformer = (o, v) -> o.apply(v, y0, z0); + } else { + this.transformer = (o, v) -> o.apply(v, y0, v); + } + } else if (this.z.isPresent()) { + final long z0 = this.z.getAsLong(); + this.transformer = (o, v) -> o.apply(v, v, z0); + } else { + this.transformer = (o, v) -> o; + } + } + + public OptionalLong x() { + return this.x; + } + + public OptionalLong y() { + return this.y; + } + + public OptionalLong z() { + return this.z; + } + + @SuppressWarnings("unchecked") + private V apply(final Operator operator, final long neutralValue) { + return (V) this.transformer.apply(operator, neutralValue); + } + + public MutableVector3l set(final MutableVector3l v) { + this.x.ifPresent(v::x); + this.y.ifPresent(v::y); + this.z.ifPresent(v::z); + return v; + } + + public Vector3l set(final Vector3l v) { + final long x = this.x.orElse(v.x()); + final long y = this.y.orElse(v.y()); + final long z = this.z.orElse(v.z()); + return new Vector3l(x, y, z); + } + + public MutableVector3l add(final MutableVector3l v) { + return this.apply(v::add, 0); + } + + public Vector3l add(final Vector3l v) { + return this.apply(v::add, 0); + } + + public MutableVector3l sub(final MutableVector3l v) { + return this.apply(v::sub, 0); + } + + public Vector3l sub(final Vector3l v) { + return this.apply(v::sub, 0); + } + + public MutableVector3l mul(final MutableVector3l v) { + return this.apply(v::mul, 1); + } + + public Vector3l mul(final Vector3l v) { + return this.apply(v::mul, 1); + } + + public MutableVector3l div(final MutableVector3l v) { + return this.apply(v::div, 1); + } + + public Vector3l div(final Vector3l v) { + return this.apply(v::div, 1); + } + + public MutableVector3l pow(final MutableVector3l v) { + return this.apply(v::pow, 1); + } + + public Vector3l pow(final Vector3l v) { + final long x = GenericMath.floorl(Math.pow(v.x(), this.x.orElse(1))); + final long y = GenericMath.floorl(Math.pow(v.y(), this.y.orElse(1))); + final long z = GenericMath.floorl(Math.pow(v.z(), this.z.orElse(1))); + return new Vector3l(x, y, z); + } + + public MutableVector3l min(final MutableVector3l v) { + return this.apply(v::min, Long.MAX_VALUE); + } + + public Vector3l min(final Vector3l v) { + return this.apply(v::min, Long.MAX_VALUE); + } + + public MutableVector3l max(final MutableVector3l v) { + return this.apply(v::max, Long.MIN_VALUE); + } + + public Vector3l max(final Vector3l v) { + return this.apply(v::max, Long.MIN_VALUE); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final OptionalVector3l that)) { + return false; + } else { + return this.x.equals(that.x) + && this.y.equals(that.y) + && this.z.equals(that.z); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.x, this.y, this.z); + } + + @Override + public String toString() { + return "(" + + "x=" + (this.x.isPresent() ? this.x.getAsLong() : "?") + + "y=" + (this.y.isPresent() ? this.y.getAsLong() : "?") + + "z=" + (this.z.isPresent() ? this.z.getAsLong() : "?") + + ")"; + } + + public static OptionalVector3l x(final long x) { + return OptionalVector3l.x(convert(x)); + } + + public static OptionalVector3l x(final @Nullable Long x) { + return OptionalVector3l.x(convert(x)); + } + + public static OptionalVector3l x(final Optional x) { + return OptionalVector3l.x(convert(x)); + } + + public static OptionalVector3l x(final OptionalLong x) { + return OptionalVector3l.of(x, empty(), empty()); + } + + public static OptionalVector3l y(final long y) { + return OptionalVector3l.y(convert(y)); + } + + public static OptionalVector3l y(final @Nullable Long y) { + return OptionalVector3l.y(convert(y)); + } + + public static OptionalVector3l y(final Optional y) { + return OptionalVector3l.y(convert(y)); + } + + public static OptionalVector3l y(final OptionalLong y) { + return OptionalVector3l.of(empty(), y, empty()); + } + + public static OptionalVector3l z(final long z) { + return OptionalVector3l.z(convert(z)); + } + + public static OptionalVector3l z(final @Nullable Long z) { + return OptionalVector3l.z(convert(z)); + } + + public static OptionalVector3l z(final Optional z) { + return OptionalVector3l.z(convert(z)); + } + + public static OptionalVector3l z(final OptionalLong z) { + return OptionalVector3l.of(empty(), empty(), z); + } + + public static OptionalVector3l xy(final long x, final long y) { + return OptionalVector3l.xy(convert(x), convert(y)); + } + + public static OptionalVector3l xy(final @Nullable Long x, final @Nullable Long y) { + return OptionalVector3l.xy(convert(x), convert(y)); + } + + public static OptionalVector3l xy(final Optional x, final Optional y) { + return OptionalVector3l.xy(convert(x), convert(y)); + } + + public static OptionalVector3l xy(final OptionalLong x, final OptionalLong y) { + return OptionalVector3l.of(x, y, empty()); + } + + public static OptionalVector3l xz(final long x, final long z) { + return OptionalVector3l.xz(convert(x), convert(z)); + } + + public static OptionalVector3l xz(final @Nullable Long x, final @Nullable Long z) { + return OptionalVector3l.xz(convert(x), convert(z)); + } + + public static OptionalVector3l xz(final Optional x, final Optional z) { + return OptionalVector3l.xz(convert(x), convert(z)); + } + + public static OptionalVector3l xz(final OptionalLong x, final OptionalLong z) { + return OptionalVector3l.of(x, empty(), z); + } + + public static OptionalVector3l yz(final long y, final long z) { + return OptionalVector3l.yz(convert(y), convert(z)); + } + + public static OptionalVector3l yz(final @Nullable Long y, final @Nullable Long z) { + return OptionalVector3l.yz(convert(y), convert(z)); + } + + public static OptionalVector3l yz(final Optional y, final Optional z) { + return OptionalVector3l.yz(convert(y), convert(z)); + } + + public static OptionalVector3l yz(final OptionalLong y, final OptionalLong z) { + return OptionalVector3l.of(empty(), y, z); + } + + public static OptionalVector3l of(final long x, final long y, final long z) { + return OptionalVector3l.of(convert(x), convert(y), convert(z)); + } + + public static OptionalVector3l of(final @Nullable Long x, final @Nullable Long y, final @Nullable Long z) { + return OptionalVector3l.of(convert(x), convert(y), convert(z)); + } + + public static OptionalVector3l of(final Optional x, final Optional y, final Optional z) { + return OptionalVector3l.of(convert(x), convert(y), convert(z)); + } + + public static OptionalVector3l of(final OptionalLong x, final OptionalLong y, final OptionalLong z) { + return new OptionalVector3l(x, y, z); + } + + private static OptionalLong empty() { + return OptionalLong.empty(); + } + + private static OptionalLong convert(final long a) { + return OptionalLong.of(a); + } + + private static OptionalLong convert(final @Nullable Long a) { + return a == null ? empty() : OptionalLong.of(a.longValue()); + } + + private static OptionalLong convert(final Optional a) { + return a.map(OptionalLong::of).orElseGet(OptionalVector3l::empty); + } + + private interface Transformer { + + Object apply(Operator operator, long neutralValue); + } + + private interface Operator { + + V apply(long x, long y, long z); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4d.java b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4d.java new file mode 100644 index 0000000..285d30f --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4d.java @@ -0,0 +1,481 @@ +package net.hellheim.spongetools.math.optional.vector; + +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalDouble; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.math.vector.Vector4d; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector4d; + +public final class OptionalVector4d { + + private final OptionalDouble x; + private final OptionalDouble y; + private final OptionalDouble z; + private final OptionalDouble w; + private final Transformer transformer; + + private OptionalVector4d(final OptionalDouble x, final OptionalDouble y, final OptionalDouble z, final OptionalDouble w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + if (this.x.isPresent()) { + final double x0 = this.x.getAsDouble(); + if (this.y.isPresent()) { + final double y0 = this.y.getAsDouble(); + if (this.z.isPresent()) { + final double z0 = this.z.getAsDouble(); + if (this.w.isPresent()) { + final double w0 = this.w.getAsDouble(); + this.transformer = (o, v) -> o.apply(x0, y0, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, y0, z0, v); + } + } else if (this.w.isPresent()) { + final double w0 = this.w.getAsDouble(); + this.transformer = (o, v) -> o.apply(x0, y0, v, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, y0, v, v); + } + } else if (this.z.isPresent()) { + final double z0 = this.z.getAsDouble(); + if (this.w.isPresent()) { + final double w0 = this.w.getAsDouble(); + this.transformer = (o, v) -> o.apply(x0, v, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, v, z0, v); + } + } else if (this.w.isPresent()) { + final double w0 = this.w.getAsDouble(); + this.transformer = (o, v) -> o.apply(x0, v, v, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, v, v, v); + } + } else if (this.y.isPresent()) { + final double y0 = this.y.getAsDouble(); + if (this.z.isPresent()) { + final double z0 = this.z.getAsDouble(); + if (this.w.isPresent()) { + final double w0 = this.w.getAsDouble(); + this.transformer = (o, v) -> o.apply(v, y0, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(v, y0, z0, v); + } + } else if (this.w.isPresent()) { + final double w0 = this.w.getAsDouble(); + this.transformer = (o, v) -> o.apply(v, y0, v, w0); + } else { + this.transformer = (o, v) -> o.apply(v, y0, v, v); + } + } else if (this.z.isPresent()) { + final double z0 = this.z.getAsDouble(); + if (this.w.isPresent()) { + final double w0 = this.w.getAsDouble(); + this.transformer = (o, v) -> o.apply(v, v, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(v, v, z0, v); + } + } else if (this.w.isPresent()) { + final double w0 = this.w.getAsDouble(); + this.transformer = (o, v) -> o.apply(v, v, v, w0); + } else { + this.transformer = (o, v) -> o; + } + } + + public OptionalDouble x() { + return this.x; + } + + public OptionalDouble y() { + return this.y; + } + + public OptionalDouble z() { + return this.z; + } + + public OptionalDouble w() { + return this.w; + } + + @SuppressWarnings("unchecked") + private V apply(final Operator operator, final double neutralValue) { + return (V) this.transformer.apply(operator, neutralValue); + } + + public MutableVector4d set(final MutableVector4d v) { + this.x.ifPresent(v::x); + this.y.ifPresent(v::y); + this.z.ifPresent(v::z); + this.w.ifPresent(v::w); + return v; + } + + public Vector4d set(final Vector4d v) { + final double x = this.x.orElse(v.x()); + final double y = this.y.orElse(v.y()); + final double z = this.z.orElse(v.z()); + final double w = this.w.orElse(v.w()); + return new Vector4d(x, y, z, w); + } + + public MutableVector4d add(final MutableVector4d v) { + return this.apply(v::add, 0); + } + + public Vector4d add(final Vector4d v) { + return this.apply(v::add, 0); + } + + public MutableVector4d sub(final MutableVector4d v) { + return this.apply(v::sub, 0); + } + + public Vector4d sub(final Vector4d v) { + return this.apply(v::sub, 0); + } + + public MutableVector4d mul(final MutableVector4d v) { + return this.apply(v::mul, 1); + } + + public Vector4d mul(final Vector4d v) { + return this.apply(v::mul, 1); + } + + public MutableVector4d div(final MutableVector4d v) { + return this.apply(v::div, 1); + } + + public Vector4d div(final Vector4d v) { + return this.apply(v::div, 1); + } + + public MutableVector4d pow(final MutableVector4d v) { + return this.apply(v::pow, 1); + } + + public Vector4d pow(final Vector4d v) { + final double x = Math.pow(v.x(), this.x.orElse(1)); + final double y = Math.pow(v.y(), this.y.orElse(1)); + final double z = Math.pow(v.z(), this.z.orElse(1)); + final double w = Math.pow(v.w(), this.w.orElse(1)); + return new Vector4d(x, y, z, w); + } + + public MutableVector4d min(final MutableVector4d v) { + return this.apply(v::min, Double.POSITIVE_INFINITY); + } + + public Vector4d min(final Vector4d v) { + return this.apply(v::min, Double.POSITIVE_INFINITY); + } + + public MutableVector4d max(final MutableVector4d v) { + return this.apply(v::max, Double.NEGATIVE_INFINITY); + } + + public Vector4d max(final Vector4d v) { + return this.apply(v::max, Double.NEGATIVE_INFINITY); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final OptionalVector4d that)) { + return false; + } else { + return this.x.equals(that.x) + && this.y.equals(that.y) + && this.z.equals(that.z) + && this.w.equals(that.w); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.x, this.y, this.z, this.w); + } + + @Override + public String toString() { + return "(" + + "x=" + (this.x.isPresent() ? this.x.getAsDouble() : "?") + + "y=" + (this.y.isPresent() ? this.y.getAsDouble() : "?") + + "z=" + (this.z.isPresent() ? this.z.getAsDouble() : "?") + + "w=" + (this.w.isPresent() ? this.w.getAsDouble() : "?") + + ")"; + } + + public static OptionalVector4d x(final double x) { + return OptionalVector4d.x(convert(x)); + } + + public static OptionalVector4d x(final @Nullable Double x) { + return OptionalVector4d.x(convert(x)); + } + + public static OptionalVector4d x(final Optional x) { + return OptionalVector4d.x(convert(x)); + } + + public static OptionalVector4d x(final OptionalDouble x) { + return OptionalVector4d.of(x, empty(), empty(), empty()); + } + + public static OptionalVector4d y(final double y) { + return OptionalVector4d.y(convert(y)); + } + + public static OptionalVector4d y(final @Nullable Double y) { + return OptionalVector4d.y(convert(y)); + } + + public static OptionalVector4d y(final Optional y) { + return OptionalVector4d.y(convert(y)); + } + + public static OptionalVector4d y(final OptionalDouble y) { + return OptionalVector4d.of(empty(), y, empty(), empty()); + } + + public static OptionalVector4d z(final double z) { + return OptionalVector4d.z(convert(z)); + } + + public static OptionalVector4d z(final @Nullable Double z) { + return OptionalVector4d.z(convert(z)); + } + + public static OptionalVector4d z(final Optional z) { + return OptionalVector4d.z(convert(z)); + } + + public static OptionalVector4d z(final OptionalDouble z) { + return OptionalVector4d.of(empty(), empty(), z, empty()); + } + + public static OptionalVector4d w(final double w) { + return OptionalVector4d.w(convert(w)); + } + + public static OptionalVector4d w(final @Nullable Double w) { + return OptionalVector4d.w(convert(w)); + } + + public static OptionalVector4d w(final Optional w) { + return OptionalVector4d.w(convert(w)); + } + + public static OptionalVector4d w(final OptionalDouble w) { + return OptionalVector4d.of(empty(), empty(), empty(), w); + } + + public static OptionalVector4d xy(final double x, final double y) { + return OptionalVector4d.xy(convert(x), convert(y)); + } + + public static OptionalVector4d xy(final @Nullable Double x, final @Nullable Double y) { + return OptionalVector4d.xy(convert(x), convert(y)); + } + + public static OptionalVector4d xy(final Optional x, final Optional y) { + return OptionalVector4d.xy(convert(x), convert(y)); + } + + public static OptionalVector4d xy(final OptionalDouble x, final OptionalDouble y) { + return OptionalVector4d.of(x, y, empty(), empty()); + } + + public static OptionalVector4d xz(final double x, final double z) { + return OptionalVector4d.xz(convert(x), convert(z)); + } + + public static OptionalVector4d xz(final @Nullable Double x, final @Nullable Double z) { + return OptionalVector4d.xz(convert(x), convert(z)); + } + + public static OptionalVector4d xz(final Optional x, final Optional z) { + return OptionalVector4d.xz(convert(x), convert(z)); + } + + public static OptionalVector4d xz(final OptionalDouble x, final OptionalDouble z) { + return OptionalVector4d.of(x, empty(), z, empty()); + } + + public static OptionalVector4d xw(final double x, final double w) { + return OptionalVector4d.xw(convert(x), convert(w)); + } + + public static OptionalVector4d xw(final @Nullable Double x, final @Nullable Double w) { + return OptionalVector4d.xw(convert(x), convert(w)); + } + + public static OptionalVector4d xw(final Optional x, final Optional w) { + return OptionalVector4d.xw(convert(x), convert(w)); + } + + public static OptionalVector4d xw(final OptionalDouble x, final OptionalDouble w) { + return OptionalVector4d.of(x, empty(), empty(), w); + } + + public static OptionalVector4d yz(final double y, final double z) { + return OptionalVector4d.yz(convert(y), convert(z)); + } + + public static OptionalVector4d yz(final @Nullable Double y, final @Nullable Double z) { + return OptionalVector4d.yz(convert(y), convert(z)); + } + + public static OptionalVector4d yz(final Optional y, final Optional z) { + return OptionalVector4d.yz(convert(y), convert(z)); + } + + public static OptionalVector4d yz(final OptionalDouble y, final OptionalDouble z) { + return OptionalVector4d.of(empty(), y, z, empty()); + } + + public static OptionalVector4d yw(final double y, final double w) { + return OptionalVector4d.yw(convert(y), convert(w)); + } + + public static OptionalVector4d yw(final @Nullable Double y, final @Nullable Double w) { + return OptionalVector4d.yw(convert(y), convert(w)); + } + + public static OptionalVector4d yw(final Optional y, final Optional w) { + return OptionalVector4d.yw(convert(y), convert(w)); + } + + public static OptionalVector4d yw(final OptionalDouble y, final OptionalDouble w) { + return OptionalVector4d.of(empty(), y, empty(), w); + } + + public static OptionalVector4d zw(final double z, final double w) { + return OptionalVector4d.zw(convert(z), convert(w)); + } + + public static OptionalVector4d zw(final @Nullable Double z, final @Nullable Double w) { + return OptionalVector4d.zw(convert(z), convert(w)); + } + + public static OptionalVector4d zw(final Optional z, final Optional w) { + return OptionalVector4d.zw(convert(z), convert(w)); + } + + public static OptionalVector4d zw(final OptionalDouble z, final OptionalDouble w) { + return OptionalVector4d.of(empty(), empty(), z, w); + } + + public static OptionalVector4d xyz(final double x, final double y, final double z) { + return OptionalVector4d.xyz(convert(x), convert(y), convert(z)); + } + + public static OptionalVector4d xyz(final @Nullable Double x, final @Nullable Double y, final @Nullable Double z) { + return OptionalVector4d.xyz(convert(x), convert(y), convert(z)); + } + + public static OptionalVector4d xyz(final Optional x, final Optional y, final Optional z) { + return OptionalVector4d.xyz(convert(x), convert(y), convert(z)); + } + + public static OptionalVector4d xyz(final OptionalDouble x, final OptionalDouble y, final OptionalDouble z) { + return OptionalVector4d.of(x, y, z, empty()); + } + + public static OptionalVector4d xyw(final double x, final double y, final double w) { + return OptionalVector4d.xyw(convert(x), convert(y), convert(w)); + } + + public static OptionalVector4d xyw(final @Nullable Double x, final @Nullable Double y, final @Nullable Double w) { + return OptionalVector4d.xyw(convert(x), convert(y), convert(w)); + } + + public static OptionalVector4d xyw(final Optional x, final Optional y, final Optional w) { + return OptionalVector4d.xyw(convert(x), convert(y), convert(w)); + } + + public static OptionalVector4d xyw(final OptionalDouble x, final OptionalDouble y, final OptionalDouble w) { + return OptionalVector4d.of(x, y, empty(), w); + } + + public static OptionalVector4d xzw(final double x, final double z, final double w) { + return OptionalVector4d.xzw(convert(x), convert(z), convert(w)); + } + + public static OptionalVector4d xzw(final @Nullable Double x, final @Nullable Double z, final @Nullable Double w) { + return OptionalVector4d.xzw(convert(x), convert(z), convert(w)); + } + + public static OptionalVector4d xzw(final Optional x, final Optional z, final Optional w) { + return OptionalVector4d.xzw(convert(x), convert(z), convert(w)); + } + + public static OptionalVector4d xzw(final OptionalDouble x, final OptionalDouble z, final OptionalDouble w) { + return OptionalVector4d.of(x, empty(), z, w); + } + + public static OptionalVector4d yzw(final double y, final double z, final double w) { + return OptionalVector4d.yzw(convert(y), convert(z), convert(w)); + } + + public static OptionalVector4d yzw(final @Nullable Double y, final @Nullable Double z, final @Nullable Double w) { + return OptionalVector4d.yzw(convert(y), convert(z), convert(w)); + } + + public static OptionalVector4d yzw(final Optional y, final Optional z, final Optional w) { + return OptionalVector4d.yzw(convert(y), convert(z), convert(w)); + } + + public static OptionalVector4d yzw(final OptionalDouble y, final OptionalDouble z, final OptionalDouble w) { + return OptionalVector4d.of(empty(), y, z, w); + } + + public static OptionalVector4d of(final double x, final double y, final double z, final double w) { + return OptionalVector4d.of(convert(x), convert(y), convert(z), convert(w)); + } + + public static OptionalVector4d of(final @Nullable Double x, final @Nullable Double y, final @Nullable Double z, final @Nullable Double w) { + return OptionalVector4d.of(convert(x), convert(y), convert(z), convert(w)); + } + + public static OptionalVector4d of(final Optional x, final Optional y, final Optional z, final Optional w) { + return OptionalVector4d.of(convert(x), convert(y), convert(z), convert(w)); + } + + public static OptionalVector4d of(final OptionalDouble x, final OptionalDouble y, final OptionalDouble z, final OptionalDouble w) { + return new OptionalVector4d(x, y, z, w); + } + + private static OptionalDouble empty() { + return OptionalDouble.empty(); + } + + private static OptionalDouble convert(final double a) { + return OptionalDouble.of(a); + } + + private static OptionalDouble convert(final @Nullable Double a) { + return a == null ? empty() : OptionalDouble.of(a.doubleValue()); + } + + private static OptionalDouble convert(final Optional a) { + return a.map(OptionalDouble::of).orElseGet(OptionalVector4d::empty); + } + + private interface Transformer { + + Object apply(Operator operator, double neutralValue); + } + + private interface Operator { + + V apply(double x, double y, double z, double w); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4i.java b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4i.java new file mode 100644 index 0000000..c7fa336 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4i.java @@ -0,0 +1,482 @@ +package net.hellheim.spongetools.math.optional.vector; + +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalInt; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector4i; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector4i; + +public final class OptionalVector4i { + + private final OptionalInt x; + private final OptionalInt y; + private final OptionalInt z; + private final OptionalInt w; + private final Transformer transformer; + + private OptionalVector4i(final OptionalInt x, final OptionalInt y, final OptionalInt z, final OptionalInt w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + if (this.x.isPresent()) { + final int x0 = this.x.getAsInt(); + if (this.y.isPresent()) { + final int y0 = this.y.getAsInt(); + if (this.z.isPresent()) { + final int z0 = this.z.getAsInt(); + if (this.w.isPresent()) { + final int w0 = this.w.getAsInt(); + this.transformer = (o, v) -> o.apply(x0, y0, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, y0, z0, v); + } + } else if (this.w.isPresent()) { + final int w0 = this.w.getAsInt(); + this.transformer = (o, v) -> o.apply(x0, y0, v, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, y0, v, v); + } + } else if (this.z.isPresent()) { + final int z0 = this.z.getAsInt(); + if (this.w.isPresent()) { + final int w0 = this.w.getAsInt(); + this.transformer = (o, v) -> o.apply(x0, v, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, v, z0, v); + } + } else if (this.w.isPresent()) { + final int w0 = this.w.getAsInt(); + this.transformer = (o, v) -> o.apply(x0, v, v, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, v, v, v); + } + } else if (this.y.isPresent()) { + final int y0 = this.y.getAsInt(); + if (this.z.isPresent()) { + final int z0 = this.z.getAsInt(); + if (this.w.isPresent()) { + final int w0 = this.w.getAsInt(); + this.transformer = (o, v) -> o.apply(v, y0, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(v, y0, z0, v); + } + } else if (this.w.isPresent()) { + final int w0 = this.w.getAsInt(); + this.transformer = (o, v) -> o.apply(v, y0, v, w0); + } else { + this.transformer = (o, v) -> o.apply(v, y0, v, v); + } + } else if (this.z.isPresent()) { + final int z0 = this.z.getAsInt(); + if (this.w.isPresent()) { + final int w0 = this.w.getAsInt(); + this.transformer = (o, v) -> o.apply(v, v, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(v, v, z0, v); + } + } else if (this.w.isPresent()) { + final int w0 = this.w.getAsInt(); + this.transformer = (o, v) -> o.apply(v, v, v, w0); + } else { + this.transformer = (o, v) -> o; + } + } + + public OptionalInt x() { + return this.x; + } + + public OptionalInt y() { + return this.y; + } + + public OptionalInt z() { + return this.z; + } + + public OptionalInt w() { + return this.w; + } + + @SuppressWarnings("unchecked") + private V apply(final Operator operator, final int neutralValue) { + return (V) this.transformer.apply(operator, neutralValue); + } + + public MutableVector4i set(final MutableVector4i v) { + this.x.ifPresent(v::x); + this.y.ifPresent(v::y); + this.z.ifPresent(v::z); + this.w.ifPresent(v::w); + return v; + } + + public Vector4i set(final Vector4i v) { + final int x = this.x.orElse(v.x()); + final int y = this.y.orElse(v.y()); + final int z = this.z.orElse(v.z()); + final int w = this.w.orElse(v.w()); + return new Vector4i(x, y, z, w); + } + + public MutableVector4i add(final MutableVector4i v) { + return this.apply(v::add, 0); + } + + public Vector4i add(final Vector4i v) { + return this.apply(v::add, 0); + } + + public MutableVector4i sub(final MutableVector4i v) { + return this.apply(v::sub, 0); + } + + public Vector4i sub(final Vector4i v) { + return this.apply(v::sub, 0); + } + + public MutableVector4i mul(final MutableVector4i v) { + return this.apply(v::mul, 1); + } + + public Vector4i mul(final Vector4i v) { + return this.apply(v::mul, 1); + } + + public MutableVector4i div(final MutableVector4i v) { + return this.apply(v::div, 1); + } + + public Vector4i div(final Vector4i v) { + return this.apply(v::div, 1); + } + + public MutableVector4i pow(final MutableVector4i v) { + return this.apply(v::pow, 1); + } + + public Vector4i pow(final Vector4i v) { + final int x = GenericMath.floor(Math.pow(v.x(), this.x.orElse(1))); + final int y = GenericMath.floor(Math.pow(v.y(), this.y.orElse(1))); + final int z = GenericMath.floor(Math.pow(v.z(), this.z.orElse(1))); + final int w = GenericMath.floor(Math.pow(v.w(), this.w.orElse(1))); + return new Vector4i(x, y, z, w); + } + + public MutableVector4i min(final MutableVector4i v) { + return this.apply(v::min, Integer.MAX_VALUE); + } + + public Vector4i min(final Vector4i v) { + return this.apply(v::min, Integer.MAX_VALUE); + } + + public MutableVector4i max(final MutableVector4i v) { + return this.apply(v::max, Integer.MIN_VALUE); + } + + public Vector4i max(final Vector4i v) { + return this.apply(v::max, Integer.MIN_VALUE); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final OptionalVector4i that)) { + return false; + } else { + return this.x.equals(that.x) + && this.y.equals(that.y) + && this.z.equals(that.z) + && this.w.equals(that.w); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.x, this.y, this.z, this.w); + } + + @Override + public String toString() { + return "(" + + "x=" + (this.x.isPresent() ? this.x.getAsInt() : "?") + + "y=" + (this.y.isPresent() ? this.y.getAsInt() : "?") + + "z=" + (this.z.isPresent() ? this.z.getAsInt() : "?") + + "w=" + (this.w.isPresent() ? this.w.getAsInt() : "?") + + ")"; + } + + public static OptionalVector4i x(final int x) { + return OptionalVector4i.x(convert(x)); + } + + public static OptionalVector4i x(final @Nullable Integer x) { + return OptionalVector4i.x(convert(x)); + } + + public static OptionalVector4i x(final Optional x) { + return OptionalVector4i.x(convert(x)); + } + + public static OptionalVector4i x(final OptionalInt x) { + return OptionalVector4i.of(x, empty(), empty(), empty()); + } + + public static OptionalVector4i y(final int y) { + return OptionalVector4i.y(convert(y)); + } + + public static OptionalVector4i y(final @Nullable Integer y) { + return OptionalVector4i.y(convert(y)); + } + + public static OptionalVector4i y(final Optional y) { + return OptionalVector4i.y(convert(y)); + } + + public static OptionalVector4i y(final OptionalInt y) { + return OptionalVector4i.of(empty(), y, empty(), empty()); + } + + public static OptionalVector4i z(final int z) { + return OptionalVector4i.z(convert(z)); + } + + public static OptionalVector4i z(final @Nullable Integer z) { + return OptionalVector4i.z(convert(z)); + } + + public static OptionalVector4i z(final Optional z) { + return OptionalVector4i.z(convert(z)); + } + + public static OptionalVector4i z(final OptionalInt z) { + return OptionalVector4i.of(empty(), empty(), z, empty()); + } + + public static OptionalVector4i w(final int w) { + return OptionalVector4i.w(convert(w)); + } + + public static OptionalVector4i w(final @Nullable Integer w) { + return OptionalVector4i.w(convert(w)); + } + + public static OptionalVector4i w(final Optional w) { + return OptionalVector4i.w(convert(w)); + } + + public static OptionalVector4i w(final OptionalInt w) { + return OptionalVector4i.of(empty(), empty(), empty(), w); + } + + public static OptionalVector4i xy(final int x, final int y) { + return OptionalVector4i.xy(convert(x), convert(y)); + } + + public static OptionalVector4i xy(final @Nullable Integer x, final @Nullable Integer y) { + return OptionalVector4i.xy(convert(x), convert(y)); + } + + public static OptionalVector4i xy(final Optional x, final Optional y) { + return OptionalVector4i.xy(convert(x), convert(y)); + } + + public static OptionalVector4i xy(final OptionalInt x, final OptionalInt y) { + return OptionalVector4i.of(x, y, empty(), empty()); + } + + public static OptionalVector4i xz(final int x, final int z) { + return OptionalVector4i.xz(convert(x), convert(z)); + } + + public static OptionalVector4i xz(final @Nullable Integer x, final @Nullable Integer z) { + return OptionalVector4i.xz(convert(x), convert(z)); + } + + public static OptionalVector4i xz(final Optional x, final Optional z) { + return OptionalVector4i.xz(convert(x), convert(z)); + } + + public static OptionalVector4i xz(final OptionalInt x, final OptionalInt z) { + return OptionalVector4i.of(x, empty(), z, empty()); + } + + public static OptionalVector4i xw(final int x, final int w) { + return OptionalVector4i.xw(convert(x), convert(w)); + } + + public static OptionalVector4i xw(final @Nullable Integer x, final @Nullable Integer w) { + return OptionalVector4i.xw(convert(x), convert(w)); + } + + public static OptionalVector4i xw(final Optional x, final Optional w) { + return OptionalVector4i.xw(convert(x), convert(w)); + } + + public static OptionalVector4i xw(final OptionalInt x, final OptionalInt w) { + return OptionalVector4i.of(x, empty(), empty(), w); + } + + public static OptionalVector4i yz(final int y, final int z) { + return OptionalVector4i.yz(convert(y), convert(z)); + } + + public static OptionalVector4i yz(final @Nullable Integer y, final @Nullable Integer z) { + return OptionalVector4i.yz(convert(y), convert(z)); + } + + public static OptionalVector4i yz(final Optional y, final Optional z) { + return OptionalVector4i.yz(convert(y), convert(z)); + } + + public static OptionalVector4i yz(final OptionalInt y, final OptionalInt z) { + return OptionalVector4i.of(empty(), y, z, empty()); + } + + public static OptionalVector4i yw(final int y, final int w) { + return OptionalVector4i.yw(convert(y), convert(w)); + } + + public static OptionalVector4i yw(final @Nullable Integer y, final @Nullable Integer w) { + return OptionalVector4i.yw(convert(y), convert(w)); + } + + public static OptionalVector4i yw(final Optional y, final Optional w) { + return OptionalVector4i.yw(convert(y), convert(w)); + } + + public static OptionalVector4i yw(final OptionalInt y, final OptionalInt w) { + return OptionalVector4i.of(empty(), y, empty(), w); + } + + public static OptionalVector4i zw(final int z, final int w) { + return OptionalVector4i.zw(convert(z), convert(w)); + } + + public static OptionalVector4i zw(final @Nullable Integer z, final @Nullable Integer w) { + return OptionalVector4i.zw(convert(z), convert(w)); + } + + public static OptionalVector4i zw(final Optional z, final Optional w) { + return OptionalVector4i.zw(convert(z), convert(w)); + } + + public static OptionalVector4i zw(final OptionalInt z, final OptionalInt w) { + return OptionalVector4i.of(empty(), empty(), z, w); + } + + public static OptionalVector4i xyz(final int x, final int y, final int z) { + return OptionalVector4i.xyz(convert(x), convert(y), convert(z)); + } + + public static OptionalVector4i xyz(final @Nullable Integer x, final @Nullable Integer y, final @Nullable Integer z) { + return OptionalVector4i.xyz(convert(x), convert(y), convert(z)); + } + + public static OptionalVector4i xyz(final Optional x, final Optional y, final Optional z) { + return OptionalVector4i.xyz(convert(x), convert(y), convert(z)); + } + + public static OptionalVector4i xyz(final OptionalInt x, final OptionalInt y, final OptionalInt z) { + return OptionalVector4i.of(x, y, z, empty()); + } + + public static OptionalVector4i xyw(final int x, final int y, final int w) { + return OptionalVector4i.xyw(convert(x), convert(y), convert(w)); + } + + public static OptionalVector4i xyw(final @Nullable Integer x, final @Nullable Integer y, final @Nullable Integer w) { + return OptionalVector4i.xyw(convert(x), convert(y), convert(w)); + } + + public static OptionalVector4i xyw(final Optional x, final Optional y, final Optional w) { + return OptionalVector4i.xyw(convert(x), convert(y), convert(w)); + } + + public static OptionalVector4i xyw(final OptionalInt x, final OptionalInt y, final OptionalInt w) { + return OptionalVector4i.of(x, y, empty(), w); + } + + public static OptionalVector4i xzw(final int x, final int z, final int w) { + return OptionalVector4i.xzw(convert(x), convert(z), convert(w)); + } + + public static OptionalVector4i xzw(final @Nullable Integer x, final @Nullable Integer z, final @Nullable Integer w) { + return OptionalVector4i.xzw(convert(x), convert(z), convert(w)); + } + + public static OptionalVector4i xzw(final Optional x, final Optional z, final Optional w) { + return OptionalVector4i.xzw(convert(x), convert(z), convert(w)); + } + + public static OptionalVector4i xzw(final OptionalInt x, final OptionalInt z, final OptionalInt w) { + return OptionalVector4i.of(x, empty(), z, w); + } + + public static OptionalVector4i yzw(final int y, final int z, final int w) { + return OptionalVector4i.yzw(convert(y), convert(z), convert(w)); + } + + public static OptionalVector4i yzw(final @Nullable Integer y, final @Nullable Integer z, final @Nullable Integer w) { + return OptionalVector4i.yzw(convert(y), convert(z), convert(w)); + } + + public static OptionalVector4i yzw(final Optional y, final Optional z, final Optional w) { + return OptionalVector4i.yzw(convert(y), convert(z), convert(w)); + } + + public static OptionalVector4i yzw(final OptionalInt y, final OptionalInt z, final OptionalInt w) { + return OptionalVector4i.of(empty(), y, z, w); + } + + public static OptionalVector4i of(final int x, final int y, final int z, final int w) { + return OptionalVector4i.of(convert(x), convert(y), convert(z), convert(w)); + } + + public static OptionalVector4i of(final @Nullable Integer x, final @Nullable Integer y, final @Nullable Integer z, final @Nullable Integer w) { + return OptionalVector4i.of(convert(x), convert(y), convert(z), convert(w)); + } + + public static OptionalVector4i of(final Optional x, final Optional y, final Optional z, final Optional w) { + return OptionalVector4i.of(convert(x), convert(y), convert(z), convert(w)); + } + + public static OptionalVector4i of(final OptionalInt x, final OptionalInt y, final OptionalInt z, final OptionalInt w) { + return new OptionalVector4i(x, y, z, w); + } + + private static OptionalInt empty() { + return OptionalInt.empty(); + } + + private static OptionalInt convert(final int a) { + return OptionalInt.of(a); + } + + private static OptionalInt convert(final @Nullable Integer a) { + return a == null ? empty() : OptionalInt.of(a.intValue()); + } + + private static OptionalInt convert(final Optional a) { + return a.map(OptionalInt::of).orElseGet(OptionalVector4i::empty); + } + + private interface Transformer { + + Object apply(Operator operator, int neutralValue); + } + + private interface Operator { + + V apply(int x, int y, int z, int w); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4l.java b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4l.java new file mode 100644 index 0000000..f3a56c8 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4l.java @@ -0,0 +1,482 @@ +package net.hellheim.spongetools.math.optional.vector; + +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalLong; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.math.GenericMath; +import org.spongepowered.math.vector.Vector4l; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector4l; + +public final class OptionalVector4l { + + private final OptionalLong x; + private final OptionalLong y; + private final OptionalLong z; + private final OptionalLong w; + private final Transformer transformer; + + private OptionalVector4l(final OptionalLong x, final OptionalLong y, final OptionalLong z, final OptionalLong w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + if (this.x.isPresent()) { + final long x0 = this.x.getAsLong(); + if (this.y.isPresent()) { + final long y0 = this.y.getAsLong(); + if (this.z.isPresent()) { + final long z0 = this.z.getAsLong(); + if (this.w.isPresent()) { + final long w0 = this.w.getAsLong(); + this.transformer = (o, v) -> o.apply(x0, y0, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, y0, z0, v); + } + } else if (this.w.isPresent()) { + final long w0 = this.w.getAsLong(); + this.transformer = (o, v) -> o.apply(x0, y0, v, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, y0, v, v); + } + } else if (this.z.isPresent()) { + final long z0 = this.z.getAsLong(); + if (this.w.isPresent()) { + final long w0 = this.w.getAsLong(); + this.transformer = (o, v) -> o.apply(x0, v, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, v, z0, v); + } + } else if (this.w.isPresent()) { + final long w0 = this.w.getAsLong(); + this.transformer = (o, v) -> o.apply(x0, v, v, w0); + } else { + this.transformer = (o, v) -> o.apply(x0, v, v, v); + } + } else if (this.y.isPresent()) { + final long y0 = this.y.getAsLong(); + if (this.z.isPresent()) { + final long z0 = this.z.getAsLong(); + if (this.w.isPresent()) { + final long w0 = this.w.getAsLong(); + this.transformer = (o, v) -> o.apply(v, y0, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(v, y0, z0, v); + } + } else if (this.w.isPresent()) { + final long w0 = this.w.getAsLong(); + this.transformer = (o, v) -> o.apply(v, y0, v, w0); + } else { + this.transformer = (o, v) -> o.apply(v, y0, v, v); + } + } else if (this.z.isPresent()) { + final long z0 = this.z.getAsLong(); + if (this.w.isPresent()) { + final long w0 = this.w.getAsLong(); + this.transformer = (o, v) -> o.apply(v, v, z0, w0); + } else { + this.transformer = (o, v) -> o.apply(v, v, z0, v); + } + } else if (this.w.isPresent()) { + final long w0 = this.w.getAsLong(); + this.transformer = (o, v) -> o.apply(v, v, v, w0); + } else { + this.transformer = (o, v) -> o; + } + } + + public OptionalLong x() { + return this.x; + } + + public OptionalLong y() { + return this.y; + } + + public OptionalLong z() { + return this.z; + } + + public OptionalLong w() { + return this.w; + } + + @SuppressWarnings("unchecked") + private V apply(final Operator operator, final long neutralValue) { + return (V) this.transformer.apply(operator, neutralValue); + } + + public MutableVector4l set(final MutableVector4l v) { + this.x.ifPresent(v::x); + this.y.ifPresent(v::y); + this.z.ifPresent(v::z); + this.w.ifPresent(v::w); + return v; + } + + public Vector4l set(final Vector4l v) { + final long x = this.x.orElse(v.x()); + final long y = this.y.orElse(v.y()); + final long z = this.z.orElse(v.z()); + final long w = this.w.orElse(v.w()); + return new Vector4l(x, y, z, w); + } + + public MutableVector4l add(final MutableVector4l v) { + return this.apply(v::add, 0); + } + + public Vector4l add(final Vector4l v) { + return this.apply(v::add, 0); + } + + public MutableVector4l sub(final MutableVector4l v) { + return this.apply(v::sub, 0); + } + + public Vector4l sub(final Vector4l v) { + return this.apply(v::sub, 0); + } + + public MutableVector4l mul(final MutableVector4l v) { + return this.apply(v::mul, 1); + } + + public Vector4l mul(final Vector4l v) { + return this.apply(v::mul, 1); + } + + public MutableVector4l div(final MutableVector4l v) { + return this.apply(v::div, 1); + } + + public Vector4l div(final Vector4l v) { + return this.apply(v::div, 1); + } + + public MutableVector4l pow(final MutableVector4l v) { + return this.apply(v::pow, 1); + } + + public Vector4l pow(final Vector4l v) { + final long x = GenericMath.floorl(Math.pow(v.x(), this.x.orElse(1))); + final long y = GenericMath.floorl(Math.pow(v.y(), this.y.orElse(1))); + final long z = GenericMath.floorl(Math.pow(v.z(), this.z.orElse(1))); + final long w = GenericMath.floorl(Math.pow(v.w(), this.w.orElse(1))); + return new Vector4l(x, y, z, w); + } + + public MutableVector4l min(final MutableVector4l v) { + return this.apply(v::min, Long.MAX_VALUE); + } + + public Vector4l min(final Vector4l v) { + return this.apply(v::min, Long.MAX_VALUE); + } + + public MutableVector4l max(final MutableVector4l v) { + return this.apply(v::max, Long.MIN_VALUE); + } + + public Vector4l max(final Vector4l v) { + return this.apply(v::max, Long.MIN_VALUE); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (!(other instanceof final OptionalVector4l that)) { + return false; + } else { + return this.x.equals(that.x) + && this.y.equals(that.y) + && this.z.equals(that.z) + && this.w.equals(that.w); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.x, this.y, this.z, this.w); + } + + @Override + public String toString() { + return "(" + + "x=" + (this.x.isPresent() ? this.x.getAsLong() : "?") + + "y=" + (this.y.isPresent() ? this.y.getAsLong() : "?") + + "z=" + (this.z.isPresent() ? this.z.getAsLong() : "?") + + "w=" + (this.w.isPresent() ? this.w.getAsLong() : "?") + + ")"; + } + + public static OptionalVector4l x(final long x) { + return OptionalVector4l.x(convert(x)); + } + + public static OptionalVector4l x(final @Nullable Long x) { + return OptionalVector4l.x(convert(x)); + } + + public static OptionalVector4l x(final Optional x) { + return OptionalVector4l.x(convert(x)); + } + + public static OptionalVector4l x(final OptionalLong x) { + return OptionalVector4l.of(x, empty(), empty(), empty()); + } + + public static OptionalVector4l y(final long y) { + return OptionalVector4l.y(convert(y)); + } + + public static OptionalVector4l y(final @Nullable Long y) { + return OptionalVector4l.y(convert(y)); + } + + public static OptionalVector4l y(final Optional y) { + return OptionalVector4l.y(convert(y)); + } + + public static OptionalVector4l y(final OptionalLong y) { + return OptionalVector4l.of(empty(), y, empty(), empty()); + } + + public static OptionalVector4l z(final long z) { + return OptionalVector4l.z(convert(z)); + } + + public static OptionalVector4l z(final @Nullable Long z) { + return OptionalVector4l.z(convert(z)); + } + + public static OptionalVector4l z(final Optional z) { + return OptionalVector4l.z(convert(z)); + } + + public static OptionalVector4l z(final OptionalLong z) { + return OptionalVector4l.of(empty(), empty(), z, empty()); + } + + public static OptionalVector4l w(final long w) { + return OptionalVector4l.w(convert(w)); + } + + public static OptionalVector4l w(final @Nullable Long w) { + return OptionalVector4l.w(convert(w)); + } + + public static OptionalVector4l w(final Optional w) { + return OptionalVector4l.w(convert(w)); + } + + public static OptionalVector4l w(final OptionalLong w) { + return OptionalVector4l.of(empty(), empty(), empty(), w); + } + + public static OptionalVector4l xy(final long x, final long y) { + return OptionalVector4l.xy(convert(x), convert(y)); + } + + public static OptionalVector4l xy(final @Nullable Long x, final @Nullable Long y) { + return OptionalVector4l.xy(convert(x), convert(y)); + } + + public static OptionalVector4l xy(final Optional x, final Optional y) { + return OptionalVector4l.xy(convert(x), convert(y)); + } + + public static OptionalVector4l xy(final OptionalLong x, final OptionalLong y) { + return OptionalVector4l.of(x, y, empty(), empty()); + } + + public static OptionalVector4l xz(final long x, final long z) { + return OptionalVector4l.xz(convert(x), convert(z)); + } + + public static OptionalVector4l xz(final @Nullable Long x, final @Nullable Long z) { + return OptionalVector4l.xz(convert(x), convert(z)); + } + + public static OptionalVector4l xz(final Optional x, final Optional z) { + return OptionalVector4l.xz(convert(x), convert(z)); + } + + public static OptionalVector4l xz(final OptionalLong x, final OptionalLong z) { + return OptionalVector4l.of(x, empty(), z, empty()); + } + + public static OptionalVector4l xw(final long x, final long w) { + return OptionalVector4l.xw(convert(x), convert(w)); + } + + public static OptionalVector4l xw(final @Nullable Long x, final @Nullable Long w) { + return OptionalVector4l.xw(convert(x), convert(w)); + } + + public static OptionalVector4l xw(final Optional x, final Optional w) { + return OptionalVector4l.xw(convert(x), convert(w)); + } + + public static OptionalVector4l xw(final OptionalLong x, final OptionalLong w) { + return OptionalVector4l.of(x, empty(), empty(), w); + } + + public static OptionalVector4l yz(final long y, final long z) { + return OptionalVector4l.yz(convert(y), convert(z)); + } + + public static OptionalVector4l yz(final @Nullable Long y, final @Nullable Long z) { + return OptionalVector4l.yz(convert(y), convert(z)); + } + + public static OptionalVector4l yz(final Optional y, final Optional z) { + return OptionalVector4l.yz(convert(y), convert(z)); + } + + public static OptionalVector4l yz(final OptionalLong y, final OptionalLong z) { + return OptionalVector4l.of(empty(), y, z, empty()); + } + + public static OptionalVector4l yw(final long y, final long w) { + return OptionalVector4l.yw(convert(y), convert(w)); + } + + public static OptionalVector4l yw(final @Nullable Long y, final @Nullable Long w) { + return OptionalVector4l.yw(convert(y), convert(w)); + } + + public static OptionalVector4l yw(final Optional y, final Optional w) { + return OptionalVector4l.yw(convert(y), convert(w)); + } + + public static OptionalVector4l yw(final OptionalLong y, final OptionalLong w) { + return OptionalVector4l.of(empty(), y, empty(), w); + } + + public static OptionalVector4l zw(final long z, final long w) { + return OptionalVector4l.zw(convert(z), convert(w)); + } + + public static OptionalVector4l zw(final @Nullable Long z, final @Nullable Long w) { + return OptionalVector4l.zw(convert(z), convert(w)); + } + + public static OptionalVector4l zw(final Optional z, final Optional w) { + return OptionalVector4l.zw(convert(z), convert(w)); + } + + public static OptionalVector4l zw(final OptionalLong z, final OptionalLong w) { + return OptionalVector4l.of(empty(), empty(), z, w); + } + + public static OptionalVector4l xyz(final long x, final long y, final long z) { + return OptionalVector4l.xyz(convert(x), convert(y), convert(z)); + } + + public static OptionalVector4l xyz(final @Nullable Long x, final @Nullable Long y, final @Nullable Long z) { + return OptionalVector4l.xyz(convert(x), convert(y), convert(z)); + } + + public static OptionalVector4l xyz(final Optional x, final Optional y, final Optional z) { + return OptionalVector4l.xyz(convert(x), convert(y), convert(z)); + } + + public static OptionalVector4l xyz(final OptionalLong x, final OptionalLong y, final OptionalLong z) { + return OptionalVector4l.of(x, y, z, empty()); + } + + public static OptionalVector4l xyw(final long x, final long y, final long w) { + return OptionalVector4l.xyw(convert(x), convert(y), convert(w)); + } + + public static OptionalVector4l xyw(final @Nullable Long x, final @Nullable Long y, final @Nullable Long w) { + return OptionalVector4l.xyw(convert(x), convert(y), convert(w)); + } + + public static OptionalVector4l xyw(final Optional x, final Optional y, final Optional w) { + return OptionalVector4l.xyw(convert(x), convert(y), convert(w)); + } + + public static OptionalVector4l xyw(final OptionalLong x, final OptionalLong y, final OptionalLong w) { + return OptionalVector4l.of(x, y, empty(), w); + } + + public static OptionalVector4l xzw(final long x, final long z, final long w) { + return OptionalVector4l.xzw(convert(x), convert(z), convert(w)); + } + + public static OptionalVector4l xzw(final @Nullable Long x, final @Nullable Long z, final @Nullable Long w) { + return OptionalVector4l.xzw(convert(x), convert(z), convert(w)); + } + + public static OptionalVector4l xzw(final Optional x, final Optional z, final Optional w) { + return OptionalVector4l.xzw(convert(x), convert(z), convert(w)); + } + + public static OptionalVector4l xzw(final OptionalLong x, final OptionalLong z, final OptionalLong w) { + return OptionalVector4l.of(x, empty(), z, w); + } + + public static OptionalVector4l yzw(final long y, final long z, final long w) { + return OptionalVector4l.yzw(convert(y), convert(z), convert(w)); + } + + public static OptionalVector4l yzw(final @Nullable Long y, final @Nullable Long z, final @Nullable Long w) { + return OptionalVector4l.yzw(convert(y), convert(z), convert(w)); + } + + public static OptionalVector4l yzw(final Optional y, final Optional z, final Optional w) { + return OptionalVector4l.yzw(convert(y), convert(z), convert(w)); + } + + public static OptionalVector4l yzw(final OptionalLong y, final OptionalLong z, final OptionalLong w) { + return OptionalVector4l.of(empty(), y, z, w); + } + + public static OptionalVector4l of(final long x, final long y, final long z, final long w) { + return OptionalVector4l.of(convert(x), convert(y), convert(z), convert(w)); + } + + public static OptionalVector4l of(final @Nullable Long x, final @Nullable Long y, final @Nullable Long z, final @Nullable Long w) { + return OptionalVector4l.of(convert(x), convert(y), convert(z), convert(w)); + } + + public static OptionalVector4l of(final Optional x, final Optional y, final Optional z, final Optional w) { + return OptionalVector4l.of(convert(x), convert(y), convert(z), convert(w)); + } + + public static OptionalVector4l of(final OptionalLong x, final OptionalLong y, final OptionalLong z, final OptionalLong w) { + return new OptionalVector4l(x, y, z, w); + } + + private static OptionalLong empty() { + return OptionalLong.empty(); + } + + private static OptionalLong convert(final long a) { + return OptionalLong.of(a); + } + + private static OptionalLong convert(final @Nullable Long a) { + return a == null ? empty() : OptionalLong.of(a.longValue()); + } + + private static OptionalLong convert(final Optional a) { + return a.map(OptionalLong::of).orElseGet(OptionalVector4l::empty); + } + + private interface Transformer { + + Object apply(Operator operator, long neutralValue); + } + + private interface Operator { + + V apply(long x, long y, long z, long w); + } +} diff --git a/src/main/java/net/hellheim/spongetools/object/OptionalRotation.java b/src/main/java/net/hellheim/spongetools/object/OptionalRotation.java index 6232ccc..71f58fc 100644 --- a/src/main/java/net/hellheim/spongetools/object/OptionalRotation.java +++ b/src/main/java/net/hellheim/spongetools/object/OptionalRotation.java @@ -1,37 +1,41 @@ package net.hellheim.spongetools.object; -import java.util.Optional; +import java.util.Objects; +import java.util.OptionalDouble; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.entity.Entity; import org.spongepowered.math.vector.Vector3d; -public class OptionalRotation extends OptionalVector3d { +import net.hellheim.spongetools.math.optional.vector.OptionalVector3d; + +public record OptionalRotation(OptionalVector3d rotation) { - protected OptionalRotation( - final Optional pitch, final Optional yaw, final Optional roll - ) { - super(pitch, yaw, roll); + public OptionalRotation(final OptionalVector3d rotation) { + this.rotation = Objects.requireNonNull(rotation, "rotation"); } - public static Builder builder() { - return new Builder(); + public static OptionalRotation of(final OptionalVector3d rotation) { + return new OptionalRotation(rotation); } public static OptionalRotation ofPitch(final double pitch) { - return OptionalRotation.builder().pitch(pitch).build(); + return OptionalRotation.of(OptionalVector3d.x(pitch)); } public static OptionalRotation ofYaw(final double yaw) { - return OptionalRotation.builder().yaw(yaw).build(); + return OptionalRotation.of(OptionalVector3d.y(yaw)); } public static OptionalRotation of(final double pitch, final double yaw) { - return OptionalRotation.builder().pitch(pitch).yaw(yaw).build(); + return OptionalRotation.of(OptionalVector3d.xy(pitch, yaw)); } public static OptionalRotation of(final double pitch, final double yaw, final double roll) { - return OptionalRotation.builder().pitch(pitch).yaw(yaw).roll(roll).build(); + return OptionalRotation.of(OptionalVector3d.of(pitch, yaw, roll)); + } + + public Vector3d transform(final Vector3d rotation) { + return this.rotation.set(rotation); } public Vector3d transform(final Entity entity) { @@ -42,63 +46,15 @@ public void apply(final Entity entity) { entity.setRotation(this.transform(entity)); } - public Optional pitch() { - return this.x; - } - - public Optional yaw() { - return this.y; + public OptionalDouble pitch() { + return this.rotation.x(); } - public Optional roll() { - return this.z; + public OptionalDouble yaw() { + return this.rotation.y(); } - public static class Builder extends OptionalVector3d.Builder { - - @Override - public Builder x(final @Nullable Double x) { - super.x(x); - return this; - } - - @Override - public Builder y(final @Nullable Double y) { - super.y(y); - return this; - } - - @Override - public Builder z(final @Nullable Double z) { - super.z(z); - return this; - } - - public Builder pitch(final @Nullable Double pitch) { - return this.x(pitch); - } - - public Builder yaw(final @Nullable Double yaw) { - return this.y(yaw); - } - - public Builder roll(final @Nullable Double roll) { - return this.z(roll); - } - - @Override - public Builder reset() { - super.reset(); - return this; - } - - @Override - public OptionalRotation build() { - return new OptionalRotation( - Optional.ofNullable(this.x), - Optional.ofNullable(this.y), - Optional.ofNullable(this.z) - ); - } + public OptionalDouble roll() { + return this.rotation.z(); } } diff --git a/src/main/java/net/hellheim/spongetools/object/OptionalVector3d.java b/src/main/java/net/hellheim/spongetools/object/OptionalVector3d.java deleted file mode 100644 index bd7ab6c..0000000 --- a/src/main/java/net/hellheim/spongetools/object/OptionalVector3d.java +++ /dev/null @@ -1,146 +0,0 @@ -package net.hellheim.spongetools.object; - -import java.util.Optional; -import java.util.function.UnaryOperator; - -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.math.vector.Vector3d; - -public class OptionalVector3d { - - protected final Optional x; - protected final Optional y; - protected final Optional z; - protected final UnaryOperator transformer; - - protected OptionalVector3d( - final Optional x, final Optional y, final Optional z - ) { - this.x = x; - this.y = y; - this.z = z; - - if (x.isPresent()) { - if (y.isPresent()) { - if (z.isPresent()) { - final double x0 = x.get(), y0 = y.get(), z0 = z.get(); - final Vector3d result = new Vector3d(x0, y0, z0); - this.transformer = v -> result; - } else { - final double x0 = x.get(), y0 = y.get(); - this.transformer = v -> new Vector3d(x0, y0, v.z()); - } - } else if (z.isPresent()) { - final double x0 = x.get(), z0 = z.get(); - this.transformer = v -> new Vector3d(x0, v.y(), z0); - } else { - final double x0 = x.get(); - this.transformer = v -> new Vector3d(x0, v.y(), v.z()); - } - } else if (y.isPresent()) { - if (z.isPresent()) { - final double y0 = y.get(), z0 = z.get(); - this.transformer = v -> new Vector3d(v.x(), y0, z0); - } else { - final double y0 = y.get(); - this.transformer = v -> new Vector3d(v.x(), y0, v.z()); - } - } else if (z.isPresent()) { - final double z0 = z.get(); - this.transformer = v -> new Vector3d(v.x(), v.y(), z0); - } else { - this.transformer = v -> v; - } - } - - public static Builder builder() { - return new Builder(); - } - - public static OptionalVector3d empty() { - return OptionalVector3d.builder().build(); - } - - public static OptionalVector3d x(final double x) { - return OptionalVector3d.builder().x(x).build(); - } - - public static OptionalVector3d y(final double y) { - return OptionalVector3d.builder().y(y).build(); - } - - public static OptionalVector3d z(final double z) { - return OptionalVector3d.builder().z(z).build(); - } - - public static OptionalVector3d xy(final double x, final double y) { - return OptionalVector3d.builder().x(x).y(y).build(); - } - - public static OptionalVector3d xz(final double x, final double z) { - return OptionalVector3d.builder().x(x).z(z).build(); - } - - public static OptionalVector3d yz(final double y, final double z) { - return OptionalVector3d.builder().y(y).z(z).build(); - } - - public static OptionalVector3d xyz(final double x, final double y, final double z) { - return OptionalVector3d.builder().x(x).y(y).z(z).build(); - } - - public Vector3d transform(final Vector3d v) { - return this.transformer.apply(v); - } - - public Optional x() { - return this.x; - } - - public Optional y() { - return this.y; - } - - public Optional z() { - return this.z; - } - - public static class Builder implements org.spongepowered.api.util.Builder { - - protected @Nullable Double x; - protected @Nullable Double y; - protected @Nullable Double z; - - public Builder x(final @Nullable Double x) { - this.x = x; - return this; - } - - public Builder y(final @Nullable Double y) { - this.y = y; - return this; - } - - public Builder z(final @Nullable Double z) { - this.z = z; - return this; - } - - @Override - public Builder reset() { - this.x = null; - this.y = null; - this.z = null; - return this; - } - - @Override - public OptionalVector3d build() { - return new OptionalVector3d( - Optional.ofNullable(this.x), - Optional.ofNullable(this.y), - Optional.ofNullable(this.z) - ); - } - } -} diff --git a/src/main/java/net/hellheim/spongetools/object/Streamable.java b/src/main/java/net/hellheim/spongetools/object/Streamable.java new file mode 100644 index 0000000..f61ba59 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/object/Streamable.java @@ -0,0 +1,70 @@ +package net.hellheim.spongetools.object; + +import java.util.Iterator; +import java.util.Objects; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import com.google.common.collect.Streams; + +public interface Streamable extends Iterable { + + Stream stream(); + + static Streamable stream(final Supplier> streamSupplier) { + Objects.requireNonNull(streamSupplier, "streamSupplier"); + return new Streamable() { + @Override + public Stream stream() { + return streamSupplier.get(); + } + + @Override + public Iterator iterator() { + return this.stream().iterator(); + } + + @Override + public Spliterator spliterator() { + return this.stream().spliterator(); + } + + @Override + public void forEach(Consumer action) { + this.stream().forEach(action); + } + }; + } + + static Streamable iterator(final Supplier> iteratorSupplier) { + Objects.requireNonNull(iteratorSupplier, "iteratorSupplier"); + return new Streamable() { + @Override + public Iterator iterator() { + return iteratorSupplier.get(); + } + + @Override + public Stream stream() { + return Streams.stream(this.iterator()); + } + }; + } + + static Streamable iterable(final Iterable iterable) { + Objects.requireNonNull(iterable, "iterable"); + return new Streamable() { + @Override + public Iterator iterator() { + return iterable.iterator(); + } + + @Override + public Stream stream() { + return Streams.stream(iterable); + } + }; + } +} diff --git a/src/main/java/net/hellheim/spongetools/util/GeomUtil.java b/src/main/java/net/hellheim/spongetools/util/GeomUtil.java index df30f2d..3031778 100644 --- a/src/main/java/net/hellheim/spongetools/util/GeomUtil.java +++ b/src/main/java/net/hellheim/spongetools/util/GeomUtil.java @@ -25,6 +25,8 @@ import net.hellheim.spongetools.function.IntBiConsumer; import net.hellheim.spongetools.function.IntTriConsumer; +import net.hellheim.spongetools.math.mutable.vector.MutableVector3i; +import net.hellheim.spongetools.object.Streamable; public final class GeomUtil { @@ -365,17 +367,14 @@ public static void forEachInCircle(final int x0, final int y0, final int radius, } } - public static void forEachCardinalNeighbour(final Vector3i pos, final IntTriConsumer action) { - GeomUtil.forEachCardinalNeighbour(pos.x(), pos.y(), pos.z(), action); + public static Streamable cardinalNeighbours(final Vector3i pos) { + return GeomUtil.cardinalNeighbours(pos.x(), pos.y(), pos.z()); } - public static void forEachCardinalNeighbour(final int x, final int y, final int z, final IntTriConsumer action) { - action.accept(x, y, z + 1); - action.accept(x, y, z - 1); - action.accept(x, y + 1, z); - action.accept(x, y - 1, z); - action.accept(x + 1, y, z); - action.accept(x - 1, y, z); + public static Streamable cardinalNeighbours(final int x, final int y, final int z) { + final MutableVector3i cursor = MutableVector3i.zero(); + return Streamable.stream(() -> GeomUtil.cardinalDirections().stream() + .map(dir -> cursor.set(x, y, z).add(dir.asBlockOffset()))); } private GeomUtil() { From a9d14fa4ac999493d6a2cfbc406f5539d5cec197 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Sun, 5 Oct 2025 23:19:42 +0300 Subject: [PATCH 20/55] continue custom stuff --- .../net/hellheim/spongetools/SpongeTools.java | 10 + .../codec/list/RegistryCodecs.java | 15 +- .../spongetools/codec/list/SpongeCodecs.java | 8 +- .../behaviour/BehaviourCallbackHolder.java | 2 +- .../behaviour/tag/TaggableInstance.java | 10 +- .../behaviour/type/BlockStateBehaviours.java | 11 + .../spongetools/custom/type/EitherType.java | 171 +++++++++- .../type/block/BasicCustomBlockType.java | 12 +- .../custom/type/block/BlockStateProvider.java | 11 +- .../custom/type/block/CustomBlockType.java | 15 + .../type/block/CustomBlockTypePresets.java | 6 +- .../type/block/CustomBlockTypeProperties.java | 2 +- .../custom/type/item/CustomIngredients.java | 156 ++++++++++ .../custom/type/item/CustomItemType.java | 47 ++- .../type/item/CustomItemTypeProperties.java | 56 ++-- .../custom/type/item/DeferredItemType.java | 7 +- .../custom/type/item/EitherItemType.java | 16 +- .../type/item/IDefaultedCustomItemType.java | 14 +- .../custom/type/item/IconProxy.java | 30 -- .../custom/type/item/LoreProcessor.java | 272 ++++++++++++++++ .../custom/type/item/LoreProvider.java | 107 +++++++ .../math/set/CardinalNeighbourShape.java | 22 ++ .../math/set/CountableVectorSet.java | 82 +++++ .../spongetools/math/set/Ellipse.java | 89 ++++++ .../spongetools/math/set/Ellipsoid.java | 43 +++ .../spongetools/math/set/Manhattan2.java | 98 ++++++ .../spongetools/math/set/Manhattan3.java | 119 +++++++ .../hellheim/spongetools/math/set/Shapes.java | 34 ++ .../net/hellheim/spongetools/menu/Menu.java | 134 +------- .../hellheim/spongetools/menu/MenuKey.java | 16 - .../object/AttributeModifierTemplate.java | 40 +++ .../spongetools/object/DataOperator.java | 77 ++++- .../spongetools/object/ItemBuilder.java | 2 +- .../spongetools/object/Streamable.java | 292 ++++++++++++++++-- .../hellheim/spongetools/object/TypedKey.java | 53 ++++ .../spongetools/object/TypedKeyMap.java | 286 +++++++++++++++++ .../spongetools/object/ValueSetBuilder.java | 66 +++- .../resourcepack/ModelPartFace.java | 10 +- .../resourcepack/ModelPartRotation.java | 2 +- .../resourcepack/block/VariantProperties.java | 4 +- .../resourcepack/block/VariantProperty.java | 2 + .../resourcepack/item/SelectProperty.java | 2 +- .../hellheim/spongetools/util/CompUtil.java | 1 + .../hellheim/spongetools/util/EffectUtil.java | 55 ++++ .../hellheim/spongetools/util/EventUtil.java | 47 ++- .../hellheim/spongetools/util/GeomUtil.java | 30 +- .../hellheim/spongetools/util/ItemUtil.java | 5 +- 47 files changed, 2265 insertions(+), 324 deletions(-) create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/item/CustomIngredients.java delete mode 100644 src/main/java/net/hellheim/spongetools/custom/type/item/IconProxy.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java create mode 100644 src/main/java/net/hellheim/spongetools/math/set/CardinalNeighbourShape.java create mode 100644 src/main/java/net/hellheim/spongetools/math/set/CountableVectorSet.java create mode 100644 src/main/java/net/hellheim/spongetools/math/set/Ellipse.java create mode 100644 src/main/java/net/hellheim/spongetools/math/set/Ellipsoid.java create mode 100644 src/main/java/net/hellheim/spongetools/math/set/Manhattan2.java create mode 100644 src/main/java/net/hellheim/spongetools/math/set/Manhattan3.java create mode 100644 src/main/java/net/hellheim/spongetools/math/set/Shapes.java delete mode 100644 src/main/java/net/hellheim/spongetools/menu/MenuKey.java create mode 100644 src/main/java/net/hellheim/spongetools/object/AttributeModifierTemplate.java create mode 100644 src/main/java/net/hellheim/spongetools/object/TypedKey.java create mode 100644 src/main/java/net/hellheim/spongetools/object/TypedKeyMap.java diff --git a/src/main/java/net/hellheim/spongetools/SpongeTools.java b/src/main/java/net/hellheim/spongetools/SpongeTools.java index 102fddc..6fef72a 100644 --- a/src/main/java/net/hellheim/spongetools/SpongeTools.java +++ b/src/main/java/net/hellheim/spongetools/SpongeTools.java @@ -15,6 +15,8 @@ import net.hellheim.spongetools.custom.type.block.EitherBlockType; import net.hellheim.spongetools.custom.type.item.CustomItemType; import net.hellheim.spongetools.custom.type.item.EitherItemType; +import net.hellheim.spongetools.custom.type.item.LoreProcessor; +import net.hellheim.spongetools.custom.type.item.LoreProvider; import net.hellheim.spongetools.custom.type.item.data.CustomConsumeEffect; import net.hellheim.spongetools.resourcepack.Model; import net.hellheim.spongetools.resourcepack.block.BlockDefinition; @@ -53,6 +55,10 @@ public static final class Registries { */ public static final DefaultedRegistryType MODEL = Registries.key("models"); + public static final DefaultedRegistryType> LORE_PROCESSOR_TYPE = Registries.key("lore_processor_type"); + + public static final DefaultedRegistryType> LORE_PROVIDER_TYPE = Registries.key("lore_provider_type"); + public static final DefaultedRegistryType> CONSUME_EFFECT_TYPE = Registries.key("consume_effect_type"); private static DefaultedRegistryType key(final String key) { @@ -67,6 +73,10 @@ public static final class Keys { public static final Key> ITEM_TYPE = Keys.key("item", CustomItemType.class); + public static final Key> LORE_PROCESSOR = Keys.key("lore_processor", LoreProcessor.class); + + public static final Key> LORE_PROVIDERS = Keys.listKey("lore_providers", LoreProvider.class); + public static final Key> CONSUME_EFFECTS = Keys.listKey("consume_effects", CustomConsumeEffect.class); private static Key> key(final String key, final Class type) { diff --git a/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java b/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java index 1b54cfe..4803366 100644 --- a/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java +++ b/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java @@ -76,7 +76,6 @@ import org.spongepowered.api.effect.potion.PotionEffectType; import org.spongepowered.api.effect.sound.SoundType; import org.spongepowered.api.effect.sound.music.MusicDisc; -import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.EntityCategory; import org.spongepowered.api.entity.EntityType; import org.spongepowered.api.entity.ai.goal.GoalExecutorType; @@ -177,6 +176,8 @@ import net.hellheim.spongetools.custom.type.block.EitherBlockType; import net.hellheim.spongetools.custom.type.item.CustomItemType; import net.hellheim.spongetools.custom.type.item.EitherItemType; +import net.hellheim.spongetools.custom.type.item.LoreProcessor; +import net.hellheim.spongetools.custom.type.item.LoreProvider; import net.hellheim.spongetools.custom.type.item.data.CustomConsumeEffect; import net.hellheim.spongetools.resourcepack.Model; import net.hellheim.spongetools.resourcepack.block.BlockDefinition; @@ -203,6 +204,10 @@ public final class RegistryCodecs { public static final Codec MODEL = RegistryCodecs.register(Model.class, Model.registry()); + public static final Codec> LORE_PROCESSOR_TYPE = RegistryCodecs.of(SpongeTools.Registries.LORE_PROCESSOR_TYPE); + + public static final Codec> LORE_PROVIDER_TYPE = RegistryCodecs.of(SpongeTools.Registries.LORE_PROVIDER_TYPE); + public static final Codec> CUSTOM_CONSUME_EFFECT_TYPE = RegistryCodecs.of(SpongeTools.Registries.CONSUME_EFFECT_TYPE); // SpongeAPI @@ -239,7 +244,7 @@ public final class RegistryCodecs { public static final Codec ENTITY_CATEGORY = RegistryCodecs.register(EntityCategory.class, RegistryTypes.ENTITY_CATEGORY); - public static final Codec> ENTITY_TYPE = RegistryCodecs.register(EntityType.class, RegistryTypes.ENTITY_TYPE); + public static final Codec> ENTITY_TYPE = RegistryCodecs.register(EntityType.class, RegistryTypes.ENTITY_TYPE); public static final Codec FEATURE = RegistryCodecs.register(Feature.class, RegistryTypes.FEATURE); @@ -273,7 +278,7 @@ public final class RegistryCodecs { public static final Codec POTION_TYPE = RegistryCodecs.register(PotionType.class, RegistryTypes.POTION_TYPE); - public static final Codec>> RECIPE_TYPE = RegistryCodecs.register(RecipeType.class, RegistryTypes.RECIPE_TYPE); + public static final Codec> RECIPE_TYPE = RegistryCodecs.register(RecipeType.class, RegistryTypes.RECIPE_TYPE); public static final Codec SOUND_TYPE = RegistryCodecs.register(SoundType.class, RegistryTypes.SOUND_TYPE); @@ -287,7 +292,7 @@ public final class RegistryCodecs { public static final Codec STRUCTURE_TYPE = RegistryCodecs.register(StructureType.class, RegistryTypes.STRUCTURE_TYPE); - public static final Codec> TRIGGER = RegistryCodecs.register(Trigger.class, RegistryTypes.TRIGGER); + public static final Codec> TRIGGER = RegistryCodecs.register(Trigger.class, RegistryTypes.TRIGGER); public static final Codec TRIM_MATERIAL = RegistryCodecs.register(TrimMaterial.class, RegistryTypes.TRIM_MATERIAL); @@ -339,7 +344,7 @@ public final class RegistryCodecs { public static final Codec> COMMAND_REGISTRAR_TYPE = RegistryCodecs.register(CommandRegistrarType.class, RegistryTypes.COMMAND_REGISTRAR_TYPE); - public static final Codec> COMMAND_TREE_NODE_TYPE = RegistryCodecs.register(CommandTreeNodeType.class, RegistryTypes.COMMAND_TREE_NODE_TYPE); + public static final Codec> COMMAND_TREE_NODE_TYPE = RegistryCodecs.register(CommandTreeNodeType.class, RegistryTypes.COMMAND_TREE_NODE_TYPE); public static final Codec COMPARATOR_MODE = RegistryCodecs.register(ComparatorMode.class, RegistryTypes.COMPARATOR_MODE); diff --git a/src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java b/src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java index 442dc81..0647168 100644 --- a/src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java +++ b/src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java @@ -44,13 +44,13 @@ public final class SpongeCodecs { public static final Codec ROTATION_BY_ANGLE = Codec.INT.flatXmap( angle -> { if (angle == 0) { - return DataResult.success(GeomUtil.ROT_0); + return DataResult.success(GeomUtil.ROT_0.get()); } else if (angle == 90) { - return DataResult.success(GeomUtil.ROT_90); + return DataResult.success(GeomUtil.ROT_90.get()); } else if (angle == 180) { - return DataResult.success(GeomUtil.ROT_180); + return DataResult.success(GeomUtil.ROT_180.get()); } else if (angle == 270) { - return DataResult.success(GeomUtil.ROT_270); + return DataResult.success(GeomUtil.ROT_270.get()); } else { return DataResult.error(() -> "Rotation angle must be 0, 90, 180 or 270: " + angle); } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java index 920fde1..e6e38f0 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java @@ -131,7 +131,7 @@ default M set( * @param value The value to return * @return This modifiable behaviour, for chaining */ - default M set( + default M supply( final BehaviourType> type, final Supplier valueSupplier ) { Objects.requireNonNull(valueSupplier, "valueSupplier"); diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java index a532730..6e265f8 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java @@ -2,6 +2,8 @@ import java.util.stream.Stream; +import org.spongepowered.api.registry.DefaultedRegistryType; +import org.spongepowered.api.tag.DefaultedTag; import org.spongepowered.api.tag.Tag; import org.spongepowered.api.tag.Taggable; @@ -10,19 +12,21 @@ public interface TaggableInstance> { T taggedType(); + DefaultedRegistryType taggedRegistry(); + Stream> tags(); - boolean is(Tag tag); + boolean is(DefaultedTag tag); interface Defaulted> extends TaggableInstance { @Override default Stream> tags() { - return this.taggedType().tags().stream(); + return this.taggedType().tags(this.taggedRegistry()); } @Override - default boolean is(final Tag tag) { + default boolean is(final DefaultedTag tag) { return this.taggedType().is(tag); } } diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java index e7abd0f..112dea1 100644 --- a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java +++ b/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java @@ -1,5 +1,7 @@ package net.hellheim.spongetools.custom.behaviour.type; +import java.util.Optional; + import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; import org.spongepowered.api.block.BlockTypes; @@ -13,6 +15,7 @@ import org.spongepowered.api.map.color.MapColorType; import org.spongepowered.api.util.AABB; import org.spongepowered.api.world.World; +import org.spongepowered.api.world.WorldLike; import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; import org.spongepowered.api.world.volume.game.Region; import org.spongepowered.api.world.volume.game.UpdatableVolume; @@ -33,6 +36,7 @@ import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.Tick; import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.UseWithItem; import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour.UseWithoutItem; +import net.kyori.adventure.sound.Sound; public final class BlockStateBehaviours { @@ -179,6 +183,13 @@ public final class BlockStateBehaviours { */ public static final BehaviourType CLONE_ITEM = BehaviourType.create(); + /** + * TODO Can do something and return item filled "bucket". + */ + public static final BehaviourType, Optional>> BUCKET_PICKUP_ITEM = BehaviourType.create(); + + public static final BehaviourType>> BUCKET_PICKUP_SOUND = BehaviourType.create(); + private BlockStateBehaviours() { } } diff --git a/src/main/java/net/hellheim/spongetools/custom/type/EitherType.java b/src/main/java/net/hellheim/spongetools/custom/type/EitherType.java index 7015a57..6eb5311 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/EitherType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/EitherType.java @@ -1,23 +1,54 @@ package net.hellheim.spongetools.custom.type; +import java.util.Arrays; +import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; +import com.google.common.collect.Streams; import com.mojang.datafixers.util.Either; +@SuppressWarnings("unchecked") public interface EitherType> { + Optional common(); + + Optional custom(); + + Either either(); + boolean isCommon(); + boolean isCommon(COMMON common); + + boolean isCommon(Supplier commonSupplier); + + boolean isAnyCommon(final COMMON... commons); + + boolean isAnyCommon(final Supplier... commonSuppliers); + + boolean isAnyCommon(final Iterable commonIterable); + boolean isCustom(); - Optional common(); + boolean isCustom(CUSTOM custom); - Optional custom(); + boolean isCustom(Supplier customSupplier); - Either either(); + boolean isAnyCustom(final CUSTOM... customs); + + boolean isAnyCustom(final Supplier... customSuppliers); + + boolean isAnyCustom(final Iterable customIterable); + + boolean is(EITHER either); + + default boolean isAny(final EITHER... eithers) { + return Arrays.stream(eithers).anyMatch(this::is); + } default EITHER mapCommon(final Function commonMapper) { return this.map(commonMapper, Function.identity()); @@ -45,29 +76,84 @@ interface Common common() { + return Optional.of(this.get()); + } + + @Override + default Optional custom() { + return Optional.empty(); + } + + @Override + default Either either() { + return Either.left(this.get()); + } + @Override default boolean isCommon() { return true; } + @Override + default boolean isCommon(final COMMON common) { + return Objects.equals(this.get(), common); + } + + @Override + default boolean isCommon(final Supplier commonSupplier) { + return this.isCommon(commonSupplier.get()); + } + + @Override + default boolean isAnyCommon(final COMMON... commons) { + return Arrays.stream(commons).anyMatch(this::isCommon); + } + + @Override + default boolean isAnyCommon(final Supplier... commonSuppliers) { + return Arrays.stream(commonSuppliers).map(Supplier::get).anyMatch(this::isCommon); + } + + @Override + default boolean isAnyCommon(final Iterable commonIterable) { + return Streams.stream(commonIterable).anyMatch(this::isCommon); + } + @Override default boolean isCustom() { return false; } @Override - default Optional common() { - return Optional.of(this.get()); + default boolean isCustom(final CUSTOM custom) { + return false; } @Override - default Optional custom() { - return Optional.empty(); + default boolean isCustom(final Supplier customSupplier) { + return false; } @Override - default Either either() { - return Either.left(this.get()); + default boolean isAnyCustom(final CUSTOM... customs) { + return false; + } + + @Override + default boolean isAnyCustom(final Supplier... customSuppliers) { + return false; + } + + @Override + default boolean isAnyCustom(final Iterable customIterable) { + return false; + } + + @Override + default boolean is(final EITHER either) { + return either.isCommon(this.get()); } @Override @@ -99,29 +185,84 @@ interface Custom common() { + return Optional.empty(); + } + + @Override + default Optional custom() { + return Optional.of(this.get()); + } + + @Override + default Either either() { + return Either.right(this.get()); + } + @Override default boolean isCommon() { return false; } + @Override + default boolean isCommon(final COMMON common) { + return false; + } + + @Override + default boolean isCommon(final Supplier commonSupplier) { + return false; + } + + @Override + default boolean isAnyCommon(final COMMON... commons) { + return false; + } + + @Override + default boolean isAnyCommon(final Supplier... commonSuppliers) { + return false; + } + + @Override + default boolean isAnyCommon(final Iterable commonIterable) { + return false; + } + @Override default boolean isCustom() { return true; } @Override - default Optional common() { - return Optional.empty(); + default boolean isCustom(final CUSTOM custom) { + return Objects.equals(this.get(), custom); } @Override - default Optional custom() { - return Optional.of(this.get()); + default boolean isCustom(final Supplier customSupplier) { + return this.isCustom(customSupplier.get()); } @Override - default Either either() { - return Either.right(this.get()); + default boolean isAnyCustom(final CUSTOM... customs) { + return Arrays.stream(customs).anyMatch(this::isCustom); + } + + @Override + default boolean isAnyCustom(final Supplier... customSuppliers) { + return Arrays.stream(customSuppliers).map(Supplier::get).anyMatch(this::isCustom); + } + + @Override + default boolean isAnyCustom(final Iterable customIterable) { + return Streams.stream(customIterable).anyMatch(this::isCustom); + } + + @Override + default boolean is(final EITHER either) { + return either.isCustom(this.get()); } @Override diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java index 4308bb6..1068132 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java @@ -10,12 +10,12 @@ public class BasicCustomBlockType implements DefaultedCustomBlockType { - private final CustomBlockTypeProperties propeties; + private final CustomBlockTypeProperties properties; private @MonotonicNonNull BlockState state; private @MonotonicNonNull BlockStateExtension stateExtension; - public BasicCustomBlockType(final CustomBlockTypeProperties propeties) { - this.propeties = Objects.requireNonNull(propeties, "propeties"); + public BasicCustomBlockType(final CustomBlockTypeProperties properties) { + this.properties = Objects.requireNonNull(properties, "properties"); } public BasicCustomBlockType(final CustomBlockTypeBuilder builder) { @@ -24,13 +24,13 @@ public BasicCustomBlockType(final CustomBlockTypeBuilder builder) { @Override public CustomBlockTypeProperties properties() { - return this.propeties; + return this.properties; } @Override public BlockState state() { if (this.state == null) { - throw new IllegalStateException("State is not yet bound"); + throw new IllegalStateException("State is not yet bound for " + this.toString()); } return this.state; @@ -39,7 +39,7 @@ public BlockState state() { @Override public void bind(final BlockState state) { if (this.state != null) { - throw new IllegalStateException("State is already bound"); + throw new IllegalStateException("State is already bound for " + this.toString()); } this.state = Objects.requireNonNull(state, "state"); diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java index ae74988..44600f0 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java @@ -11,11 +11,10 @@ import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.block.BlockTypes; import org.spongepowered.api.data.type.SlabPortions; -import org.spongepowered.api.registry.RegistryTypes; import org.spongepowered.api.state.BooleanStateProperties; import org.spongepowered.api.state.EnumStateProperties; -import org.spongepowered.api.tag.BlockTypeTags; public interface BlockStateProvider/* extends MapCodecProxy*/ { @@ -91,7 +90,7 @@ public Stream allStates() { @Override public final String toString() { - return this.providers.toString(); + return "AnyProvider[" + this.providers.toString() + "]"; } } @@ -108,7 +107,7 @@ public Stream allStates() { @Override public String toString() { - return this.states.toString(); + return "AnyState[" + this.states.toString() + "]"; } } @@ -125,7 +124,7 @@ public Stream allStates() { @Override public String toString() { - return this.blocks.toString(); + return "AnyBlock[" + this.blocks.toString() + "]"; } } @@ -135,7 +134,7 @@ record Slab() implements BlockStateProvider { @Override public Stream allStates() { - return RegistryTypes.BLOCK_TYPE.get().taggedValues(BlockTypeTags.SLABS).stream() + return BlockTypes.registry().stream() .flatMap(block -> block.validStates().stream()) .filter(state -> state .stateProperty(EnumStateProperties.property_SLAB_TYPE()).orElse(null) == SlabPortions.DOUBLE.get()) diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java index 44df457..e022e2e 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java @@ -3,14 +3,17 @@ import java.util.Optional; import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.registry.DefaultedRegistryType; +import org.spongepowered.api.world.Location; import com.mojang.serialization.Codec; import net.hellheim.spongetools.SpongeTools; import net.hellheim.spongetools.codec.list.RegistryCodecs; import net.hellheim.spongetools.custom.type.CustomType; +import net.hellheim.spongetools.proxy.solid.block.BlockStateProxy; public interface CustomBlockType extends CustomType, @@ -35,4 +38,16 @@ static Optional get(final BlockState state) { return BlockStateDispatcher.get().get(state) .map(holder -> holder instanceof final CustomBlockType block ? block : null); } + + static Optional get(final Location location) { + return CustomBlockType.get(location.block()); + } + + static Optional get(final BlockSnapshot snapshot) { + return CustomBlockType.get(snapshot.state()); + } + + static Optional get(final BlockStateProxy proxy) { + return CustomBlockType.get(proxy.getAsBlockState()); + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java index 8932e0b..488a035 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java @@ -3,6 +3,7 @@ import java.util.function.Consumer; import org.spongepowered.api.fluid.FluidTypes; +import org.spongepowered.api.item.inventory.ItemStack; import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviours; @@ -11,8 +12,9 @@ public final class CustomBlockTypePresets { public static final CustomBlockTypeProperties SLAB = create(b -> b.state(BlockStateProvider.slab()) - .set(BlockStateBehaviours.FLUID, () -> FluidTypes.EMPTY.get().defaultState()) - .offer); + .set(BlockStateBehaviours.FLUID, FluidTypes.EMPTY.get().defaultState()) + .set(BlockStateBehaviours.BUCKET_PICKUP_ITEM, ItemStack.empty()) + ); private static final CustomBlockTypeProperties create( final Consumer> configurator diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java index 807fd36..6e6d27f 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java @@ -40,6 +40,6 @@ public List model() { } public CustomBlockTypeBuilder toBuilder() { - return new CustomBlockTypeBuilder<>(); + return new CustomBlockTypeBuilder<>().from(this); } } diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomIngredients.java b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomIngredients.java new file mode 100644 index 0000000..5787d1f --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomIngredients.java @@ -0,0 +1,156 @@ +package net.hellheim.spongetools.custom.type.item; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.item.ItemType; +import org.spongepowered.api.item.inventory.ItemStackLike; +import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.recipe.crafting.Ingredient; + +import com.google.common.collect.Streams; + +import net.hellheim.spongetools.util.ItemUtil; + +/** + * Utility class to make {@link Ingredient}s using {@link CustomItemType}s.
+ *
+ * Due to {@link CustomItemType} being built on top of actual {@link ItemType}, + * most ingredients by default would accept custom item if its vanilla type matches.
+ * This is fixed for ingredients that only test for {@link ItemType} (e.g. {@link Ingredient#of(ItemType...)}).
+ * If this ever becomes an issue for predicate ingredients (e.g. the ones made with + * {@link Ingredient#of(ResourceKey, Predicate, ItemStackLike...)}, it would require more intrusive fix.
+ *
+ * Therefore, it's recommended to use methods in this class if {@link CustomItemType}s are involved, + * because they will always work as expected regardless of whether the mentioned fix happened or not. + */ +public final class CustomIngredients { + + /* TODO tags are not yet loaded during recipe registration + public static Ingredient of(final DefaultedTag tag) { + return Ingredient.of(tag.values().toArray(ItemType[]::new)); + } + */ + + private static final Map SINGLETONS = new HashMap<>(); + + public static Ingredient singleton(final CustomItemType item) { + return CustomIngredients.SINGLETONS.computeIfAbsent(item, $ -> CustomIngredients.of(item.key(), item)); + } + + public static Ingredient of(final ResourceKey key, final CustomItemType... items) { + return CustomIngredients.of(key, CustomIngredients.isAny(items), CustomIngredients.icons(items)); + } + + @SafeVarargs + public static Ingredient of(final ResourceKey key, final Supplier... items) { + return CustomIngredients.of(key, CustomIngredients.isAny(items), CustomIngredients.icons(items)); + } + + public static Ingredient of(final ResourceKey key, final Iterable items) { + return CustomIngredients.of(key, CustomIngredients.isAny(items), CustomIngredients.icons(items)); + } + + public static Ingredient of(final ResourceKey key, final EitherItemType... items) { + return CustomIngredients.of(key, CustomIngredients.isAny(items), CustomIngredients.icons(items)); + } + + public static Ingredient of( + final ResourceKey key, final Predicate predicate, + final CustomItemType... exemplaryItems + ) { + return CustomIngredients.of(key, predicate, CustomIngredients.icons(exemplaryItems)); + } + + @SafeVarargs + public static Ingredient of( + final ResourceKey key, final Predicate predicate, + final Supplier... exemplaryItems + ) { + return CustomIngredients.of(key, predicate, CustomIngredients.icons(exemplaryItems)); + } + + public static Ingredient of( + final ResourceKey key, final Predicate predicate, + final Iterable exemplaryItems + ) { + return CustomIngredients.of(key, predicate, CustomIngredients.icons(exemplaryItems)); + } + + public static Ingredient of( + final ResourceKey key, final Predicate predicate, + final EitherItemType... exemplaryItems + ) { + return CustomIngredients.of(key, predicate, CustomIngredients.icons(exemplaryItems)); + } + + public static Ingredient of( + final ResourceKey key, final Predicate predicate, + final ItemStackLike... exemplaryItems + ) { + // This is subject to change due to reasons described above + return Ingredient.of(key, predicate, exemplaryItems); + } + + + + public static ItemStackSnapshot[] icons(final CustomItemType... items) { + return Arrays.stream(items) + .map(CustomIngredients::icon) + .toArray(ItemStackSnapshot[]::new); + } + + @SafeVarargs + public static ItemStackSnapshot[] icons(final Supplier... items) { + return Arrays.stream(items) + .map(Supplier::get) + .map(CustomIngredients::icon) + .toArray(ItemStackSnapshot[]::new); + } + + public static ItemStackSnapshot[] icons(final Iterable items) { + return Streams.stream(items) + .map(CustomIngredients::icon) + .toArray(ItemStackSnapshot[]::new); + } + + public static ItemStackSnapshot[] icons(final EitherItemType... items) { + return Arrays.stream(items) + .map(CustomIngredients::icon) + .toArray(ItemStackSnapshot[]::new); + } + + private static ItemStackSnapshot icon(final EitherItemType item) { + return item.apply(ItemUtil::snapshotOf, CustomIngredients::icon); + } + + private static ItemStackSnapshot icon(final CustomItemType item) { + return item.ingredientIcon(); + } + + + + public static Predicate isAny(final CustomItemType... items) { + return stack -> CustomItemType.isAny(stack, items); + } + + @SafeVarargs + public static Predicate isAny(final Supplier... items) { + return stack -> CustomItemType.isAny(stack, items); + } + + public static Predicate isAny(final Iterable items) { + return stack -> CustomItemType.isAny(stack, items); + } + + public static Predicate isAny(final EitherItemType... items) { + return stack -> EitherItemType.of(stack).isAny(items); + } + + private CustomIngredients() { + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java index b494e4a..b239bd8 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java @@ -1,6 +1,7 @@ package net.hellheim.spongetools.custom.type.item; import java.util.Optional; +import java.util.function.Supplier; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.ResourceKey; @@ -16,6 +17,8 @@ import org.spongepowered.api.data.value.Value; import org.spongepowered.api.data.value.ValueContainer; import org.spongepowered.api.item.ItemType; +import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.item.recipe.crafting.Ingredient; import org.spongepowered.api.registry.DefaultedRegistryReference; import org.spongepowered.api.registry.DefaultedRegistryType; @@ -34,7 +37,6 @@ public interface CustomItemType extends ComponentLike, DataSerializable, ValueContainer, - IconProxy, ItemStackSnapshotProxy { static DefaultedRegistryType registry() { @@ -107,6 +109,11 @@ static boolean isAny(final @Nullable CustomItemType itemToCompare, final CustomI return itemToCompare != null && itemToCompare.isAnyOf(items); } + @SafeVarargs + static boolean isAny(final @Nullable CustomItemType itemToCompare, final Supplier... items) { + return itemToCompare != null && itemToCompare.isAnyOf(items); + } + static boolean isAny(final @Nullable CustomItemType itemToCompare, final Iterable items) { return itemToCompare != null && itemToCompare.isAnyOfItem(items); } @@ -115,6 +122,11 @@ static boolean isAny(final @Nullable ValueContainer container, final CustomItemT return container != null && CustomItemType.isAny(CustomItemType.getOrNull(container), items); } + @SafeVarargs + static boolean isAny(final @Nullable ValueContainer container, final Supplier... items) { + return container != null && CustomItemType.isAny(CustomItemType.getOrNull(container), items); + } + static boolean isAny(final @Nullable ValueContainer container, final Iterable items) { return container != null && CustomItemType.isAny(CustomItemType.getOrNull(container), items); } @@ -123,6 +135,11 @@ static boolean isNone(final @Nullable CustomItemType itemToCompare, final Custom return !CustomItemType.isAny(itemToCompare, items); } + @SafeVarargs + static boolean isNone(final @Nullable CustomItemType itemToCompare, final Supplier... items) { + return !CustomItemType.isAny(itemToCompare, items); + } + static boolean isNone(final @Nullable CustomItemType itemToCompare, final Iterable items) { return !CustomItemType.isAny(itemToCompare, items); } @@ -131,6 +148,11 @@ static boolean isNone(final @Nullable ValueContainer container, final CustomItem return !CustomItemType.isAny(container, items); } + @SafeVarargs + static boolean isNone(final @Nullable ValueContainer container, final Supplier... items) { + return !CustomItemType.isAny(container, items); + } + static boolean isNone(final @Nullable ValueContainer container, final Iterable items) { return !CustomItemType.isAny(container, items); } @@ -141,6 +163,10 @@ default boolean is(final @Nullable CustomItemType item) { return item == this; } + default boolean is(final @Nullable Supplier item) { + return item != null && this.is(item.get()); + } + default boolean is(final @Nullable ValueContainer container) { return container != null && this.is(CustomItemType.getOrNull(container)); } @@ -155,6 +181,17 @@ default boolean isAnyOf(final CustomItemType... items) { return false; } + @SuppressWarnings("unchecked") + default boolean isAnyOf(final Supplier... items) { + for (final Supplier item : items) { + if (this.is(item.get())) { + return true; + } + } + + return false; + } + default boolean isAnyOf(final ValueContainer... containers) { for (final ValueContainer container : containers) { if (this.is(container)) { @@ -205,6 +242,14 @@ default EitherItemType either() { return EitherItemType.custom(this); } + default Ingredient ingredient() { + return CustomIngredients.singleton(this); + } + + ItemStackSnapshot icon(); + + ItemStackSnapshot ingredientIcon(); + // Methods that may be overriden @Override diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java index 69fe095..e3c5f08 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java @@ -7,7 +7,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.ResourceKeyed; -import org.spongepowered.api.Sponge; import org.spongepowered.api.data.Keys; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.ItemTypes; @@ -34,6 +33,7 @@ import net.hellheim.spongetools.resourcepack.item.ItemDefinition; import net.hellheim.spongetools.resourcepack.item.ItemModel; import net.hellheim.spongetools.resourcepack.item.TintSource; +import net.hellheim.spongetools.util.ModelUtil; import net.hellheim.spongetools.util.TranslationUtil; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.ComponentLike; @@ -42,7 +42,6 @@ public class CustomItemTypeProperties implements ResourceKeyed, ComponentLike, ValueContainerProxy, - IconProxy, ItemStackSnapshotProxy { public static final MapCodec MAP_CODEC = RecordCodecBuilder.mapCodec( @@ -57,6 +56,7 @@ public class CustomItemTypeProperties implements private final Component name; private final ItemStackSnapshotProxy icon; + private final ItemStackSnapshotProxy ingredientIcon; private final ItemStackSnapshotProxy snapshot; protected CustomItemTypeProperties(final Builder builder) { @@ -73,15 +73,16 @@ protected CustomItemTypeProperties(final Builder builder) { } this.data = data; - this.icon = ItemStackSnapshotProxy.of(() -> this.iconBuilder(builder).getAsItemStackSnapshot()); - this.snapshot = ItemStackSnapshotProxy.of(() -> this.snapshotBuilder(builder).getAsItemStackSnapshot()); + this.icon = ItemStackSnapshotProxy.of(() -> this.iconBuilder().getAsItemStackSnapshot()); + this.ingredientIcon = ItemStackSnapshotProxy.of(() -> this.ingredientIconBuilder().getAsItemStackSnapshot()); + this.snapshot = ItemStackSnapshotProxy.of(() -> this.snapshotBuilder().getAsItemStackSnapshot()); } protected CustomItemTypeProperties( final ResourceKey key, final RegistryKey base, final Optional model, DeferredValueContainer data ) { this.key = key; - this.base = base.asDefaultedReference(Sponge::server); + this.base = base.asScopedReference(); this.model = model; this.name = TranslationUtil.item(this.key); @@ -91,9 +92,9 @@ protected CustomItemTypeProperties( } this.data = data; - final Builder builder = this.asBuilder(); - this.icon = ItemStackSnapshotProxy.of(() -> this.iconBuilder(builder).getAsItemStackSnapshot()); - this.snapshot = ItemStackSnapshotProxy.of(() -> this.snapshotBuilder(builder).getAsItemStackSnapshot()); + this.icon = ItemStackSnapshotProxy.of(() -> this.iconBuilder().getAsItemStackSnapshot()); + this.ingredientIcon = ItemStackSnapshotProxy.of(() -> this.ingredientIconBuilder().getAsItemStackSnapshot()); + this.snapshot = ItemStackSnapshotProxy.of(() -> this.snapshotBuilder().getAsItemStackSnapshot()); } public static Builder builder() { @@ -137,28 +138,32 @@ public DeferredValueContainer getAsData() { return this.data; } - @Override - public ItemStackSnapshot getAsIcon() { + public ItemStackSnapshot icon() { return this.icon.getAsItemStackSnapshot(); } + public ItemStackSnapshot ingredientIcon() { + return this.ingredientIcon.getAsItemStackSnapshot(); + } + @Override public ItemStackSnapshot getAsItemStackSnapshot() { return this.snapshot.getAsItemStackSnapshot(); } - protected ItemBuilder iconBuilder(final Builder builder) { - final ItemBuilder item = ItemBuilder.of(this.base).displayName(this.name); - this.data.getAsData().getValues().forEach(item::offer); + protected ItemBuilder iconBuilder() { + final ItemBuilder item = ItemBuilder.of(this.base); + this.getValue(Keys.ITEM_NAME).ifPresent(item::offer); + this.getValue(Keys.MODEL).ifPresent(item::offer); return item; } - protected ItemBuilder snapshotBuilder(final Builder builder) { - return ItemBuilder.of(this.icon); + protected ItemBuilder ingredientIconBuilder() { + return this.snapshotBuilder(); } - protected Builder asBuilder() { - return new Builder().from(this); + protected ItemBuilder snapshotBuilder() { + return ItemBuilder.of(this.icon).copyFrom(this.data); } public static class Builder implements @@ -198,7 +203,7 @@ public Builder simpleModel(final TintSource... tints) { if (this.key == null) { throw new IllegalStateException("key must be set"); } - return this.model(ItemModel.simple(this.key, tints)); + return this.model(ItemModel.simple(ModelUtil.withItemPrefix(this.key), tints)); } public Builder data(final DeferredValueContainer data) { @@ -206,8 +211,21 @@ public Builder data(final DeferredValueContainer data) { return this; } + public Builder dataBefore(final Consumer data) { + return this.data == null + ? this.data(DeferredValueContainer.of(data)) + : this.data(this.data.withBefore(data)); + } + + public Builder dataAfter(final Consumer data) { + return this.data == null + ? this.data(DeferredValueContainer.of(data)) + : this.data(this.data.withAfter(data)); + } + + // TODO keep or remove? public Builder data(final Consumer data) { - return this.data(DeferredValueContainer.of(data)); + return this.dataAfter(data); } @Override diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java b/src/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java index 8990d41..27c1d3d 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java @@ -23,7 +23,7 @@ */ public final class DeferredItemType implements Supplier, - ResourceKeyed, ComponentLike, ValueContainerProxy, IconProxy, IItemProxy { + ResourceKeyed, ComponentLike, ValueContainerProxy, IItemProxy { private final Supplier type; @@ -79,11 +79,6 @@ public ValueContainer getAsData() { return this.get().getAsData(); } - @Override - public ItemStackSnapshot getAsIcon() { - return this.get().getAsIcon(); - } - @Override public ItemType getAsItemType() { return this.get().getAsItemType(); diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java b/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java index 3fb7b19..30c763c 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java @@ -34,7 +34,7 @@ * Wrapper for either {@link ItemType} or {@link CustomItemType}. */ public sealed abstract class EitherItemType - implements EitherType, ResourceKeyed, ComponentLike, ValueContainerProxy, IconProxy, IItemProxy + implements EitherType, ResourceKeyed, ComponentLike, ValueContainerProxy, IItemProxy permits EitherItemType.Common, EitherItemType.Custom { private static final Map COMMON_MAP = new IdentityHashMap<>(); @@ -125,11 +125,9 @@ protected static final class Common extends EitherItemType implements ItemTypeProxy { private final ItemType type; - private final IconProxy icon; protected Common(final ItemType type) { this.type = Objects.requireNonNull(type, "type"); - this.icon = IconProxy.wrapTypeCached(() -> this.type); } @Override @@ -137,11 +135,6 @@ public ItemType get() { return this.type; }; - @Override - public ItemStackSnapshot getAsIcon() { - return this.icon.getAsIcon(); - } - @Override public ItemType getAsItemType() { return this.type; @@ -207,12 +200,7 @@ protected Custom(final CustomItemType type) { @Override public CustomItemType get() { - return this.get(); - } - - @Override - public ItemStackSnapshot getAsIcon() { - return this.type.getAsIcon(); + return this.type; } @Override diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java b/src/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java index 6603e5d..0155a07 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java @@ -8,6 +8,7 @@ import org.spongepowered.api.registry.DefaultedRegistryReference; import net.hellheim.spongetools.object.DeferredValueContainer; +import net.hellheim.spongetools.object.ItemBuilder; import net.hellheim.spongetools.proxy.solid.data.ValueContainerProxy; import net.hellheim.spongetools.resourcepack.item.ItemDefinition; import net.kyori.adventure.text.Component; @@ -42,12 +43,21 @@ default DeferredValueContainer getAsData() { } @Override - default ItemStackSnapshot getAsIcon() { - return this.properties().getAsIcon(); + default ItemStackSnapshot icon() { + return this.properties().icon(); + } + + @Override + default ItemStackSnapshot ingredientIcon() { + return this.properties().ingredientIcon(); } @Override default ItemStackSnapshot getAsItemStackSnapshot() { return this.properties().getAsItemStackSnapshot(); } + + default ItemBuilder builderOfIcon() { + return ItemBuilder.of(this.icon()); + } } diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/IconProxy.java b/src/main/java/net/hellheim/spongetools/custom/type/item/IconProxy.java deleted file mode 100644 index f45f572..0000000 --- a/src/main/java/net/hellheim/spongetools/custom/type/item/IconProxy.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.hellheim.spongetools.custom.type.item; - -import java.util.function.Supplier; - -import org.spongepowered.api.item.ItemType; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; - -import net.hellheim.spongetools.object.ItemBuilder; -import net.hellheim.spongetools.proxy.solid.item.ItemStackSnapshotProxy; - -/** - * Proxy that has some generic {@link ItemStackSnapshot} - * which is assumed as default display item. - */ -public interface IconProxy { - - static IconProxy wrapType(final Supplier typeSupplier) { - return ItemStackSnapshotProxy.wrapType(typeSupplier)::getAsItemStackSnapshot; - } - - static IconProxy wrapTypeCached(final Supplier typeSupplier) { - return ItemStackSnapshotProxy.wrapTypeCached(typeSupplier)::getAsItemStackSnapshot; - } - - ItemStackSnapshot getAsIcon(); - - default ItemBuilder builderOfIcon() { - return ItemBuilder.of(this.getAsIcon()); - } -} diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java b/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java new file mode 100644 index 0000000..7e55b09 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java @@ -0,0 +1,272 @@ +package net.hellheim.spongetools.custom.type.item; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; + +import org.spongepowered.api.data.Key; +import org.spongepowered.api.data.Keys; +import org.spongepowered.api.data.persistence.DataBuilder; +import org.spongepowered.api.data.value.ListValue; +import org.spongepowered.api.data.value.Value; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; +import org.spongepowered.api.registry.DefaultedRegistryType; +import org.spongepowered.api.util.CopyableBuilder; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.DataCodecs; +import net.hellheim.spongetools.codec.list.RegistryCodecs; +import net.hellheim.spongetools.object.CodecDataSerializable; +import net.hellheim.spongetools.object.TypedKeyMap; +import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; +import net.hellheim.spongetools.proxy.solid.item.IItemProxy; +import net.kyori.adventure.text.Component; + +public interface LoreProcessor extends CodecDataSerializable, MapCodecProxy { + + Codec CODEC = LoreProcessor.registryCodec() + .dispatch(LoreProcessor::mapCodec, Function.identity()); + + static DefaultedRegistryType> registry() { + return SpongeTools.Registries.LORE_PROCESSOR_TYPE; + } + + static Codec> registryCodec() { + return RegistryCodecs.LORE_PROCESSOR_TYPE; + } + + static Key> dataKey() { + return SpongeTools.Keys.LORE_PROCESSOR; + } + + static DataBuilder dataBuilder() { + return DataCodecs.dataBuilder(CODEC); + } + + static LoreProcessor.Plain plain() { + return Plain.INSTANCE; + } + + static LoreProcessor.Separated.Builder separated() { + return new LoreProcessor.Separated.Builder(); + } + + static ItemStackLike apply(final ItemStackLike stack, final TypedKeyMap context) { + return stack.get(LoreProcessor.dataKey()) + .map(processor -> processor.apply(stack, context)) + .orElse(stack); + } + + static ItemStackLike apply(final IItemProxy stack, final TypedKeyMap context) { + return LoreProcessor.applyProcessor(stack.getAsItemStackLike(), context); + } + + /** + * Processes all the given {@link LoreProvider}s and returns accumulated list of components. + * + * @param stack The stack to process lore for + * @param context The context to use providers with + * @param providers The list of lore providers + * @return The list of components + */ + List process(ItemStackLike stack, TypedKeyMap context, List providers); + + default ListValue processValue( + final ItemStackLike stack, final TypedKeyMap context, final List providers + ) { + return ListValue.immutableOf(Keys.LORE, this.process(stack, context, providers)); + } + + /** + * Processes and applies given lore providers to the given item.
+ * If the item is mutable, it is modified and returned.
+ * If the item is immutable, its mutable copy is modified and returned. + * + * @param stack The stack to apply lore to + * @param context The context to use providers with + * @param providers The list of lore providers + * @return The stack with applied lore + * + default ItemStack apply(final ItemStackLike stack, final TypedKeyMap context, final List providers) { + final ItemStack mutable = stack.asMutable(); + mutable.offer(Keys.LORE, this.process(stack, context, providers)); + providers.forEach(provider -> + provider.loreHidingKeys().forEach(key -> + mutable.offer(key, true))); + return mutable; + } + + /** + * Processes and applies lore to the given item.
+ * If item does not have any lore providers, then empty list is used.
+ * If item is mutable, it is modified and returned.
+ * If item is immutable, its mutable copy is modified and returned. + * + * @param stack The stack to apply lore to + * @param context The context to use providers with + * @return The stack with applied lore + * + default ItemStack apply(final ItemStackLike stack, final TypedKeyMap context) { + return this.apply(stack, context, stack.getOrElse(LoreProvider.dataKey(), List.of())); + } + + /** + * Uses {@link #apply(ItemStackLike, TypedKeyMap)} with {@link IItemProxy#getAsItemStackLike()}. + * + * @param stack The stack to apply lore to + * @param context The context to use providers with + * @return The stack with applied lore + * + default ItemStack apply(final IItemProxy stack, final TypedKeyMap context) { + return this.apply(stack.getAsItemStackLike(), context); + } + + /** + * Processes and applies lore to the given item.
+ * If item does not have any lore providers, then the original stack is returned.
+ * If item is mutable, it is modified and returned.
+ * If item is immutable, its mutable copy is modified and returned. + * + * @param stack The stack to apply lore to + * @param context The context to use providers with + * @return The stack with applied lore, or original stack + * + default ItemStackLike applyIfPresent(final ItemStackLike stack, final TypedKeyMap context) { + return stack.get(LoreProvider.dataKey()) + .map(providers -> this.apply(stack, context, providers)) + .orElse(stack); + } + + /** + * Uses {@link #applyIfPresent(ItemStackLike, TypedKeyMap)} with {@link IItemProxy#getAsItemStackLike()}. + * + * @param stack The stack to apply lore to + * @param context The context to use providers with + * @return The stack with applied lore, or original stack + * + default ItemStackLike applyIfPresent(final IItemProxy stack, final TypedKeyMap context) { + return this.applyIfPresent(stack.getAsItemStackLike(), context); + } + */ + @Override + default Codec codec() { + return CODEC; + } + + record Plain() implements LoreProcessor { + + public static final Plain INSTANCE = new Plain(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + @Override + public MapCodec mapCodec() { + return CODEC; + } + + @Override + public List process(final ItemStackLike stack, final TypedKeyMap context, final List providers) { + final List lore = new ArrayList<>(); + providers.forEach(provider -> lore.addAll(provider.provide(stack, context))); + return lore; + } + } + + record Separated(LoreProvider prefix, LoreProvider suffix, LoreProvider separator) implements LoreProcessor { + + public static final LoreProvider DEFAULT_PREFIX = LoreProvider.empty(); + public static final LoreProvider DEFAULT_SUFFIX = LoreProvider.empty(); + public static final LoreProvider DEFAULT_SEPARATOR = LoreProvider.plain(Component.empty()); + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + LoreProvider.CODEC.optionalFieldOf("prefix", DEFAULT_PREFIX).forGetter(Separated::prefix), + LoreProvider.CODEC.optionalFieldOf("suffix", DEFAULT_SUFFIX).forGetter(Separated::suffix), + LoreProvider.CODEC.optionalFieldOf("separator", DEFAULT_SEPARATOR).forGetter(Separated::separator) + ).apply(instance, Separated::new)); + + public Separated(final LoreProvider prefix, final LoreProvider suffix, final LoreProvider separator) { + this.prefix = Objects.requireNonNull(prefix, "prefix"); + this.suffix = Objects.requireNonNull(suffix, "suffix"); + this.separator = Objects.requireNonNull(separator, "separator"); + } + + @Override + public MapCodec mapCodec() { + return CODEC; + } + + @Override + public List process(final ItemStackLike stack, final TypedKeyMap context, final List providers) { + final List lore = new ArrayList<>(); + if (!providers.isEmpty()) { + final List separator = this.separator.provide(stack, context); + providers.forEach(provider -> { + final List loreToAdd = provider.provide(stack, context); + if (!loreToAdd.isEmpty() && !lore.isEmpty()) { + lore.addAll(separator); + } + + lore.addAll(loreToAdd); + }); + + lore.addAll(0, this.prefix.provide(stack, context)); + lore.addAll(this.suffix.provide(stack, context)); + } + return lore; + } + + public static final class Builder implements + org.spongepowered.api.util.Builder, + CopyableBuilder { + + private LoreProvider prefix; + private LoreProvider suffix; + private LoreProvider separator; + + public Builder() { + this.reset(); + } + + public Builder prefix(final LoreProvider prefix) { + this.prefix = Objects.requireNonNull(prefix, "prefix"); + return this; + } + + public Builder suffix(final LoreProvider suffix) { + this.suffix = Objects.requireNonNull(suffix, "suffix"); + return this; + } + + public Builder separator(final LoreProvider separator) { + this.separator = Objects.requireNonNull(separator, "separator"); + return this; + } + + @Override + public Builder reset() { + this.prefix = Separated.DEFAULT_PREFIX; + this.suffix = Separated.DEFAULT_SUFFIX; + this.separator = Separated.DEFAULT_SEPARATOR; + return this; + } + + @Override + public Builder from(final Separated value) { + this.prefix = value.prefix(); + this.suffix = value.suffix(); + this.separator = value.separator(); + return this; + } + + @Override + public Separated build() { + return new Separated(this.prefix, this.suffix, this.separator); + } + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java b/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java new file mode 100644 index 0000000..d22c527 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java @@ -0,0 +1,107 @@ +package net.hellheim.spongetools.custom.type.item; + +import java.util.List; +import java.util.Objects; +import java.util.function.Function; + +import org.spongepowered.api.data.Key; +import org.spongepowered.api.data.persistence.DataBuilder; +import org.spongepowered.api.data.value.ListValue; +import org.spongepowered.api.data.value.Value; +import org.spongepowered.api.item.inventory.ItemStackLike; +import org.spongepowered.api.registry.DefaultedRegistryType; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.AdventureCodecs; +import net.hellheim.spongetools.codec.list.DataCodecs; +import net.hellheim.spongetools.codec.list.RegistryCodecs; +import net.hellheim.spongetools.object.CodecDataSerializable; +import net.hellheim.spongetools.object.TypedKeyMap; +import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; +import net.kyori.adventure.text.Component; + +public interface LoreProvider extends CodecDataSerializable, MapCodecProxy { + + Codec CODEC = LoreProvider.registryCodec() + .dispatch(LoreProvider::mapCodec, Function.identity()); + + static DefaultedRegistryType> registry() { + return SpongeTools.Registries.LORE_PROVIDER_TYPE; + } + + static Codec> registryCodec() { + return RegistryCodecs.LORE_PROVIDER_TYPE; + } + + static Key> dataKey() { + return SpongeTools.Keys.LORE_PROVIDERS; + } + + static DataBuilder dataBuilder() { + return DataCodecs.dataBuilder(CODEC); + } + + static LoreProvider empty() { + return LoreProvider.Plain.EMPTY; + } + + static LoreProvider.Plain plain(final Component... components) { + return LoreProvider.plain(List.of(components)); + } + + static LoreProvider.Plain plain(final List components) { + return new LoreProvider.Plain(components); + } + + /** + * Returns the list of {@link Component}s this provider adds to item lore.
+ * It's totally valid for provider to return empty list (e.g. if it acts only in the specific context). + * + * @param stack The item to provide the lore for + * @param context The context to use the provider with + * @return The list of components + */ + List provide(ItemStackLike stack, TypedKeyMap context); + + /** + * Returns the list of {@link Key}s that hide some parts of regular lore on the item.
+ * Useful for providers that change the appearance of vanilla lore (e.g. enchantments, potions). + * + * @return The list of keys + */ + default List>> loreHidingKeys() { + return List.of(); + } + + @Override + default Codec codec() { + return CODEC; + } + + record Plain(List components) implements LoreProvider { + + public static final Plain EMPTY = LoreProvider.plain(); + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + AdventureCodecs.COMPONENT.listOf().fieldOf("components").forGetter(Plain::components) + ).apply(instance, Plain::new)); + + public Plain(final List components) { + this.components = List.copyOf(Objects.requireNonNull(components, "components")); + } + + @Override + public List provide(final ItemStackLike stack, final TypedKeyMap context) { + return this.components; + } + + @Override + public MapCodec mapCodec() { + return Plain.CODEC; + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/set/CardinalNeighbourShape.java b/src/main/java/net/hellheim/spongetools/math/set/CardinalNeighbourShape.java new file mode 100644 index 0000000..a852678 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/set/CardinalNeighbourShape.java @@ -0,0 +1,22 @@ +package net.hellheim.spongetools.math.set; + +import java.util.random.RandomGenerator; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector3i; +import net.hellheim.spongetools.object.Streamable; + +public class CardinalNeighbourShape implements CountableVectorSet.Vec3i { + + @Override + public Streamable all() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Streamable random(RandomGenerator random) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/main/java/net/hellheim/spongetools/math/set/CountableVectorSet.java b/src/main/java/net/hellheim/spongetools/math/set/CountableVectorSet.java new file mode 100644 index 0000000..422510f --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/set/CountableVectorSet.java @@ -0,0 +1,82 @@ +package net.hellheim.spongetools.math.set; + +import java.util.random.RandomGenerator; + +import org.spongepowered.math.vector.Vector2i; +import org.spongepowered.math.vector.Vector3i; +import org.spongepowered.math.vector.Vector4i; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector2i; +import net.hellheim.spongetools.math.mutable.vector.MutableVector3i; +import net.hellheim.spongetools.math.mutable.vector.MutableVector4i; +import net.hellheim.spongetools.object.Streamable; + +/** + * @param The vector type + */ +public interface CountableVectorSet { + + Streamable all(); + + /** + * @return The infinite Streamable + */ + Streamable random(RandomGenerator random); + + interface Vec2i extends CountableVectorSet { + + default Streamable all(final Vector2i translation) { + return this.all(translation.x(), translation.y()); + } + + default Streamable all(final int xTranslation, final int yTranslation) { + return this.all().map(v -> v.add(xTranslation, yTranslation)); + } + + default Streamable random(final RandomGenerator random, final Vector2i translation) { + return this.random(random, translation.x(), translation.y()); + } + + default Streamable random(final RandomGenerator random, final int xTranslation, final int yTranslation) { + return this.random(random).map(v -> v.add(xTranslation, yTranslation)); + } + } + + interface Vec3i extends CountableVectorSet { + + default Streamable all(final Vector3i translation) { + return this.all(translation.x(), translation.y(), translation.z()); + } + + default Streamable all(final int xTranslation, final int yTranslation, final int zTranslation) { + return this.all().map(v -> v.add(xTranslation, yTranslation, zTranslation)); + } + + default Streamable random(final RandomGenerator random, final Vector3i translation) { + return this.random(random, translation.x(), translation.y(), translation.z()); + } + + default Streamable random(final RandomGenerator random, final int xTranslation, final int yTranslation, final int zTranslation) { + return this.random(random).map(v -> v.add(xTranslation, yTranslation, zTranslation)); + } + } + + interface Vec4i extends CountableVectorSet { + + default Streamable all(final Vector4i translation) { + return this.all(translation.x(), translation.y(), translation.z(), translation.w()); + } + + default Streamable all(final int xTranslation, final int yTranslation, final int zTranslation, final int wTranslation) { + return this.all().map(v -> v.add(xTranslation, yTranslation, zTranslation, wTranslation)); + } + + default Streamable random(final RandomGenerator random, final Vector4i translation) { + return this.random(random, translation.x(), translation.y(), translation.z(), translation.w()); + } + + default Streamable random(final RandomGenerator random, final int xTranslation, final int yTranslation, final int zTranslation, final int wTranslation) { + return this.random(random).map(v -> v.add(xTranslation, yTranslation, zTranslation, wTranslation)); + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/set/Ellipse.java b/src/main/java/net/hellheim/spongetools/math/set/Ellipse.java new file mode 100644 index 0000000..455914e --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/set/Ellipse.java @@ -0,0 +1,89 @@ +package net.hellheim.spongetools.math.set; + +import java.util.random.RandomGenerator; +import java.util.stream.Stream; + +import com.google.common.base.Preconditions; +import com.google.common.collect.AbstractIterator; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector2i; +import net.hellheim.spongetools.object.Streamable; + +public class Ellipse implements CountableVectorSet.Vec2i { + + private final int xRad; + private final int yRad; + + private final int xRad2; + private final int yRad2; + private final double xMul; + + protected Ellipse(final int xRadius, final int yRadius) { + Preconditions.checkArgument(xRadius > 0, "xRadius must be positive"); + Preconditions.checkArgument(yRadius > 0, "yRadius must be positive"); + this.xRad = xRadius; + this.yRad = yRadius; + + this.xRad2 = xRadius * xRadius; + this.yRad2 = yRadius * yRadius; + this.xMul = ((double) this.yRad2) / this.xRad2; + } + + public int xRadius() { + return this.xRad; + } + + public int yRadius() { + return this.yRad; + } + + public boolean isInside(final int x, final int y) { + return this.yRad2 * x * x + this.xRad2 * y * y <= this.xRad2 * this.yRad2; + } + + @Override + public Streamable all() { + return Streamable.of(() -> new AbstractIterator() { + private final MutableVector2i cursor = MutableVector2i.zero(); + private boolean yMirror = false; + private int x = - Ellipse.this.xRad - 1; + private int y; + private int y2Max; + + @Override + protected MutableVector2i computeNext() { + if (this.yMirror) { + this.yMirror = false; + return this.cursor.set(this.x, this.y); + } + + ++this.y; + if (this.y * this.y <= this.y2Max) { + this.yMirror = true; + return this.cursor.set(this.x, this.y); + } + + ++this.x; + if (this.x > Ellipse.this.xRad) { + return this.endOfData(); + } + + this.y = 0; + this.y2Max = (int) (Ellipse.this.yRad2 - Ellipse.this.xMul * this.x); + return this.cursor.set(this.x, 0); + } + }); + } + + @Override + public Streamable random(final RandomGenerator random) { + return Streamable.of(() -> { + final MutableVector2i cursor = MutableVector2i.zero(); + return Stream.generate(() -> { + final int x = random.nextInt(-this.xRad, this.xRad + 1); + final int y = random.nextInt(-this.yRad, this.yRad + 1); + return cursor.set(x, y); + }).filter(v -> this.isInside(v.x(), v.y())); + }); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/set/Ellipsoid.java b/src/main/java/net/hellheim/spongetools/math/set/Ellipsoid.java new file mode 100644 index 0000000..9edd649 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/set/Ellipsoid.java @@ -0,0 +1,43 @@ +package net.hellheim.spongetools.math.set; + +import java.util.random.RandomGenerator; + +import com.google.common.base.Preconditions; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector3i; +import net.hellheim.spongetools.object.Streamable; + +public class Ellipsoid implements CountableVectorSet.Vec3i { + + private final int xRad; + private final int yRad; + private final int zRad; + + private final int xRad2; + private final int yRad2; + private final double xMul; + + protected Ellipsoid(final int xRadius, final int yRadius, final int zRadius) { + Preconditions.checkArgument(xRadius > 0, "xRadius must be positive"); + Preconditions.checkArgument(yRadius > 0, "yRadius must be positive"); + Preconditions.checkArgument(zRadius > 0, "zRadius must be positive"); + this.xRad = xRadius; + this.yRad = yRadius; + this.zRad = zRadius; + + this.xRad2 = xRadius * xRadius; + this.yRad2 = yRadius * yRadius; + this.xMul = ((double) this.yRad2) / this.xRad2; + } + + @Override + public Streamable all() { + return null; + } + + @Override + public Streamable random(RandomGenerator random) { + // TODO Auto-generated method stub + return null; + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/set/Manhattan2.java b/src/main/java/net/hellheim/spongetools/math/set/Manhattan2.java new file mode 100644 index 0000000..e275250 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/set/Manhattan2.java @@ -0,0 +1,98 @@ +package net.hellheim.spongetools.math.set; + +import java.util.random.RandomGenerator; +import java.util.stream.Stream; + +import com.google.common.base.Preconditions; +import com.google.common.collect.AbstractIterator; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector2i; +import net.hellheim.spongetools.object.Streamable; + +public class Manhattan2 implements CountableVectorSet.Vec2i { + + private final int xDepth; + private final int yDepth; + private final int totalDepth; + + protected Manhattan2(final int xDepth, final int yDepth) { + Preconditions.checkArgument(xDepth >= 0, "xDepth must not be negative"); + Preconditions.checkArgument(yDepth >= 0, "yDepth must not be negative"); + this.xDepth = xDepth; + this.yDepth = yDepth; + this.totalDepth = xDepth + yDepth; + } + + public int xDepth() { + return this.xDepth; + } + + public int yDepth() { + return this.yDepth; + } + + @Override + public Streamable all() { + return Streamable.of(() -> new AbstractIterator() { + private final MutableVector2i cursor = MutableVector2i.zero(); + private int currentDepth; + private int xMax; + private int x; + private boolean yMirror; + + @Override + protected MutableVector2i computeNext() { + if (this.yMirror) { + this.yMirror = false; + return this.cursor.set(this.x - 1, -this.cursor.y()); + } + + MutableVector2i vec; + for (vec = null; vec == null; this.x++) { + if (this.x > this.xMax) { + this.currentDepth++; + if (this.currentDepth > Manhattan2.this.totalDepth) { + return this.endOfData(); + } + + this.xMax = Math.min(Manhattan2.this.xDepth, this.currentDepth); + this.x = -this.xMax; + } + + final int y = this.currentDepth - Math.abs(this.x); + if (y <= Manhattan2.this.yDepth) { + this.yMirror = y != 0; + vec = this.cursor.set(this.x, y); + } + } + + return vec; + }; + }); + } + + @Override + public Streamable random(final RandomGenerator random) { + return Streamable.of(() -> { + final MutableVector2i cursor = MutableVector2i.zero(); + return Stream.generate(() -> { + int x = random.nextInt(this.xDepth + 1); + int y = random.nextInt(this.yDepth + 1); + + if ((x + y) > this.totalDepth) { + x = this.xDepth - x; + y = this.yDepth - y; + } + + if (random.nextBoolean()) { + x = -x; + } + if (random.nextBoolean()) { + y = -y; + } + + return cursor.set(x, y); + }); + }); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/set/Manhattan3.java b/src/main/java/net/hellheim/spongetools/math/set/Manhattan3.java new file mode 100644 index 0000000..a774aee --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/set/Manhattan3.java @@ -0,0 +1,119 @@ +package net.hellheim.spongetools.math.set; + +import java.util.random.RandomGenerator; +import java.util.stream.Stream; + +import com.google.common.base.Preconditions; +import com.google.common.collect.AbstractIterator; + +import net.hellheim.spongetools.math.mutable.vector.MutableVector3i; +import net.hellheim.spongetools.object.Streamable; + +public class Manhattan3 implements CountableVectorSet.Vec3i { + + private final int xDepth; + private final int yDepth; + private final int zDepth; + private final long totalDepth; + + protected Manhattan3(final int xDepth, final int yDepth, final int zDepth) { + Preconditions.checkArgument(xDepth >= 0, "xDepth must not be negative"); + Preconditions.checkArgument(yDepth >= 0, "yDepth must not be negative"); + Preconditions.checkArgument(zDepth >= 0, "zDepth must not be negative"); + this.xDepth = xDepth; + this.yDepth = yDepth; + this.zDepth = zDepth; + this.totalDepth = xDepth + yDepth + zDepth; + } + + public int xDepth() { + return this.xDepth; + } + + public int yDepth() { + return this.yDepth; + } + + public int zDepth() { + return this.zDepth; + } + + @Override + public Streamable all() { + // Copied from Minecraft's BlockPos#withinManhattan + return Streamable.of(() -> new AbstractIterator() { + private final MutableVector3i cursor = MutableVector3i.zero(); + private int currentDepth; + private int xMax; + private int yMax; + private int x; + private int y; + private boolean zMirror; + + @Override + protected MutableVector3i computeNext() { + if (this.zMirror) { + this.zMirror = false; + return this.cursor.set(this.x, this.y - 1, -this.cursor.z()); + } + + MutableVector3i vec; + for (vec = null; vec == null; this.y++) { + if (this.y > this.yMax) { + this.x++; + if (this.x > this.xMax) { + this.currentDepth++; + if (this.currentDepth > Manhattan3.this.totalDepth) { + return this.endOfData(); + } + + this.xMax = Math.min(Manhattan3.this.xDepth, this.currentDepth); + this.x = -this.xMax; + } + + this.yMax = Math.min(Manhattan3.this.yDepth, this.currentDepth - Math.abs(this.x)); + this.y = -this.yMax; + } + + final int z = this.currentDepth - Math.abs(this.x) - Math.abs(this.y); + if (z <= Manhattan3.this.zDepth) { + this.zMirror = z != 0; + vec = this.cursor.set(this.x, this.y, z); + } + } + + return vec; + } + }); + } + + @Override + public Streamable random(final RandomGenerator random) { + return Streamable.of(() -> { + final MutableVector3i cursor = MutableVector3i.zero(); + return Stream.generate(() -> { + int x = random.nextInt(this.xDepth + 1); + int y = random.nextInt(this.yDepth + 1); + int z = random.nextInt(this.zDepth + 1); + + if ((x + y + z) > this.totalDepth) { + x = this.xDepth - x; + y = this.yDepth - y; + z = this.zDepth - z; + } + + if (random.nextBoolean()) { + x = -x; + } + if (random.nextBoolean()) { + y = -y; + } + if (random.nextBoolean()) { + z = -z; + } + + return cursor.set(x, y, z); + }); + }); + } +} diff --git a/src/main/java/net/hellheim/spongetools/math/set/Shapes.java b/src/main/java/net/hellheim/spongetools/math/set/Shapes.java new file mode 100644 index 0000000..98da0c9 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/math/set/Shapes.java @@ -0,0 +1,34 @@ +package net.hellheim.spongetools.math.set; + +import org.spongepowered.math.vector.Vector2i; +import org.spongepowered.math.vector.Vector3i; + +public final class Shapes { + + public static Manhattan3 manhattan3(final Vector3i depth) { + return Shapes.manhattan3(depth.x(), depth.y(), depth.z()); + } + + public static Manhattan3 manhattan3(final int depth) { + return Shapes.manhattan3(depth, depth, depth); + } + + public static Manhattan3 manhattan3(final int xDepth, final int yDepth, final int zDepth) { + return new Manhattan3(xDepth, yDepth, zDepth); + } + + public static Manhattan2 manhattan2(final Vector2i depth) { + return Shapes.manhattan2(depth.x(), depth.y()); + } + + public static Manhattan2 manhattan2(final int depth) { + return Shapes.manhattan2(depth, depth); + } + + public static Manhattan2 manhattan2(final int xDepth, final int yDepth) { + return new Manhattan2(xDepth, yDepth); + } + + private Shapes() { + } +} diff --git a/src/main/java/net/hellheim/spongetools/menu/Menu.java b/src/main/java/net/hellheim/spongetools/menu/Menu.java index b8a8ed4..fb90bff 100644 --- a/src/main/java/net/hellheim/spongetools/menu/Menu.java +++ b/src/main/java/net/hellheim/spongetools/menu/Menu.java @@ -3,9 +3,6 @@ import java.util.ArrayDeque; import java.util.Collection; import java.util.Deque; -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -22,6 +19,8 @@ import net.hellheim.spongetools.menu.pagination.Pagination; import net.hellheim.spongetools.menu.pagination.PaginationInitStage; import net.hellheim.spongetools.menu.pagination.PaginationType; +import net.hellheim.spongetools.object.TypedKey; +import net.hellheim.spongetools.object.TypedKeyMap; import net.hellheim.spongetools.proxy.solid.PluginProxy; import net.hellheim.spongetools.util.TaskUtil; import net.kyori.adventure.text.Component; @@ -29,7 +28,7 @@ /** * {@link Menu} is a wrapper for {@link InventoryMenu} with some useful additions:
* - History of visited {@link MenuType}s is stored to surf through them back and forth
- * - Data can be stored via {@link MenuKey}s
+ * - Data can be stored via {@link TypedKey}s
* - {@link Pagination} support
*
* Since menu creation requires {@link PluginContainer}, it's recommended to use {@link IMenuManager}.
@@ -39,7 +38,7 @@ * * @param The menu itself */ -public abstract class Menu> implements PluginProxy, Identifiable { +public abstract class Menu> implements PluginProxy, Identifiable, TypedKeyMap.Proxy.Mutable { private final PluginContainer plugin; private final UUID uniqueId; @@ -48,7 +47,7 @@ public abstract class Menu> implements PluginProxy, Identifiab private final Deque> history = new ArrayDeque<>(); private final UnmodifiableDeque> historyView = new UnmodifiableDeque<>(this.history); - private final Map, Object> data = new HashMap<>(); + private final TypedKeyMap.Mutable data = TypedKeyMap.create(); private @Nullable Pagination pagination = null; private IMenuType type; @@ -81,11 +80,6 @@ private M cast() { return (M) this; } - @SuppressWarnings("unchecked") - private T castValue(final MenuKey key, final Object value) { - return (T) value; - } - private void registerHandlers() { this.type.handlers().forEach(handler -> this.menu.registerHandler(handler.asDefaultHandler(this.cast()))); } @@ -156,121 +150,9 @@ public ViewableInventory inventory() { return this.menu.inventory(); } - - - /** - * Sets value of unknown type for the specified {@link MenuKey} for this {@link Menu}.
- * Useful when deleloper is sure about complex type compatability but IDE complains about it.
- *
- * It's strongly advised to not use this method whenever possible. - * - * @param key The {@link MenuKey key} - * @param value The value - */ - public void setUnsafe(final MenuKey key, final @Nullable Object value) { - this.data.put(key, value); - } - - /** - * Sets value for the specified {@link MenuKey} for this {@link Menu}.
- * Null value is supported. - * - * @param The type of key and value - * @param key The {@link MenuKey key} - * @param value The value - */ - public void set(final MenuKey key, final @Nullable T value) { - this.data.put(key, value); - } - - /** - * - * Sets value for the specified {@link MenuKey} for this {@link Menu} only if provided {@link Optional} is present. - * - * @param The type of key and value - * @param key The key - * @param optionalValue The optional value - */ - public void setIfPresent(final MenuKey key, final Optional optionalValue) { - optionalValue.ifPresent(value -> this.set(key, value)); - } - - /** - * Removes provided {@link MenuKey} for this {@link Menu}.
- *
- * Returns the previous value assosiated with key, or null if there was no value for key. - * - * @param The type of key - * @param key The key - * @return The previous value assosiated with key, or null if there was no value for key. - */ - public @Nullable T remove(final MenuKey key) { - return this.castValue(key, this.data.remove(key)); - } - - /** - * Returns whether this {@link Menu} contains value for provided {@link MenuKey}. - * - * @param key The key - * @return True if this menu contains value for provided key. - */ - public boolean has(final MenuKey key) { - return this.data.containsKey(key); - } - - /** - * Returns the value assosiated with provided {@link MenuKey} for this {@link Menu}, - * or {@link Optional#empty()} if there is no value for key. - * - * @param The type of key - * @param key The key - * @return The value, if available - */ - public Optional get(final MenuKey key) { - return this.data.containsKey(key) ? Optional.of(this.castValue(key, this.data.get(key))) : Optional.empty(); - } - - /** - * Returns the value assosiated with provided {@link MenuKey} for this {@link Menu}, - * or defaultValue if there is no value for key. - * - * @param The type of key and default value - * @param key The key - * @param defaultValue The default value - * @return The value, or default if not set - */ - public @Nullable T getOrElse(final MenuKey key, T defaultValue) { - return this.castValue(key, this.data.getOrDefault(key, defaultValue)); - } - - /** - * Returns the value assosiated with provided {@link MenuKey} for this {@link Menu}, - * or null if there is no value for key. - * - * @param The type of key - * @param key The key - * @return The value, or null if not set - */ - public @Nullable T getOrNull(final MenuKey key) { - return this.castValue(key, this.data.get(key)); - } - - /** - * Returns the value assosiated with provided {@link MenuKey} for this {@link Menu}.
- *
- * If there is no value for key, {@link NoSuchElementException} will be thrown. - * - * @param The type of key - * @param key The {@link MenuKey key} - * @return The value - * @throws NoSuchElementException If there is no value for provided key - */ - public @Nullable T require(final MenuKey key) { - if (!this.data.containsKey(key)) { - throw new NoSuchElementException("No value found for the specified menu key"); - } - - return this.castValue(key, this.data.get(key)); + @Override + public TypedKeyMap.Mutable data() { + return this.data; } diff --git a/src/main/java/net/hellheim/spongetools/menu/MenuKey.java b/src/main/java/net/hellheim/spongetools/menu/MenuKey.java deleted file mode 100644 index 46a6248..0000000 --- a/src/main/java/net/hellheim/spongetools/menu/MenuKey.java +++ /dev/null @@ -1,16 +0,0 @@ -package net.hellheim.spongetools.menu; - -/** - * Used to store data within {@link Menu}. - * - * @param The type of key - */ -public final class MenuKey { - - private MenuKey() { - } - - public static MenuKey key() { - return new MenuKey<>(); - } -} diff --git a/src/main/java/net/hellheim/spongetools/object/AttributeModifierTemplate.java b/src/main/java/net/hellheim/spongetools/object/AttributeModifierTemplate.java new file mode 100644 index 0000000..ce41ef4 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/object/AttributeModifierTemplate.java @@ -0,0 +1,40 @@ +package net.hellheim.spongetools.object; + +import java.util.Objects; +import java.util.function.Supplier; + +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.ResourceKeyed; +import org.spongepowered.api.entity.attribute.AttributeModifier; +import org.spongepowered.api.entity.attribute.AttributeOperation; + +public record AttributeModifierTemplate(ResourceKey key, AttributeOperation operation, double amountPerLevel) implements ResourceKeyed { + + public static AttributeModifierTemplate of( + final ResourceKey key, final Supplier operation, final double amountPerLevel + ) { + return AttributeModifierTemplate.of(key, Objects.requireNonNull(operation, "operation").get(), amountPerLevel); + } + + public static AttributeModifierTemplate of( + final ResourceKey key, final AttributeOperation operation, final double amountPerLevel + ) { + return new AttributeModifierTemplate(key, operation, amountPerLevel); + } + + public AttributeModifierTemplate( + final ResourceKey key, final AttributeOperation operation, final double amountPerLevel + ) { + this.key = Objects.requireNonNull(key, "key"); + this.operation = Objects.requireNonNull(operation, "operation"); + this.amountPerLevel = amountPerLevel; + } + + public AttributeModifier build(int amplifier) { + return AttributeModifier.builder() + .key(this.key) + .operation(this.operation) + .amount(this.amountPerLevel * (amplifier + 1)) + .build(); + } +} diff --git a/src/main/java/net/hellheim/spongetools/object/DataOperator.java b/src/main/java/net/hellheim/spongetools/object/DataOperator.java index 6121fa8..0254e74 100644 --- a/src/main/java/net/hellheim/spongetools/object/DataOperator.java +++ b/src/main/java/net/hellheim/spongetools/object/DataOperator.java @@ -1,11 +1,18 @@ package net.hellheim.spongetools.object; +import java.util.Arrays; +import java.util.Collection; import java.util.function.Supplier; +import java.util.stream.Stream; import org.spongepowered.api.data.Key; +import org.spongepowered.api.data.value.CollectionValue; import org.spongepowered.api.data.value.Value; import org.spongepowered.api.data.value.ValueContainer; +import com.google.common.collect.Streams; + +@SuppressWarnings("unchecked") public interface DataOperator> { /** @@ -44,7 +51,6 @@ default B supplyAll(final Supplier>> value * @param values The values to add * @return This builder, for chaining */ - @SuppressWarnings("unchecked") default B addAll(final Iterable> values) { values.forEach(this::add); return (B) this; @@ -66,9 +72,8 @@ default B supply(final Supplier> value) { * @param value The value to add * @return This builder, for chaining */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - default B add(final Value value) { - return (B) this.add((Key) value.key(), value.get()); + default B add(final Value value) { + return (B) this.add(value.key(), value.get()); } /** @@ -117,5 +122,69 @@ default B add(final Supplier>> key, final V */ B add(Key> key, V value); + default > B supplyAll(final Supplier>> key, final Supplier... elements) { + return this.addAll(key, Arrays.stream(elements).map(Supplier::get)); + } + + default > B supplyAll(final Supplier>> key, final Supplier> elements) { + return this.addAll(key, elements.get()); + } + + default > B supplyAll(final Key> key, final Supplier... elements) { + return this.addAll(key, Arrays.stream(elements).map(Supplier::get)); + } + + default > B supplyAll(final Key> key, final Supplier> elements) { + return this.addAll(key, elements.get()); + } + + default > B addAll(final Supplier>> key, final V... elements) { + return this.addAll(key.get(), elements); + } + + default > B addAll(final Supplier>> key, final Iterable elements) { + return this.addAll(key.get(), elements); + } + + default > B addAll(final Supplier>> key, final Stream elements) { + return this.addAll(key.get(), elements); + } + + default > B addAll(final Key> key, final V... elements) { + return this.addAll(key, Arrays.stream(elements)); + } + + default > B addAll(final Key> key, final Iterable elements) { + return this.addAll(key, Streams.stream(elements)); + } + + default > B addAll(final Key> key, final Stream elements) { + elements.forEach(element -> this.addSingle(key, element)); + return (B) this; + } + + default > B supplySingle(final Supplier>> key, final Supplier element) { + return this.addSingle(key.get(), element.get()); + } + + default > B supplySingle(final Key> key, final Supplier element) { + return this.addSingle(key, element.get()); + } + + default > B addSingle(final Supplier>> key, final V element) { + return this.addSingle(key.get(), element); + } + + /** + * Adds the given element to currently present for the given {@link Key}. + * TODO doc + * + * @param key The key to assign the element with + * @param element The element to assign with the key + * @param The type of the element + * @return The builder, for chaining + */ + > B addSingle(Key> key, V element); + B reset(); } diff --git a/src/main/java/net/hellheim/spongetools/object/ItemBuilder.java b/src/main/java/net/hellheim/spongetools/object/ItemBuilder.java index 419c980..1dc3021 100644 --- a/src/main/java/net/hellheim/spongetools/object/ItemBuilder.java +++ b/src/main/java/net/hellheim/spongetools/object/ItemBuilder.java @@ -92,7 +92,7 @@ public ItemStackSnapshot getAsItemStackSnapshot() { @Override public ItemStackLike getAsItemStackLike() { - return this.getAsItemStack(); + return this.stack; } @Override diff --git a/src/main/java/net/hellheim/spongetools/object/Streamable.java b/src/main/java/net/hellheim/spongetools/object/Streamable.java index f61ba59..b485cd4 100644 --- a/src/main/java/net/hellheim/spongetools/object/Streamable.java +++ b/src/main/java/net/hellheim/spongetools/object/Streamable.java @@ -1,19 +1,274 @@ package net.hellheim.spongetools.object; +import java.util.Comparator; import java.util.Iterator; +import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Spliterator; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.BinaryOperator; import java.util.function.Consumer; +import java.util.function.DoubleConsumer; +import java.util.function.Function; +import java.util.function.IntConsumer; +import java.util.function.IntFunction; +import java.util.function.LongConsumer; +import java.util.function.Predicate; import java.util.function.Supplier; +import java.util.function.ToDoubleFunction; +import java.util.function.ToIntFunction; +import java.util.function.ToLongFunction; +import java.util.stream.Collector; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; import java.util.stream.Stream; import com.google.common.collect.Streams; -public interface Streamable extends Iterable { +public interface Streamable extends Iterable, Stream { Stream stream(); - static Streamable stream(final Supplier> streamSupplier) { + @Override + Iterator iterator(); + + @Override + Spliterator spliterator(); + + @Override + void forEach(Consumer action); + + @Override + default boolean isParallel() { + return this.stream().isParallel(); + } + + @Override + default Streamable sequential() { + return of(() -> this.stream().sequential()); + } + + @Override + default Streamable parallel() { + return of(() -> this.stream().parallel()); + } + + @Override + default Streamable unordered() { + return of(() -> this.stream().unordered()); + } + + @Override + default Streamable onClose(final Runnable closeHandler) { + return of(() -> this.stream().onClose(closeHandler)); + } + + @Override + default void close() { + } + + @Override + default Streamable filter(final Predicate predicate) { + return of(() -> this.stream().filter(predicate)); + } + + @Override + default Streamable map(final Function mapper) { + return of(() -> this.stream().map(mapper)); + } + + @Override + default IntStream mapToInt(final ToIntFunction mapper) { + return this.stream().mapToInt(mapper); + } + + @Override + default LongStream mapToLong(final ToLongFunction mapper) { + return this.stream().mapToLong(mapper); + } + + @Override + default DoubleStream mapToDouble(final ToDoubleFunction mapper) { + return this.stream().mapToDouble(mapper); + } + + @Override + default Streamable flatMap(final Function> mapper) { + return of(() -> this.stream().flatMap(mapper)); + } + + @Override + default IntStream flatMapToInt(final Function mapper) { + return this.stream().flatMapToInt(mapper); + } + + @Override + default LongStream flatMapToLong(final Function mapper) { + return this.stream().flatMapToLong(mapper); + } + + @Override + default DoubleStream flatMapToDouble(final Function mapper) { + return this.stream().flatMapToDouble(mapper); + } + + @Override + default Streamable mapMulti(final BiConsumer> mapper) { + return of(() -> this.stream().mapMulti(mapper)); + } + + @Override + default IntStream mapMultiToInt(final BiConsumer mapper) { + return this.stream().mapMultiToInt(mapper); + } + + @Override + default LongStream mapMultiToLong(final BiConsumer mapper) { + return this.stream().mapMultiToLong(mapper); + } + + @Override + default DoubleStream mapMultiToDouble(final BiConsumer mapper) { + return this.stream().mapMultiToDouble(mapper); + } + + @Override + default Streamable distinct() { + return of(() -> this.stream().distinct()); + } + + @Override + default Streamable sorted() { + return of(() -> this.stream().sorted()); + } + + @Override + default Streamable sorted(final Comparator comparator) { + return of(() -> this.stream().sorted(comparator)); + } + + @Override + default Streamable peek(final Consumer action) { + return of(() -> this.stream().peek(action)); + } + + @Override + default Streamable limit(final long maxSize) { + return of(() -> this.stream().limit(maxSize)); + } + + @Override + default Streamable skip(final long n) { + return of(() -> this.stream().skip(n)); + } + + @Override + default Streamable takeWhile(final Predicate predicate) { + return of(() -> this.stream().takeWhile(predicate)); + } + + @Override + default Streamable dropWhile(final Predicate predicate) { + return of(() -> this.stream().dropWhile(predicate)); + } + + @Override + default void forEachOrdered(final Consumer action) { + this.stream().forEachOrdered(action); + } + + @Override + default Object[] toArray() { + return this.stream().toArray(); + } + + @Override + default A[] toArray(final IntFunction generator) { + return this.stream().toArray(generator); + } + + @Override + default T reduce(final T identity, final BinaryOperator accumulator) { + return this.stream().reduce(identity, accumulator); + } + + @Override + default Optional reduce(final BinaryOperator accumulator) { + return this.stream().reduce(accumulator); + } + + @Override + default U reduce( + final U identity, + final BiFunction accumulator, + final BinaryOperator combiner + ) { + return this.stream().reduce(identity, accumulator, combiner); + } + + @Override + default R collect( + final Supplier supplier, + final BiConsumer accumulator, + final BiConsumer combiner + ) { + return this.stream().collect(supplier, accumulator, combiner); + } + + @Override + default R collect(final Collector collector) { + return this.stream().collect(collector); + } + + @Override + default List toList() { + return this.stream().toList(); + } + + @Override + default Optional min(final Comparator comparator) { + return this.stream().min(comparator); + } + + @Override + default Optional max(Comparator comparator) { + return this.stream().max(comparator); + } + + @Override + default long count() { + return this.stream().count(); + } + + @Override + default boolean anyMatch(final Predicate predicate) { + return this.stream().anyMatch(predicate); + } + + @Override + default boolean allMatch(final Predicate predicate) { + return this.stream().allMatch(predicate); + } + + @Override + default boolean noneMatch(final Predicate predicate) { + return this.stream().noneMatch(predicate); + } + + @Override + default Optional findFirst() { + return this.stream().findFirst(); + } + + @Override + default Optional findAny() { + return this.stream().findAny(); + } + + static Streamable of(final Supplier> streamSupplier) { Objects.requireNonNull(streamSupplier, "streamSupplier"); return new Streamable() { @Override @@ -32,38 +287,37 @@ public Spliterator spliterator() { } @Override - public void forEach(Consumer action) { + public void forEach(final Consumer action) { this.stream().forEach(action); } }; } - static Streamable iterator(final Supplier> iteratorSupplier) { - Objects.requireNonNull(iteratorSupplier, "iteratorSupplier"); + static Streamable of(final Iterable iterable) { + Objects.requireNonNull(iterable, "iterable"); + if (iterable instanceof final Streamable streamable) { + return streamable; + } + return new Streamable() { - @Override - public Iterator iterator() { - return iteratorSupplier.get(); - } - @Override public Stream stream() { - return Streams.stream(this.iterator()); + return Streams.stream(iterable); } - }; - } - - static Streamable iterable(final Iterable iterable) { - Objects.requireNonNull(iterable, "iterable"); - return new Streamable() { + @Override public Iterator iterator() { return iterable.iterator(); } @Override - public Stream stream() { - return Streams.stream(iterable); + public Spliterator spliterator() { + return iterable.spliterator(); + } + + @Override + public void forEach(final Consumer action) { + iterable.forEach(action); } }; } diff --git a/src/main/java/net/hellheim/spongetools/object/TypedKey.java b/src/main/java/net/hellheim/spongetools/object/TypedKey.java new file mode 100644 index 0000000..48c4987 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/object/TypedKey.java @@ -0,0 +1,53 @@ +package net.hellheim.spongetools.object; + +import java.lang.reflect.Type; +import java.util.Objects; + +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.ResourceKeyed; + +import io.leangen.geantyref.GenericTypeReflector; +import io.leangen.geantyref.TypeToken; + +public record TypedKey(ResourceKey key, Type type) implements ResourceKeyed, Comparable> { + + public TypedKey(final ResourceKey key, final Type type) { + this.key = Objects.requireNonNull(key, "key"); + this.type = Objects.requireNonNull(type, "type"); + } + + public static TypedKey of(final ResourceKey key, final Type type) { + return new TypedKey<>(key, type); + } + + public static TypedKey of(final ResourceKey key, final TypeToken token) { + return TypedKey.of(key, token.getType()); + } + + public static TypedKey of(final ResourceKey key) { + return TypedKey.of(key, new TypeToken(){}.getType()); + } + + public boolean isInstance(final Object value) { + return value != null && GenericTypeReflector.erase(this.type).isInstance(value); + } + + public T cast(final Object value) { + @SuppressWarnings("unchecked") + final T casted = (T) value; + return casted; + } + + @Override + public int compareTo(final TypedKey key) { + return this.key().compareTo(key.key()); + } + + @Override + public final String toString() { + return "TypedKey{" + + "key=" + this.key.toString() + + ", type=" + this.type.toString() + + '}'; + } +} diff --git a/src/main/java/net/hellheim/spongetools/object/TypedKeyMap.java b/src/main/java/net/hellheim/spongetools/object/TypedKeyMap.java new file mode 100644 index 0000000..2a0ea0e --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/object/TypedKeyMap.java @@ -0,0 +1,286 @@ +package net.hellheim.spongetools.object; + +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.StringJoiner; + +import org.checkerframework.checker.nullness.qual.Nullable; + +public interface TypedKeyMap { + + static TypedKeyMap empty() { + return TypedKeyMap.Impl.EMPTY; + } + + static TypedKeyMap.Mutable create() { + return new TypedKeyMap.Impl.Mutable(); + } + + Set> keySet(); + + /** + * Returns whether this {@link TypedKeyMap} contains value for provided {@link TypedKey}. + * + * @param key The key + * @return True if this {@link TypedKeyMap} contains value for provided key + */ + boolean has(TypedKey key); + + /** + * Returns the value assosiated with provided {@link TypedKey} for this {@link TypedKeyMap}, + * or {@link Optional#empty()} if there is no value for key. + * + * @param The type of key + * @param key The key + * @return The value, if available + */ + Optional get(TypedKey key); + + /** + * Returns the value assosiated with provided {@link TypedKey} for this {@link TypedKeyMap}.
+ *
+ * If there is no value for key, {@link NoSuchElementException} will be thrown. + * + * @param The type of key + * @param key The key + * @return The value + * @throws NoSuchElementException If there is no value for provided key + */ + T require(TypedKey key); + + /** + * Returns the value assosiated with provided {@link TypedKey} for this {@link TypedKeyMap}, + * or defaultValue if there is no value for key. + * + * @param The type of key and default value + * @param key The key + * @param defaultValue The default value + * @return The value, or default if not set + */ + T getOrElse(TypedKey key, T defaultValue); + + /** + * Returns the value assosiated with provided {@link TypedKey} for this {@link TypedKeyMap}, + * or null if there is no value for key. + * + * @param The type of key + * @param key The key + * @return The value, or null if not set + */ + T getOrNull(TypedKey key); + + interface Mutable extends TypedKeyMap { + + /** + * Sets value for the provided {@link TypedKey} for this {@link TypedKeyMap}.
+ * Returns the previously assosiated value, or {@link Optional#empty()} if there was no value for key. + * + * @param The type of key and value + * @param key The key + * @param value The value + * @return Previously assotiated value for key, if present + */ + Optional set(TypedKey key, T value); + + /** + * Removes provided {@link TypedKey} for this {@link TypedKeyMap}.
+ * Returns the previously assosiated value, or {@link Optional#empty()} if there was no value for key. + * + * @param The type of key + * @param key The key + * @return Previously assotiated value for key, if present + */ + Optional remove(TypedKey key); + + /** + * Sets value for the specified {@link TypedKey} for this {@link TypedKeyMap} + * only if provided {@link Optional} is present. + * + * @param The type of key and value + * @param key The key + * @param optionalValue The optional value + */ + default void trySet(final TypedKey key, final Optional optValue) { + optValue.ifPresent(value -> this.set(key, value)); + } + + /** + * If provided {@link Optional} is present, sets its value for the specified {@link TypedKey}.
+ * If the {@link Optional} is empty, removes provided {@link TypedKey} for this {@link TypedKeyMap}. + * + * @param + * @param key + * @param optValue + */ + default void apply(final TypedKey key, final Optional optValue) { + optValue.ifPresentOrElse(value -> this.set(key, value), () -> this.remove(key)); + } + } + + interface Proxy extends TypedKeyMap { + + /** + * Returns the underlying {@link TypedKeyMap} for this {@link TypedKeyMap.Proxy}. + * + * @return The underlying {@link TypedKeyMap}. + */ + TypedKeyMap data(); + + @Override + default Set> keySet() { + return this.data().keySet(); + } + + @Override + default boolean has(final TypedKey key) { + return this.data().has(key); + } + + @Override + default Optional get(final TypedKey key) { + return this.data().get(key); + } + + @Override + default T require(final TypedKey key) { + return this.data().require(key); + } + + @Override + default T getOrElse(final TypedKey key, final T defaultValue) { + return this.data().getOrElse(key, defaultValue); + } + + @Override + default T getOrNull(final TypedKey key) { + return this.data().getOrNull(key); + } + + interface Mutable extends Proxy, TypedKeyMap.Mutable { + + @Override + TypedKeyMap.Mutable data(); + + @Override + default Optional set(final TypedKey key, final T value) { + return this.data().set(key, value); + } + + @Override + default Optional remove(final TypedKey key) { + return this.data().remove(key); + } + + @Override + default void trySet(final TypedKey key, final Optional optValue) { + this.data().trySet(key, optValue); + } + + @Override + default void apply(final TypedKey key, final Optional optValue) { + this.data().apply(key, optValue); + } + } + } + + class Impl implements TypedKeyMap { + + private static final TypedKeyMap EMPTY = new Impl(Map.of()); + + protected final Map, Object> values; + + protected Impl(final Map, Object> emptyMap) { + this.values = emptyMap; + } + + @Override + public Set> keySet() { + return this.values.keySet(); + } + + @Override + public boolean has(final TypedKey key) { + return this.values.containsKey(key); + } + + @Override + public Optional get(final TypedKey key) { + return Optional.ofNullable(key.cast(this.values.get(key))); + } + + @Override + public T require(final TypedKey key) { + final @Nullable Object value = this.values.get(key); + if (value == null) { + throw new NoSuchElementException("Could not retrieve value for key " + key.toString()); + } + return key.cast(value); + } + + @Override + public T getOrElse(final TypedKey key, final T defaultValue) { + return key.cast(this.values.getOrDefault(key, defaultValue)); + } + + @Override + public T getOrNull(final TypedKey key) { + return key.cast(this.values.get(key)); + } + + @Override + public int hashCode() { + return this.values.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof final TypedKeyMap that) { + if (this.keySet().size() != that.keySet().size()) { + return false; + } + + for (final TypedKey key : that.keySet()) { + if (!this.has(key) || !Objects.equals(this.require(key), that.require(key))) { + return false; + } + } + + return true; + } else { + return false; + } + } + + @Override + public String toString() { + final StringJoiner joiner = new StringJoiner(", "); + for (Map.Entry, Object> entry : this.values.entrySet()) { + joiner.add("\"" + entry.getKey().toString() + "\"=" + entry.getValue().toString()); + } + return "Context[" + joiner.toString() + "]"; + } + + public static class Mutable extends Impl implements TypedKeyMap.Mutable { + + protected Mutable() { + super(new HashMap<>()); + } + + @Override + public Optional set(final TypedKey key, final T value) { + return Optional.ofNullable(key.cast(this.values.put(key, Objects.requireNonNull(value, "value")))); + } + + @Override + public Optional remove(final TypedKey key) { + return Optional.ofNullable(key.cast(this.values.remove(key))); + } + } + } +} diff --git a/src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java b/src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java index cc2da63..c07c140 100644 --- a/src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java +++ b/src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java @@ -1,22 +1,64 @@ package net.hellheim.spongetools.object; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; -import java.util.Set; +import java.util.Iterator; +import java.util.Map; +import java.util.stream.Stream; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.data.DataManipulator; import org.spongepowered.api.data.Key; +import org.spongepowered.api.data.value.CollectionValue; +import org.spongepowered.api.data.value.ListValue; +import org.spongepowered.api.data.value.SetValue; import org.spongepowered.api.data.value.Value; +import org.spongepowered.api.data.value.WeightedCollectionValue; +import org.spongepowered.api.util.weighted.WeightedTable; + +import io.leangen.geantyref.GenericTypeReflector; public class ValueSetBuilder implements DataOperator { - protected final Set> values = new HashSet<>(); + protected final Map, Value> values = new HashMap<>(); @Override public ValueSetBuilder add(final Key> key, final V value) { - this.values.add(Value.immutableOf(key, value)); + this.values.put(key, Value.immutableOf(key, value)); return this; } + @Override + public > ValueSetBuilder addAll(final Key> key, final Stream stream) { + final Iterator iterator = stream.iterator(); + if (!iterator.hasNext()) { + return this; + } + + @SuppressWarnings("unchecked") + final @Nullable CollectionValue elements = (CollectionValue) this.values.get(key); + final C newElements = createCollection(key); + if (elements != null) { + newElements.addAll(elements.all()); + } + iterator.forEachRemaining(newElements::add); + return this.add(key, newElements); + } + + @Override + public > ValueSetBuilder addSingle(final Key> key, final V element) { + @SuppressWarnings("unchecked") + final @Nullable CollectionValue elements = (CollectionValue) this.values.get(key); + final C newElements = createCollection(key); + if (elements != null) { + newElements.addAll(elements.all()); + } + newElements.add(element); + return this.add(key, newElements); + } + @Override public ValueSetBuilder reset() { this.values.clear(); @@ -24,10 +66,24 @@ public ValueSetBuilder reset() { } public DataManipulator.Mutable asMutableManipulator() { - return DataManipulator.mutableOf(this.values); + return DataManipulator.mutableOf(this.values.values()); } public DataManipulator.Immutable asImmutableManipulator() { - return DataManipulator.immutableOf(this.values); + return DataManipulator.immutableOf(this.values.values()); + } + + @SuppressWarnings("unchecked") + private static > C createCollection(final Key> key) { + final Class rawType = GenericTypeReflector.erase(key.valueType()); + if (ListValue.class.isAssignableFrom(rawType)) { + return (C) new ArrayList<>(); + } else if (SetValue.class.isAssignableFrom(rawType)) { + return (C) new HashSet<>(); + } else if (WeightedCollectionValue.class.isAssignableFrom(rawType)) { + return (C) new WeightedTable<>(); + } + + throw new IllegalArgumentException("Unknown CollectionValue type: " + rawType); } } diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java b/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java index d212b6f..165e17e 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java @@ -21,15 +21,15 @@ public final class ModelPartFace { public static final int DEFAULT_TINT = -1; - public static final Rotation DEFAULT_ROTATION = GeomUtil.ROT_0; - public static final Codec CODEC = RecordCodecBuilder.create( + public static final Supplier DEFAULT_ROTATION = GeomUtil.ROT_0; + public static final Codec CODEC = Codec.lazyInitialized(() -> RecordCodecBuilder.create( instance -> instance.group( TextureSlot.CODEC_HASHED.fieldOf("texture").forGetter(ModelPartFace::texture), MathCodecs.MATRIX2D.optionalFieldOf("uv").forGetter(ModelPartFace::uv), SpongeCodecs.CARDINAL_DIRECTION.optionalFieldOf("cullface").forGetter(ModelPartFace::cullface), - SpongeCodecs.ROTATION_BY_ANGLE.optionalFieldOf("rotation", ModelPartFace.DEFAULT_ROTATION).forGetter(ModelPartFace::rotation), + SpongeCodecs.ROTATION_BY_ANGLE.optionalFieldOf("rotation", ModelPartFace.DEFAULT_ROTATION.get()).forGetter(ModelPartFace::rotation), Codec.INT.optionalFieldOf("tintindex", ModelPartFace.DEFAULT_TINT).forGetter(ModelPartFace::tintIndex) - ).apply(instance, ModelPartFace::new)); + ).apply(instance, ModelPartFace::new))); private final TextureSlot texture; private final Optional uv; @@ -150,7 +150,7 @@ public Builder reset() { this.texture = null; this.uv = null; this.cullface = null; - this.rotation = ModelPartFace.DEFAULT_ROTATION; + this.rotation = ModelPartFace.DEFAULT_ROTATION.get(); this.tintIndex = ModelPartFace.DEFAULT_TINT; return this; } diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java b/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java index a570eb2..7ed4061 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java @@ -14,7 +14,7 @@ public final class ModelPartRotation { - public static final Codec CODEC = RecordCodecBuilder.create( + public static final Codec CODEC = RecordCodecBuilder.create( instance -> instance.group( MathCodecs.VECTOR3D.fieldOf("origin").forGetter(ModelPartRotation::origin), SpongeCodecs.AXIS.fieldOf("axis").forGetter(ModelPartRotation::axis), diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java index 1aff037..e58a196 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java @@ -14,9 +14,9 @@ public final class VariantProperties { public static final VariantProperty MODEL = property("model", SpongeCodecs.RESOURCE_KEY, Optional.empty()); - public static final VariantProperty X_ROT = property("x", SpongeCodecs.ROTATION_BY_ANGLE, Optional.of(GeomUtil.ROT_0)); + public static final VariantProperty X_ROT = property("x", SpongeCodecs.ROTATION_BY_ANGLE, Optional.of(GeomUtil.ROT_0.get())); - public static final VariantProperty Y_ROT = property("y", SpongeCodecs.ROTATION_BY_ANGLE, Optional.of(GeomUtil.ROT_0)); + public static final VariantProperty Y_ROT = property("y", SpongeCodecs.ROTATION_BY_ANGLE, Optional.of(GeomUtil.ROT_0.get())); public static final VariantProperty UV_LOCK = property("uvlock", Codec.BOOL, Optional.of(false)); diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java index 14ed502..c4ca9f3 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java @@ -5,11 +5,13 @@ import java.util.function.Supplier; import org.spongepowered.api.data.type.StringRepresentable; +import org.spongepowered.api.util.annotation.CatalogedBy; import com.mojang.serialization.Codec; import net.hellheim.spongetools.codec.LateBoundIdMapper; +@CatalogedBy(VariantProperties.class) public record VariantProperty(String name, Codec valueCodec, Optional defaultValue) implements StringRepresentable { diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java b/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java index 4f63c91..a4491df 100644 --- a/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java +++ b/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java @@ -123,7 +123,7 @@ record World() implements SelectProperty> { } } - record Entity() implements SelectProperty>> { + record Entity() implements SelectProperty>> { public static final Entity INSTANCE = new Entity(); public static final MapCodec CODEC = MapCodec.unit(INSTANCE); public static final MapCodec> SWITCH = SelectProperty.create(CODEC, SpongeCodecs.registryKey(RegistryTypes.ENTITY_TYPE)); diff --git a/src/main/java/net/hellheim/spongetools/util/CompUtil.java b/src/main/java/net/hellheim/spongetools/util/CompUtil.java index 41cf28c..1028612 100644 --- a/src/main/java/net/hellheim/spongetools/util/CompUtil.java +++ b/src/main/java/net/hellheim/spongetools/util/CompUtil.java @@ -21,6 +21,7 @@ */ public final class CompUtil { + public static String toPlain(final Component comp) { return toString(Types.plain(), comp); } diff --git a/src/main/java/net/hellheim/spongetools/util/EffectUtil.java b/src/main/java/net/hellheim/spongetools/util/EffectUtil.java index 3daceb3..9154950 100644 --- a/src/main/java/net/hellheim/spongetools/util/EffectUtil.java +++ b/src/main/java/net/hellheim/spongetools/util/EffectUtil.java @@ -1,11 +1,17 @@ package net.hellheim.spongetools.util; +import java.util.HashMap; +import java.util.Map; import java.util.function.Supplier; +import org.spongepowered.api.Sponge; import org.spongepowered.api.effect.potion.PotionEffect; import org.spongepowered.api.effect.potion.PotionEffectType; +import org.spongepowered.api.entity.attribute.AttributeModifier; +import org.spongepowered.api.entity.attribute.type.AttributeType; import org.spongepowered.api.util.Ticks; +import net.hellheim.spongetools.object.AttributeModifierTemplate; import net.hellheim.spongetools.proxy.solid.PotionEffectProxy; import net.hellheim.spongetools.proxy.solid.PotionEffectTypeProxy; @@ -80,6 +86,55 @@ public static PotionEffect of(PotionEffect effect) { return effect; } + + public static Map attributes(final PotionEffectProxy effect) { + return EffectUtil.attributes(effect.getAsPotionEffect()); + } + + public static Map attributes(final Supplier effect) { + return EffectUtil.attributes(effect.get()); + } + + public static Map attributes(final PotionEffect effect) { + return EffectUtil.attributes(effect.type(), effect.amplifier()); + } + + public static Map attributes(final PotionEffectTypeProxy type, final int amplifier) { + return EffectUtil.attributes(type.getAsPotionEffectType(), amplifier); + } + + public static Map attributes(final Supplier type, final int amplifier) { + return EffectUtil.attributes(type.get(), amplifier); + } + + public static Map attributes(final PotionEffectType type, final int amplifier) { + final Map modifiers = new HashMap<>(); + EffectUtil.attributeTemplates(type).forEach( + (attribute, template) -> modifiers.put(attribute, template.build(amplifier))); + return modifiers; + } + + public static Map attributeTemplates(final PotionEffectTypeProxy type) { + return EffectUtil.attributeTemplates(type.getAsPotionEffectType()); + } + + public static Map attributeTemplates(final Supplier type) { + return EffectUtil.attributeTemplates(type.get()); + } + + public static Map attributeTemplates(final PotionEffectType type) { + return EffectUtil.factory().modifierTemplates(type); + } + + private static Factory factory() { + return Sponge.game().factoryProvider().provide(Factory.class); + } + + public interface Factory { + + Map modifierTemplates(PotionEffectType type); + } + private EffectUtil() { } } diff --git a/src/main/java/net/hellheim/spongetools/util/EventUtil.java b/src/main/java/net/hellheim/spongetools/util/EventUtil.java index 7919e3e..a7adc03 100644 --- a/src/main/java/net/hellheim/spongetools/util/EventUtil.java +++ b/src/main/java/net/hellheim/spongetools/util/EventUtil.java @@ -1,6 +1,7 @@ package net.hellheim.spongetools.util; import java.util.HashMap; +import java.util.Map; import java.util.function.Supplier; import org.apache.commons.lang3.mutable.MutableInt; @@ -15,6 +16,7 @@ import org.spongepowered.api.block.transaction.Operations; import org.spongepowered.api.command.CommandCause; import org.spongepowered.api.command.parameter.CommandContext; +import org.spongepowered.api.data.type.StringRepresentable; import org.spongepowered.api.event.Cause; import org.spongepowered.api.event.Event; import org.spongepowered.api.event.EventContext; @@ -63,8 +65,9 @@ private static StringList list(final Event e) { if (bt.custom().isPresent()) { tr.add(DASH + "Default: " + toString(bt.defaultReplacement())); tr.add(DASH + "Custom: " + toString(bt.custom().get())); + } else { + tr.add(DASH + "Final: " + toString(bt.finalReplacement())); } - tr.add(DASH + "Final: " + toString(bt.finalReplacement())); tr.shift(SHIFT); tr.add(0, DASH + "Transaction №" + counter.getAndIncrement() + ":"); @@ -120,10 +123,8 @@ private static StringList list(final Cause cause, final String name) { cause.forEach(o -> { if (o instanceof Event) { result.addAll(list((Event) o)); - } else if (o instanceof LocatableBlock) { - result.add(DASH + "LocatableBlock: " + toString((LocatableBlock) o)); } else { - result.add(DASH + o.getClass().getSimpleName()); + result.add(DASH + objectToString(o, () -> o.getClass().getSimpleName())); } }); @@ -135,7 +136,7 @@ private static StringList list(final Cause cause, final String name) { private static StringList list(final EventContext context, final String name) { final StringList result = new StringList(); context.asMap().forEach((key, o) -> { - result.add(DASH + key.key().asString() + " - " + o.toString()); + result.add(DASH + key.key().asString() + DASH + objectToString(o, o::toString)); }); result.add(0, "Context of " + name); @@ -143,19 +144,43 @@ private static StringList list(final EventContext context, final String name) { return result; } + private static String objectToString(final Object object, final Supplier defaultString) { + return switch (object) { + case BlockSnapshot bs -> toString(bs); + case LocatableBlock lb -> toString(lb); + case StringRepresentable sr -> toString(sr); + case Enum en -> toString(en); + default -> defaultString.get(); + }; + } + + private static String toString(final StringRepresentable sr) { + return sr.getClass().getSimpleName() + " " + sr.serializationString().toUpperCase(); + } + + private static String toString(final Enum en) { + return en.getClass().getSimpleName() + " " + en.name(); + } + private static String toString(final BlockSnapshot bs) { - return toString(bs.world(), bs.position(), bs.state()); + return "BlockSnapshot{" + + toString(bs.world(), bs.position(), bs.state()) + + "}"; } + private static String toString(final LocatableBlock lb) { - return toString(lb.serverLocation().worldKey(), lb.blockPosition(), lb.blockState()); + return "LocatableBlock{" + + toString(lb.serverLocation().worldKey(), lb.blockPosition(), lb.blockState()) + + "}"; } + private static String toString(final ResourceKey world, final Vector3i pos, final BlockState state) { - return "World=" + world.asString() + "; " + - "Loc=" + pos.toString() + "; " + - "State=" + state.asString() + ";"; + return "world=" + world.asString() + "; " + + "pos=" + pos.toString() + "; " + + "state=" + state.asString(); } - private static final HashMap OPERATIONS = new HashMap<>(); + private static final Map OPERATIONS = new HashMap<>(); static { OPERATIONS.put(Operations.BREAK.get(), "BREAK"); OPERATIONS.put(Operations.PLACE.get(), "PLACE"); diff --git a/src/main/java/net/hellheim/spongetools/util/GeomUtil.java b/src/main/java/net/hellheim/spongetools/util/GeomUtil.java index 3031778..08ed434 100644 --- a/src/main/java/net/hellheim/spongetools/util/GeomUtil.java +++ b/src/main/java/net/hellheim/spongetools/util/GeomUtil.java @@ -23,6 +23,8 @@ import org.spongepowered.math.vector.Vector3i; import org.spongepowered.math.vector.Vector3l; +import com.google.common.base.Suppliers; + import net.hellheim.spongetools.function.IntBiConsumer; import net.hellheim.spongetools.function.IntTriConsumer; import net.hellheim.spongetools.math.mutable.vector.MutableVector3i; @@ -30,13 +32,12 @@ public final class GeomUtil { - // Relies on implementation where these are enum values meaning they should always be available. - public static final Rotation ROT_0 = Rotations.NONE.get(); - public static final Rotation ROT_90 = Rotations.CLOCKWISE_90.get(); - public static final Rotation ROT_180 = Rotations.CLOCKWISE_180.get(); - public static final Rotation ROT_270 = Rotations.COUNTERCLOCKWISE_90.get(); - private static final List ROTATION_VALUES = - List.of(ROT_0, ROT_90, ROT_180, ROT_270); + public static final Supplier ROT_0 = Suppliers.memoize(Rotations.NONE::get); + public static final Supplier ROT_90 = Suppliers.memoize(Rotations.CLOCKWISE_90::get); + public static final Supplier ROT_180 = Suppliers.memoize(Rotations.CLOCKWISE_180::get); + public static final Supplier ROT_270 = Suppliers.memoize(Rotations.COUNTERCLOCKWISE_90::get); + private static final Supplier> ROTATION_VALUES = Suppliers.memoize(() -> + List.of(ROT_0.get(), ROT_90.get(), ROT_180.get(), ROT_270.get())); private static final List DIR_CARDINAL = Arrays.stream(Direction.values()) .filter(Direction::isCardinal) @@ -105,7 +106,7 @@ public static boolean is270(final Rotation rotation) { } public static List rotations() { - return ROTATION_VALUES; + return ROTATION_VALUES.get(); } public static List cardinalDirections() { @@ -130,13 +131,13 @@ public static Optional rotation(final Direction from, final Direction } if (GeomUtil.is(from, to)) { - return Optional.of(GeomUtil.ROT_0); + return Optional.of(GeomUtil.ROT_0.get()); } else if (from.isOpposite(to)) { - return Optional.of(GeomUtil.ROT_180); + return Optional.of(GeomUtil.ROT_180.get()); } else if (DIR_CLOCKWISE_90.get(from) == to) { - return Optional.of(GeomUtil.ROT_90); + return Optional.of(GeomUtil.ROT_90.get()); } else if (DIR_COUNTERCLOCKWISE_90.get(from) == to) { - return Optional.of(GeomUtil.ROT_270); + return Optional.of(GeomUtil.ROT_270.get()); } return Optional.empty(); @@ -355,9 +356,6 @@ public static void forEachInCircle(final int x0, final int y0, final int radius, for (int x = -radius; x <= radius; ++x) { final int x2 = x * x; final int y2max = rad2 - x2; - if (y2max < 0) { - break; - } action.accept(x0, y0); for (int y = 1; y*y <= y2max; ++y) { @@ -373,7 +371,7 @@ public static Streamable cardinalNeighbours(final Vector3i pos) public static Streamable cardinalNeighbours(final int x, final int y, final int z) { final MutableVector3i cursor = MutableVector3i.zero(); - return Streamable.stream(() -> GeomUtil.cardinalDirections().stream() + return Streamable.of(() -> GeomUtil.cardinalDirections().stream() .map(dir -> cursor.set(x, y, z).add(dir.asBlockOffset()))); } diff --git a/src/main/java/net/hellheim/spongetools/util/ItemUtil.java b/src/main/java/net/hellheim/spongetools/util/ItemUtil.java index a5ab7a2..1415104 100644 --- a/src/main/java/net/hellheim/spongetools/util/ItemUtil.java +++ b/src/main/java/net/hellheim/spongetools/util/ItemUtil.java @@ -202,8 +202,9 @@ public static boolean is(final ItemType i1, final ItemType i2) { - public static boolean similar(final ItemStack i1, final ItemStack i2) { - return ItemStackComparators.TYPE.get().compare(i1, i2) == 0;//TODO replace TYPE with IGNORE_SIZE + public static boolean similar(final ItemStackLike i1, final ItemStackLike i2) { + // TODO change in API to use ItemStackLike + return ItemStackComparators.IGNORE_SIZE.get().compare(i1.asMutable(), i2.asMutable()) == 0; } From 1c996803b8a3c2bf54752e0cb4a9e23553eeb374 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Thu, 9 Oct 2025 01:59:12 +0300 Subject: [PATCH 21/55] continue custom stuff --- build.gradle | 2 +- .../type/item/CustomItemTypeProperties.java | 8 +- .../custom/type/item/EitherItemType.java | 5 +- .../custom/type/item/LoreApplicator.java | 140 ++++++++++++++++++ .../custom/type/item/LoreProcessor.java | 128 ++++++---------- .../custom/type/item/LoreProvider.java | 5 +- .../spongetools/object/ItemBuilder.java | 13 +- .../hellheim/spongetools/util/EventUtil.java | 111 +++++++++++--- .../hellheim/spongetools/util/ItemUtil.java | 8 - 9 files changed, 300 insertions(+), 120 deletions(-) create mode 100644 src/main/java/net/hellheim/spongetools/custom/type/item/LoreApplicator.java diff --git a/build.gradle b/build.gradle index b924e7a..a3cd7b7 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ repositories { dependencies { // SpongeAPI - api 'org.spongepowered:spongeapi:14.0.0-SNAPSHOT' + api 'org.spongepowered:spongeapi:14.1.0-SNAPSHOT' // DataFixerUpper api 'com.mojang:datafixerupper:8.0.16' diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java index e3c5f08..609f6af 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java @@ -151,6 +151,10 @@ public ItemStackSnapshot getAsItemStackSnapshot() { return this.snapshot.getAsItemStackSnapshot(); } + protected LoreApplicator loreApplicator() { + return LoreApplicator.empty(); + } + protected ItemBuilder iconBuilder() { final ItemBuilder item = ItemBuilder.of(this.base); this.getValue(Keys.ITEM_NAME).ifPresent(item::offer); @@ -163,7 +167,9 @@ protected ItemBuilder ingredientIconBuilder() { } protected ItemBuilder snapshotBuilder() { - return ItemBuilder.of(this.icon).copyFrom(this.data); + return this.iconBuilder() + .copyFrom(this.data) + .lore(this.loreApplicator()); } public static class Builder implements diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java b/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java index 30c763c..d388eb4 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java @@ -16,6 +16,7 @@ import org.spongepowered.api.registry.DefaultedRegistryType; import org.spongepowered.api.registry.RegistryTypes; +import com.google.common.base.Suppliers; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; @@ -125,9 +126,11 @@ protected static final class Common extends EitherItemType implements ItemTypeProxy { private final ItemType type; + private final Supplier key; protected Common(final ItemType type) { this.type = Objects.requireNonNull(type, "type"); + this.key = Suppliers.memoize(() -> this.type.key(RegistryTypes.ITEM_TYPE)); } @Override @@ -152,7 +155,7 @@ public Component asComponent() { @Override public ResourceKey key() { - return this.type.key(RegistryTypes.ITEM_TYPE); + return this.key.get(); } @Override diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/LoreApplicator.java b/src/main/java/net/hellheim/spongetools/custom/type/item/LoreApplicator.java new file mode 100644 index 0000000..c178c83 --- /dev/null +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/LoreApplicator.java @@ -0,0 +1,140 @@ +package net.hellheim.spongetools.custom.type.item; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; + +import net.hellheim.spongetools.object.TypedKeyMap; + +/** + * The utility class to apply {@link LoreProcessor} and {@link LoreProvider}s to the item. + */ +public record LoreApplicator( + /** + * Optional lore processor to use if absent on item + */ + Optional defaultProcessor, + /** + * Optional lore providers to use if absent on item + */ + Optional> defaultProviders + ) { + + private static final LoreApplicator EMPTY = new LoreApplicator(Optional.empty(), Optional.empty()); + + public LoreApplicator( + final Optional defaultProcessor, final Optional> defaultProviders + ) { + this.defaultProcessor(); + this.defaultProcessor = Objects.requireNonNull(defaultProcessor, "defaultProcessor"); + this.defaultProviders = Objects.requireNonNull(defaultProviders, "defaultProviders"); + } + + /** + * Returns lore applicator without fallback processor and providers. + * + * @return Lore applicator without fallback processor and providers + */ + public static LoreApplicator empty() { + return LoreApplicator.EMPTY; + } + + /** + * Returns lore applicator with given fallback processor. + * + * @param defaultProcessor Lore processor to use if absent on item + * @return Lore applicator with the given arguments + */ + public static LoreApplicator of(final LoreProcessor defaultProcessor) { + return LoreApplicator.of(Optional.of(defaultProcessor), Optional.empty()); + } + + /** + * Returns lore applicator with given fallback providers. + * + * @param defaultProviders Lore providers to use if absent on item + * @return Lore applicator with the given arguments + */ + public static LoreApplicator of(final List defaultProviders) { + return LoreApplicator.of(Optional.empty(), Optional.of(defaultProviders)); + } + + /** + * Returns lore applicator with given fallback processor and providers. + * + * @param defaultProcessor Lore processor to use if absent on item + * @param defaultProviders Lore providers to use if absent on item + * @return Lore applicator with the given arguments + */ + public static LoreApplicator of(final LoreProcessor defaultProcessor, final List defaultProviders) { + return LoreApplicator.of(Optional.of(defaultProcessor), Optional.of(defaultProviders)); + } + + /** + * Returns lore applicator with given fallback processor and providers. + * + * @param defaultProcessor Optional lore processor to use if absent on item + * @param defaultProviders Optional lore providers to use if absent on item + * @return Lore applicator with the given arguments + */ + public static LoreApplicator of( + final Optional defaultProcessor, final Optional> defaultProviders + ) { + if (defaultProcessor.isEmpty() && defaultProviders.isEmpty()) { + return LoreApplicator.empty(); + } + + return new LoreApplicator(defaultProcessor, defaultProviders); + } + + /** + * Processes and applies lore to the given item with the given context.
+ * Given item is modified only if following conditions are met:
+ * - Item contains {@link LoreProcessor#dataKey()} or {@link #defaultProcessor()} is present;
+ * - Item contains {@link LoreProvider#dataKey()} or {@link #defaultProviders()} is present.
+ * Item's processor and providers are preferred over this applicator's ones.
+ * Moreover, modifications (if any) are applied to + * {@link ItemStackLike#asMutable()} of the given stack.
+ * If there are no modifications to apply, the original stack is returned. + * + * @param stack The item to apply lore to + * @param context The context to use lore providers with + * @return The modified item or the original item if no modifications were made + */ + public ItemStackLike apply(final ItemStackLike stack, final TypedKeyMap context) { + return stack.get(LoreProcessor.dataKey()) + .or(this::defaultProcessor) + .map(processor -> stack.get(LoreProvider.dataKey()) + .or(this::defaultProviders) + .map(providers -> { + final ItemStack mutable = stack.asMutable(); + mutable.offer(processor.processValue(stack, context, providers)); + providers.forEach(provider -> + provider.loreHidingKeys().forEach(key -> + mutable.offer(key, true))); + return (ItemStackLike) mutable; + }) + .orElse(null)) + .orElse(stack); + } + + /** + * Processes and applies lore to the given item with empty context.
+ * Given item is modified only if following conditions are met:
+ * - Item contains {@link LoreProcessor#dataKey()} or {@link #defaultProcessor()} is present;
+ * - Item contains {@link LoreProvider#dataKey()} or {@link #defaultProviders()} is present.
+ * Item's processor and providers are preferred over this applicator's ones.
+ * Moreover, modifications (if any) are applied to + * {@link ItemStackLike#asMutable()} of the given stack.
+ * If there are no modifications to apply, the original stack is returned. + * + * @param stack The item to apply lore to + * @return The modified item or the original item if no modifications were made + */ + public ItemStackLike apply(final ItemStackLike stack) { + return this.apply(stack, TypedKeyMap.empty()); + } +} diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java b/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java index 7e55b09..7e7af59 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java @@ -10,7 +10,6 @@ import org.spongepowered.api.data.persistence.DataBuilder; import org.spongepowered.api.data.value.ListValue; import org.spongepowered.api.data.value.Value; -import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.registry.DefaultedRegistryType; import org.spongepowered.api.util.CopyableBuilder; @@ -20,13 +19,14 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.AdventureCodecs; import net.hellheim.spongetools.codec.list.DataCodecs; import net.hellheim.spongetools.codec.list.RegistryCodecs; import net.hellheim.spongetools.object.CodecDataSerializable; import net.hellheim.spongetools.object.TypedKeyMap; import net.hellheim.spongetools.proxy.solid.codec.MapCodecProxy; -import net.hellheim.spongetools.proxy.solid.item.IItemProxy; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.Style; public interface LoreProcessor extends CodecDataSerializable, MapCodecProxy { @@ -49,22 +49,16 @@ static DataBuilder dataBuilder() { return DataCodecs.dataBuilder(CODEC); } - static LoreProcessor.Plain plain() { + static Plain plain() { return Plain.INSTANCE; } - static LoreProcessor.Separated.Builder separated() { - return new LoreProcessor.Separated.Builder(); + static ApplyFallbackStyle applyFallbackStyle(final LoreProcessor processor, final Style style) { + return new ApplyFallbackStyle(processor, style); } - static ItemStackLike apply(final ItemStackLike stack, final TypedKeyMap context) { - return stack.get(LoreProcessor.dataKey()) - .map(processor -> processor.apply(stack, context)) - .orElse(stack); - } - - static ItemStackLike apply(final IItemProxy stack, final TypedKeyMap context) { - return LoreProcessor.applyProcessor(stack.getAsItemStackLike(), context); + static Separated.Builder separated() { + return new Separated.Builder(); } /** @@ -83,77 +77,10 @@ default ListValue processValue( return ListValue.immutableOf(Keys.LORE, this.process(stack, context, providers)); } - /** - * Processes and applies given lore providers to the given item.
- * If the item is mutable, it is modified and returned.
- * If the item is immutable, its mutable copy is modified and returned. - * - * @param stack The stack to apply lore to - * @param context The context to use providers with - * @param providers The list of lore providers - * @return The stack with applied lore - * - default ItemStack apply(final ItemStackLike stack, final TypedKeyMap context, final List providers) { - final ItemStack mutable = stack.asMutable(); - mutable.offer(Keys.LORE, this.process(stack, context, providers)); - providers.forEach(provider -> - provider.loreHidingKeys().forEach(key -> - mutable.offer(key, true))); - return mutable; - } - - /** - * Processes and applies lore to the given item.
- * If item does not have any lore providers, then empty list is used.
- * If item is mutable, it is modified and returned.
- * If item is immutable, its mutable copy is modified and returned. - * - * @param stack The stack to apply lore to - * @param context The context to use providers with - * @return The stack with applied lore - * - default ItemStack apply(final ItemStackLike stack, final TypedKeyMap context) { - return this.apply(stack, context, stack.getOrElse(LoreProvider.dataKey(), List.of())); - } - - /** - * Uses {@link #apply(ItemStackLike, TypedKeyMap)} with {@link IItemProxy#getAsItemStackLike()}. - * - * @param stack The stack to apply lore to - * @param context The context to use providers with - * @return The stack with applied lore - * - default ItemStack apply(final IItemProxy stack, final TypedKeyMap context) { - return this.apply(stack.getAsItemStackLike(), context); + default LoreProcessor withFallbackStyle(final Style style) { + return LoreProcessor.applyFallbackStyle(this, style); } - /** - * Processes and applies lore to the given item.
- * If item does not have any lore providers, then the original stack is returned.
- * If item is mutable, it is modified and returned.
- * If item is immutable, its mutable copy is modified and returned. - * - * @param stack The stack to apply lore to - * @param context The context to use providers with - * @return The stack with applied lore, or original stack - * - default ItemStackLike applyIfPresent(final ItemStackLike stack, final TypedKeyMap context) { - return stack.get(LoreProvider.dataKey()) - .map(providers -> this.apply(stack, context, providers)) - .orElse(stack); - } - - /** - * Uses {@link #applyIfPresent(ItemStackLike, TypedKeyMap)} with {@link IItemProxy#getAsItemStackLike()}. - * - * @param stack The stack to apply lore to - * @param context The context to use providers with - * @return The stack with applied lore, or original stack - * - default ItemStackLike applyIfPresent(final IItemProxy stack, final TypedKeyMap context) { - return this.applyIfPresent(stack.getAsItemStackLike(), context); - } - */ @Override default Codec codec() { return CODEC; @@ -170,13 +97,44 @@ public MapCodec mapCodec() { } @Override - public List process(final ItemStackLike stack, final TypedKeyMap context, final List providers) { + public List process( + final ItemStackLike stack, final TypedKeyMap context, final List providers + ) { final List lore = new ArrayList<>(); providers.forEach(provider -> lore.addAll(provider.provide(stack, context))); return lore; } } + record ApplyFallbackStyle(LoreProcessor processor, Style style) implements LoreProcessor { + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + LoreProcessor.CODEC.fieldOf("processor").forGetter(ApplyFallbackStyle::processor), + AdventureCodecs.STYLE.fieldOf("style").forGetter(ApplyFallbackStyle::style) + ).apply(instance, ApplyFallbackStyle::new)); + + public ApplyFallbackStyle(final LoreProcessor processor, final Style style) { + this.processor = Objects.requireNonNull(processor, "processor"); + this.style = Objects.requireNonNull(style, "style"); + } + + @Override + public List process( + final ItemStackLike stack, final TypedKeyMap context, final List providers + ) { + return this.processor.process(stack, context, providers) + .stream() + .map(c -> c.applyFallbackStyle(this.style)) + .toList(); + } + + @Override + public MapCodec mapCodec() { + return CODEC; + } + } + record Separated(LoreProvider prefix, LoreProvider suffix, LoreProvider separator) implements LoreProcessor { public static final LoreProvider DEFAULT_PREFIX = LoreProvider.empty(); @@ -201,7 +159,9 @@ public MapCodec mapCodec() { } @Override - public List process(final ItemStackLike stack, final TypedKeyMap context, final List providers) { + public List process( + final ItemStackLike stack, final TypedKeyMap context, final List providers + ) { final List lore = new ArrayList<>(); if (!providers.isEmpty()) { final List separator = this.separator.provide(stack, context); diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java b/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java index d22c527..44e96ce 100644 --- a/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java +++ b/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.function.Function; import org.spongepowered.api.data.Key; @@ -73,8 +74,8 @@ static LoreProvider.Plain plain(final List components) { * * @return The list of keys */ - default List>> loreHidingKeys() { - return List.of(); + default Set>> loreHidingKeys() { + return Set.of(); } @Override diff --git a/src/main/java/net/hellheim/spongetools/object/ItemBuilder.java b/src/main/java/net/hellheim/spongetools/object/ItemBuilder.java index 1dc3021..e000263 100644 --- a/src/main/java/net/hellheim/spongetools/object/ItemBuilder.java +++ b/src/main/java/net/hellheim/spongetools/object/ItemBuilder.java @@ -14,6 +14,7 @@ import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import net.hellheim.spongetools.custom.type.item.LoreApplicator; import net.hellheim.spongetools.proxy.solid.EnchantmentProxy; import net.hellheim.spongetools.proxy.solid.EnchantmentTypeProxy; import net.hellheim.spongetools.proxy.solid.data.TransitiveMutableDataHolderProxy; @@ -114,7 +115,7 @@ private ItemBuilder hideFlags() { this.stack.offer(Keys.HIDE_ATTRIBUTES, true); this.stack.offer(Keys.HIDE_CAN_DESTROY, true); this.stack.offer(Keys.HIDE_CAN_PLACE, true); - //this.stack.offer(Keys.HIDE_ENCHANTMENTS, true); + this.stack.offer(Keys.HIDE_ENCHANTMENTS, true); this.stack.offer(Keys.HIDE_UNBREAKABLE, true); this.stack.offer(Keys.HIDE_MISCELLANEOUS, true); return this; @@ -152,6 +153,16 @@ public ItemBuilder displayName(ComponentLike name) { + public ItemBuilder lore(final LoreApplicator applicator, final TypedKeyMap context) { + applicator.apply(this.stack, context); + return this; + } + + public ItemBuilder lore(final LoreApplicator applicator) { + applicator.apply(this.stack); + return this; + } + public ItemBuilder loreMini(String... lore) { return this.lore(CompUtil.fromMinis(lore)); } diff --git a/src/main/java/net/hellheim/spongetools/util/EventUtil.java b/src/main/java/net/hellheim/spongetools/util/EventUtil.java index a7adc03..a106ba9 100644 --- a/src/main/java/net/hellheim/spongetools/util/EventUtil.java +++ b/src/main/java/net/hellheim/spongetools/util/EventUtil.java @@ -2,6 +2,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.function.Function; import java.util.function.Supplier; import org.apache.commons.lang3.mutable.MutableInt; @@ -16,11 +17,16 @@ import org.spongepowered.api.block.transaction.Operations; import org.spongepowered.api.command.CommandCause; import org.spongepowered.api.command.parameter.CommandContext; +import org.spongepowered.api.data.Transaction; import org.spongepowered.api.data.type.StringRepresentable; import org.spongepowered.api.event.Cause; import org.spongepowered.api.event.Event; import org.spongepowered.api.event.EventContext; import org.spongepowered.api.event.block.ChangeBlockEvent; +import org.spongepowered.api.event.item.inventory.AffectItemStackEvent; +import org.spongepowered.api.event.item.inventory.AffectSlotEvent; +import org.spongepowered.api.item.inventory.ItemStackLike; +import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.menu.ClickType; import org.spongepowered.api.world.LocatableBlock; import org.spongepowered.math.vector.Vector3i; @@ -55,28 +61,56 @@ private static StringList list(final Event e) { final StringList result = new StringList(); final String clazz = e.getClass().getSimpleName(); - if (e instanceof ChangeBlockEvent.All) { - final StringList transactions = new StringList(); - final MutableInt counter = new MutableInt(1); - ((ChangeBlockEvent.All) e).transactions().forEach(bt -> { - final StringList tr = new StringList(); - tr.add(DASH + "Operation: " + toString(bt.operation())); - tr.add(DASH + "Original: " + toString(bt.original())); - if (bt.custom().isPresent()) { - tr.add(DASH + "Default: " + toString(bt.defaultReplacement())); - tr.add(DASH + "Custom: " + toString(bt.custom().get())); - } else { - tr.add(DASH + "Final: " + toString(bt.finalReplacement())); - } - - tr.shift(SHIFT); - tr.add(0, DASH + "Transaction №" + counter.getAndIncrement() + ":"); - transactions.addAll(tr); - }); - - transactions.add(0, "BlockTransactions of " + clazz); - transactions.shift(SHIFT); - result.addAll(transactions); + if (e instanceof final ChangeBlockEvent.All eventWithTransactions) { + result.addAll(listTransactions( + "Block Transactions of " + clazz, + eventWithTransactions.transactions(), + bt -> { + final StringList tr = new StringList(); + tr.add(DASH + "Operation: " + toString(bt.operation())); + tr.add(DASH + "Original: " + toString(bt.original())); + if (bt.custom().isPresent()) { + tr.add(DASH + "Default: " + toString(bt.defaultReplacement())); + tr.add(DASH + "Custom: " + toString(bt.custom().get())); + } else { + tr.add(DASH + "Final: " + toString(bt.finalReplacement())); + } + tr.add(DASH + "Valid: " + bt.isValid()); + return tr; + })); + } else if (e instanceof final AffectSlotEvent eventWithTransactions) { + result.addAll(listTransactions( + "Slot Transactions of " + clazz, + eventWithTransactions.transactions(), + st -> { + final StringList tr = new StringList(); + tr.add(DASH + "Slot: " + toString(st.slot())); + tr.add(DASH + "Original: " + toString(st.original())); + if (st.custom().isPresent()) { + tr.add(DASH + "Default: " + toString(st.defaultReplacement())); + tr.add(DASH + "Custom: " + toString(st.custom().get())); + } else { + tr.add(DASH + "Final: " + toString(st.finalReplacement())); + } + tr.add(DASH + "Valid: " + st.isValid()); + return tr; + })); + } else if (e instanceof final AffectItemStackEvent eventWithTransactions) { + result.addAll(listTransactions( + "ItemStack Transactions of " + clazz, + eventWithTransactions.transactions(), + st -> { + final StringList tr = new StringList(); + tr.add(DASH + "Original: " + toString(st.original())); + if (st.custom().isPresent()) { + tr.add(DASH + "Default: " + toString(st.defaultReplacement())); + tr.add(DASH + "Custom: " + toString(st.custom().get())); + } else { + tr.add(DASH + "Final: " + toString(st.finalReplacement())); + } + tr.add(DASH + "Valid: " + st.isValid()); + return tr; + })); } result.addAll(list(e.context(), clazz)); @@ -144,6 +178,25 @@ private static StringList list(final EventContext context, final String name) { return result; } + private static > StringList listTransactions( + final String header, final Iterable transactions, final Function transactionMapper + ) { + final StringList transactionList = new StringList(); + final MutableInt counter = new MutableInt(1); + + transactions.forEach(transaction -> { + final StringList tr = new StringList(); + tr.addAll(transactionMapper.apply(transaction)); + tr.shift(SHIFT); + tr.add(0, DASH + "Transaction №" + counter.getAndIncrement() + ":"); + transactionList.addAll(tr); + }); + + transactionList.add(0, header); + transactionList.shift(SHIFT); + return transactionList; + } + private static String objectToString(final Object object, final Supplier defaultString) { return switch (object) { case BlockSnapshot bs -> toString(bs); @@ -162,6 +215,20 @@ private static String toString(final Enum en) { return en.getClass().getSimpleName() + " " + en.name(); } + private static String toString(final Slot slot) { + return toString(slot.peek()); + } + + private static String toString(final ItemStackLike stack) { + if (stack.isEmpty()) { + return "Empty ItemStack"; + } + return "ItemStack{" + + "type=" + stack.type().toString() + "; " + + "quantity=" + stack.quantity() + + "}"; + } + private static String toString(final BlockSnapshot bs) { return "BlockSnapshot{" + toString(bs.world(), bs.position(), bs.state()) diff --git a/src/main/java/net/hellheim/spongetools/util/ItemUtil.java b/src/main/java/net/hellheim/spongetools/util/ItemUtil.java index 1415104..cb39793 100644 --- a/src/main/java/net/hellheim/spongetools/util/ItemUtil.java +++ b/src/main/java/net/hellheim/spongetools/util/ItemUtil.java @@ -12,7 +12,6 @@ import org.spongepowered.api.item.enchantment.EnchantmentType; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.item.inventory.ItemStackComparators; import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.item.inventory.ItemStackSnapshot; import org.spongepowered.api.item.inventory.Slot; @@ -202,13 +201,6 @@ public static boolean is(final ItemType i1, final ItemType i2) { - public static boolean similar(final ItemStackLike i1, final ItemStackLike i2) { - // TODO change in API to use ItemStackLike - return ItemStackComparators.IGNORE_SIZE.get().compare(i1.asMutable(), i2.asMutable()) == 0; - } - - - public static Component displayName(Supplier type) { return displayName(type.get()); } From ccb8160c5aeeb1ca9a4b193add52d2378f4066f7 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Thu, 9 Oct 2025 14:08:52 +0300 Subject: [PATCH 22/55] update to api 14.1.0 --- src/main/java/net/hellheim/spongetools/util/ViewerUtil.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/net/hellheim/spongetools/util/ViewerUtil.java b/src/main/java/net/hellheim/spongetools/util/ViewerUtil.java index 7c9c6ce..2137435 100644 --- a/src/main/java/net/hellheim/spongetools/util/ViewerUtil.java +++ b/src/main/java/net/hellheim/spongetools/util/ViewerUtil.java @@ -9,6 +9,7 @@ import org.spongepowered.api.effect.Viewer; import org.spongepowered.api.effect.particle.ParticleEffect; import org.spongepowered.api.effect.sound.music.MusicDisc; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.world.WorldType; import org.spongepowered.math.vector.Vector3d; import org.spongepowered.math.vector.Vector3i; @@ -115,6 +116,10 @@ public void openBook(final Book.Builder book) { public void sendWorldType(final WorldType worldType) { } + @Override + public void playTotemOfUndyingEffect(final ItemStackLike stack) { + } + @Override public void spawnParticles(final ParticleEffect particleEffect, final Vector3d position) { } From a3653104b3bb8f7b87d0422fc4f4b0528feb576c Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Thu, 9 Oct 2025 22:34:50 +0300 Subject: [PATCH 23/55] Update ViewerProxy.java --- .../spongetools/proxy/solid/adventure/ViewerProxy.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ViewerProxy.java b/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ViewerProxy.java index 83ff27f..13cb817 100644 --- a/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ViewerProxy.java +++ b/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ViewerProxy.java @@ -4,6 +4,7 @@ import org.spongepowered.api.effect.Viewer; import org.spongepowered.api.effect.particle.ParticleEffect; import org.spongepowered.api.effect.sound.music.MusicDisc; +import org.spongepowered.api.item.inventory.ItemStackLike; import org.spongepowered.api.world.WorldType; import org.spongepowered.math.vector.Vector3d; import org.spongepowered.math.vector.Vector3i; @@ -20,6 +21,11 @@ default void sendWorldType(final WorldType worldType) { this.getAsAudience().sendWorldType(worldType); } + @Override + default void playTotemOfUndyingEffect(final ItemStackLike stack) { + this.getAsAudience().playTotemOfUndyingEffect(stack); + } + @Override default void spawnParticles(final ParticleEffect particleEffect, final Vector3d position) { this.getAsAudience().spawnParticles(particleEffect, position); From 31eff508d0effae1bc9bc6c3060e494f2ef1af86 Mon Sep 17 00:00:00 2001 From: MrHell228 Date: Fri, 10 Oct 2025 01:09:04 +0300 Subject: [PATCH 24/55] refactor into single project with subprojects --- .../net/hellheim/spongetools/SpongeTools.java | 0 .../spongetools/codec/CodecDispatcher.java | 0 .../spongetools/codec/CodecMapper.java | 0 .../codec/CodecMapperDispatcher.java | 0 .../spongetools/codec/LateBoundIdMapper.java | 0 .../spongetools/codec/MapCodecMapper.java | 0 .../codec/StringRepresentableCodec.java | 0 .../codec/dispatched/TableEntryCodecs.java | 0 .../dispatched/VariableAmountCodecs.java | 0 .../codec/list/AdventureCodecs.java | 0 .../codec/list/BuildableCodecs.java | 0 .../spongetools/codec/list/DataCodecs.java | 0 .../spongetools/codec/list/ExtraCodecs.java | 0 .../spongetools/codec/list/MathCodecs.java | 0 .../codec/list/RegistryCodecs.java | 0 .../spongetools/codec/list/SpongeCodecs.java | 0 .../codec/list/StringRepresentableCodecs.java | 0 .../spongetools/codec/list/TypeCodecs.java | 0 .../spongetools/collection/ComponentList.java | 0 .../spongetools/collection/StringList.java | 0 .../spongetools/collection/TupleList.java | 0 .../spongetools/collection/TupleMap.java | 0 .../collection/UnmodifiableDeque.java | 0 .../collection/UnmodifiableIterator.java | 0 .../custom/behaviour/Behaviour.java | 0 .../custom/behaviour/BehaviourArgs.java | 0 .../custom/behaviour/BehaviourCallback.java | 0 .../behaviour/BehaviourCallbackHolder.java | 0 .../BehaviourCallbackHolderLogic.java | 0 .../BehaviourCallbackHolderProxy.java | 0 .../custom/behaviour/BehaviourHolder.java | 0 .../behaviour/BehaviourHolderProxy.java | 0 .../custom/behaviour/BehaviourManager.java | 0 .../custom/behaviour/BehaviourType.java | 0 .../behaviour/TypedBehaviourCallback.java | 0 .../behaviour/tag/TaggableInstance.java | 0 .../behaviour/type/BlockStateBehaviour.java | 0 .../behaviour/type/BlockStateBehaviours.java | 0 .../behaviour/type/BlockStateExtension.java | 0 .../behaviour/type/BlockTypeExtension.java | 0 .../custom/behaviour/type/WorldExtension.java | 0 .../custom/behaviour/util/HitResult.java | 0 .../behaviour/util/InteractionResult.java | 0 .../custom/behaviour/util/SignalBias.java | 0 .../behaviour/util/SignalOrientation.java | 0 .../custom/behaviour/util/SwingType.java | 0 .../custom/behaviour/util/UseContext.java | 0 .../spongetools/custom/type/CustomType.java | 0 .../spongetools/custom/type/EitherType.java | 0 .../type/block/BasicCustomBlockType.java | 0 .../type/block/BlockStateDispatcher.java | 0 .../custom/type/block/BlockStateHolder.java | 0 .../custom/type/block/BlockStateProvider.java | 0 .../custom/type/block/CustomBlockType.java | 0 .../type/block/CustomBlockTypeBuilder.java | 0 .../type/block/CustomBlockTypeLike.java | 0 .../type/block/CustomBlockTypePresets.java | 0 .../type/block/CustomBlockTypeProperties.java | 0 .../type/block/DefaultedCustomBlockType.java | 0 .../custom/type/block/EitherBlockType.java | 0 .../custom/type/item/CustomIngredients.java | 0 .../custom/type/item/CustomItemType.java | 0 .../type/item/CustomItemTypeProperties.java | 0 .../custom/type/item/DeferredItemType.java | 0 .../custom/type/item/EitherItemType.java | 0 .../type/item/IDefaultedCustomItemType.java | 0 .../custom/type/item/LoreApplicator.java | 0 .../custom/type/item/LoreProcessor.java | 0 .../custom/type/item/LoreProvider.java | 0 .../type/item/data/CustomConsumeEffect.java | 0 .../event/RegisterBehaviourDataEvent.java | 0 .../RegisterBlockStateBehaviourEvent.java | 0 .../event/RegisterBlockStateHolderEvent.java | 0 .../function/BooleanBinaryOperator.java | 0 .../spongetools/function/IntBiConsumer.java | 0 .../spongetools/function/IntTriConsumer.java | 0 .../spongetools/function/QuadConsumer.java | 0 .../spongetools/function/QuadFunction.java | 0 .../spongetools/function/QuadPredicate.java | 0 .../spongetools/function/QuinFunction.java | 0 .../spongetools/function/QuinPredicate.java | 0 .../spongetools/function/TriConsumer.java | 0 .../spongetools/function/TriFunction.java | 0 .../spongetools/function/TriPredicate.java | 0 .../spongetools/manager/BasicMenuManager.java | 0 .../manager/FutureTaskManager.java | 0 .../spongetools/manager/IMenuManager.java | 0 .../hellheim/spongetools/manager/Manager.java | 0 .../spongetools/manager/TaskManager.java | 0 .../manager/TranslationManager.java | 0 .../math/mutable/package-info.java | 0 .../math/mutable/vector/MutableVector2d.java | 0 .../math/mutable/vector/MutableVector2f.java | 0 .../math/mutable/vector/MutableVector2i.java | 0 .../math/mutable/vector/MutableVector2l.java | 0 .../math/mutable/vector/MutableVector3d.java | 0 .../math/mutable/vector/MutableVector3f.java | 0 .../math/mutable/vector/MutableVector3i.java | 0 .../math/mutable/vector/MutableVector3l.java | 0 .../math/mutable/vector/MutableVector4d.java | 0 .../math/mutable/vector/MutableVector4f.java | 0 .../math/mutable/vector/MutableVector4i.java | 0 .../math/mutable/vector/MutableVector4l.java | 0 .../math/optional/package-info.java | 0 .../optional/vector/OptionalVector2d.java | 0 .../optional/vector/OptionalVector2i.java | 0 .../optional/vector/OptionalVector2l.java | 0 .../optional/vector/OptionalVector3d.java | 0 .../optional/vector/OptionalVector3i.java | 0 .../optional/vector/OptionalVector3l.java | 0 .../optional/vector/OptionalVector4d.java | 0 .../optional/vector/OptionalVector4i.java | 0 .../optional/vector/OptionalVector4l.java | 0 .../math/set/CardinalNeighbourShape.java | 0 .../math/set/CountableVectorSet.java | 0 .../spongetools/math/set/Ellipse.java | 0 .../spongetools/math/set/Ellipsoid.java | 0 .../spongetools/math/set/Manhattan2.java | 0 .../spongetools/math/set/Manhattan3.java | 0 .../hellheim/spongetools/math/set/Shapes.java | 0 .../hellheim/spongetools/menu/BasicMenu.java | 0 .../spongetools/menu/DefaultedMenuType.java | 0 .../spongetools/menu/IDefaultedMenuType.java | 0 .../hellheim/spongetools/menu/IMenuType.java | 0 .../net/hellheim/spongetools/menu/Menu.java | 0 .../hellheim/spongetools/menu/MenuAction.java | 0 .../spongetools/menu/MenuTypeProperties.java | 0 .../menu/handler/MenuClickHandler.java | 0 .../menu/handler/MenuCloseHandler.java | 0 .../handler/MenuInventoryCallbackHandler.java | 0 .../menu/handler/MenuKeySwapHandler.java | 0 .../menu/handler/MenuSlotChangeHandler.java | 0 .../menu/handler/MenuSlotClickHandler.java | 0 .../menu/pagination/MultiplePagination.java | 0 .../menu/pagination/PageContentProvider.java | 0 .../menu/pagination/Pagination.java | 0 .../menu/pagination/PaginationButton.java | 0 .../menu/pagination/PaginationConfig.java | 0 .../menu/pagination/PaginationInitStage.java | 0 .../menu/pagination/PaginationType.java | 0 .../menu/pagination/SinglePagination.java | 0 .../object/AttributeModifierTemplate.java | 0 .../net/hellheim/spongetools/object/Box.java | 0 .../spongetools/object/CachedSupplier.java | 0 .../object/CodecDataSerializable.java | 0 .../spongetools/object/DataOperator.java | 0 .../object/DeferredValueContainer.java | 0 .../object/InventoryDecorator.java | 0 .../object/InventoryDecoratorImpl.java | 0 .../spongetools/object/InventoryOperator.java | 0 .../object/InventoryOperatorImpl.java | 0 .../spongetools/object/ItemBuilder.java | 0 .../spongetools/object/MutableBigDec.java | 0 .../spongetools/object/MutableBigInt.java | 0 .../spongetools/object/MutableBigNumber.java | 0 .../spongetools/object/OptionalRotation.java | 0 .../spongetools/object/RequestedSupplier.java | 0 .../object/SpongeCompletableFuture.java | 0 .../spongetools/object/Streamable.java | 0 .../hellheim/spongetools/object/TypedKey.java | 0 .../spongetools/object/TypedKeyMap.java | 0 .../spongetools/object/UpdatableSupplier.java | 0 .../spongetools/object/ValueSetBuilder.java | 0 .../object/ViewableInventoryBuilder.java | 0 .../object/ViewableInventoryBuilderImpl.java | 0 .../data/OptionalDataHolderProxy.java | 0 .../OptionalImmutableDataHolderProxy.java | 0 .../data/OptionalMutableDataHolderProxy.java | 0 .../data/OptionalValueContainerProxy.java | 0 .../entity/OptionalEntityArchetypeProxy.java | 0 .../optional/entity/OptionalEntityProxy.java | 0 .../entity/OptionalEntityTypeProxy.java | 0 .../optional/entity/OptionalIEntityProxy.java | 0 .../instance/OptionalLivingEntityProxy.java | 0 .../instance/OptionalPlayerEntityProxy.java | 0 .../OptionalServerPlayerEntityProxy.java | 0 .../spongetools/proxy/solid/ColorProxy.java | 0 .../proxy/solid/EnchantmentProxy.java | 0 .../proxy/solid/EnchantmentTypeProxy.java | 0 .../spongetools/proxy/solid/PluginProxy.java | 0 .../proxy/solid/PotionEffectProxy.java | 0 .../proxy/solid/PotionEffectTypeProxy.java | 0 .../proxy/solid/SchedulerProxy.java | 0 .../proxy/solid/adventure/AudienceProxy.java | 0 .../adventure/ForwardingAudienceProxy.java | 0 .../proxy/solid/adventure/ViewerProxy.java | 0 .../proxy/solid/block/BlockStateProxy.java | 0 .../proxy/solid/block/BlockTypeProxy.java | 0 .../solid/block/StateContainerProxy.java | 0 .../proxy/solid/codec/CodecProxy.java | 0 .../proxy/solid/codec/DecoderProxy.java | 0 .../proxy/solid/codec/DynamicOpsProxy.java | 0 .../proxy/solid/codec/EncoderProxy.java | 0 .../proxy/solid/codec/MapCodecProxy.java | 0 .../proxy/solid/codec/MapDecoderProxy.java | 0 .../proxy/solid/codec/MapEncoderProxy.java | 0 .../proxy/solid/data/DataHolderProxy.java | 0 .../solid/data/DataManipulatorProxy.java | 0 .../solid/data/ImmutableDataHolderProxy.java | 0 .../data/ImmutableDataManipulatorProxy.java | 0 .../solid/data/MutableDataHolderProxy.java | 0 .../data/MutableDataManipulatorProxy.java | 0 .../TransitiveMutableDataHolderProxy.java | 0 .../proxy/solid/data/ValueContainerProxy.java | 0 .../solid/entity/EntityArchetypeProxy.java | 0 .../proxy/solid/entity/EntityProxy.java | 0 .../proxy/solid/entity/EntityTypeProxy.java | 0 .../proxy/solid/entity/IEntityProxy.java | 0 .../solid/item/DirectItemStackProxy.java | 0 .../proxy/solid/item/IItemProxy.java | 0 .../proxy/solid/item/ItemStackProxy.java | 0 .../solid/item/ItemStackSnapshotProxy.java | 0 .../proxy/solid/item/ItemTypeProxy.java | 0 .../resourcepack/ItemTransform.java | 0 .../spongetools/resourcepack/Model.java | 0 .../spongetools/resourcepack/ModelPart.java | 0 .../resourcepack/ModelPartFace.java | 0 .../resourcepack/ModelPartRotation.java | 0 .../resourcepack/ModelTemplate.java | 0 .../resourcepack/ModelTemplateProvider.java | 0 .../resourcepack/ModelTemplates.java | 0 .../spongetools/resourcepack/TextureSlot.java | 0 .../resourcepack/TextureSlots.java | 0 .../resourcepack/TexturedModel.java | 0 .../spongetools/resourcepack/Textures.java | 0 .../resourcepack/block/BlockDefinition.java | 0 .../resourcepack/block/StateCodec.java | 0 .../resourcepack/block/StateCondition.java | 0 .../resourcepack/block/StateDispatch.java | 0 .../resourcepack/block/StateOps.java | 0 .../resourcepack/block/StatePart.java | 0 .../resourcepack/block/StatePredicate.java | 0 .../block/StatePropertyValue.java | 0 .../resourcepack/block/StateSelector.java | 0 .../resourcepack/block/Variant.java | 0 .../resourcepack/block/VariantProperties.java | 0 .../resourcepack/block/VariantProperty.java | 0 .../block/VariantPropertyValue.java | 0 .../item/ConditionalProperty.java | 0 .../resourcepack/item/ItemDefinition.java | 0 .../resourcepack/item/ItemModel.java | 0 .../resourcepack/item/RangeSelectEntry.java | 0 .../item/RangeSelectProperty.java | 0 .../resourcepack/item/SelectProperty.java | 0 .../resourcepack/item/SelectSwitch.java | 0 .../resourcepack/item/SelectSwitchCase.java | 0 .../resourcepack/item/SpecialModel.java | 0 .../resourcepack/item/TintSource.java | 0 .../resourcepack/meta/AnimationFrame.java | 0 .../resourcepack/meta/GuiScaling.java | 0 .../resourcepack/meta/Metadata.java | 0 .../resourcepack/meta/MetadataLike.java | 0 .../resourcepack/meta/MetadataSection.java | 0 .../meta/MetadataSectionLike.java | 0 .../resourcepack/util/ChargeType.java | 0 .../resourcepack/util/CompassTarget.java | 0 .../resourcepack/util/GuiLight.java | 0 .../resourcepack/util/SkullType.java | 0 .../resourcepack/util/TimeSource.java | 0 .../resourcepack/util/VillagerHat.java | 0 .../resourcepack/util/WoodTypes.java | 0 .../hellheim/spongetools/util/BlockUtil.java | 0 .../spongetools/util/CollectionUtil.java | 0 .../hellheim/spongetools/util/CompUtil.java | 0 .../hellheim/spongetools/util/EffectUtil.java | 0 .../hellheim/spongetools/util/EntityUtil.java | 0 .../hellheim/spongetools/util/EventUtil.java | 0 .../hellheim/spongetools/util/GeomUtil.java | 0 .../hellheim/spongetools/util/ItemUtil.java | 0 .../hellheim/spongetools/util/ModelUtil.java | 0 .../net/hellheim/spongetools/util/RNG.java | 0 .../hellheim/spongetools/util/TaskUtil.java | 0 .../hellheim/spongetools/util/TickUtil.java | 0 .../spongetools/util/TranslationUtil.java | 0 .../hellheim/spongetools/util/ViewerUtil.java | 0 build.gradle | 120 ++- common/build.gradle | 29 + .../bridge/BlockStateBaseBridge.java | 26 + .../spongetools/bridge/MobEffectBridge.java | 11 + .../spongetools/common/SpongeToolsPlugin.java | 443 ++++++++++ .../behaviour/BehaviourManagerImpl.java | 206 +++++ .../common/behaviour/BlockStateArgs.java | 322 +++++++ .../behaviour/BlockStateDispatcherImpl.java | 53 ++ .../common/codec/AdventureCodecsFactory.java | 211 +++++ .../common/codec/ExtraCodecsFactory.java | 176 ++++ .../common/codec/SpongeToolsCodecs.java | 124 +++ .../StringRepresentableCodecsFactory.java | 30 + .../event/RegisterBehaviourDataEventImpl.java | 29 + .../RegisterBlockStateBehaviourEventImpl.java | 59 ++ .../RegisterBlockStateHolderEventImpl.java | 29 + .../listener/BehaviourEventListener.java | 424 +++++++++ .../BlockStateDispatcherEventListener.java | 31 + .../event/listener/ItemEventListener.java | 25 + .../common/util/BlockHitResultBuilder.java | 99 +++ .../spongetools/common/util/BucketUtil.java | 37 + .../spongetools/common/util/Converter.java | 337 ++++++++ .../common/util/EffectUtilFactory.java | 18 + .../common/util/HitResultFactory.java | 20 + .../common/util/InteractionResultFactory.java | 54 ++ .../spongetools/common/util/MapColorUtil.java | 91 ++ .../common/util/SignalOrientationFactory.java | 47 + .../util/StatePropertyValueFactory.java | 19 + .../common/util/SwingTypeFactory.java | 22 + .../common/web/MineConnection.java | 77 ++ .../spongetools/common/web/MineHttpd.java | 169 ++++ .../spongetools/common/web/WebUtil.java | 42 + .../mixin/world/InteractionResultMixin.java | 8 + .../world/InteractionResult_SuccessMixin.java | 34 + .../InteractionResult_SwingSourceMixin.java | 9 + .../mixin/world/effect/MobEffectMixin.java | 43 + .../mixin/world/entity/EntityMixin.java | 10 + .../mixin/world/item/BucketItemMixin.java | 86 ++ .../item/context/BlockPlaceContextMixin.java | 50 ++ .../context/DirectionalPlaceContextMixin.java | 20 + .../world/item/context/UseOnContextMixin.java | 88 ++ .../world/item/crafting/IngredientMixin.java | 20 + .../mixin/world/level/LevelMixin.java | 37 + .../mixin/world/level/block/BlockMixin.java | 15 + .../mixin/world/level/block/BlocksMixin.java | 90 ++ .../block/piston/PistonBaseBlockMixin.java | 52 ++ .../block/state/BlockBehaviourAccessor.java | 84 ++ .../BlockBehaviour_BlockStateBaseMixin.java | 815 ++++++++++++++++++ .../BlockBehaviour_PropertiesAccessor.java | 32 + .../state/properties/Property_ValueMixin.java | 40 + .../level/redstone/OrientationMixin.java | 77 ++ .../redstone/Orientation_SideBiasMixin.java | 18 + .../mixin/world/phys/BlockHitResultMixin.java | 40 + .../world/phys/EntityHitResultMixin.java | 20 + .../mixin/world/phys/HitResultMixin.java | 27 + .../AttributeModifierTemplateMixin.java | 32 + .../main/resources/mixins.spongetools.json | 35 + gradle.properties | 19 + settings.gradle | 40 +- 333 files changed, 5196 insertions(+), 25 deletions(-) rename {src => api/src}/main/java/net/hellheim/spongetools/SpongeTools.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/CodecDispatcher.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/CodecMapper.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/CodecMapperDispatcher.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/LateBoundIdMapper.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/MapCodecMapper.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/StringRepresentableCodec.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/dispatched/TableEntryCodecs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/dispatched/VariableAmountCodecs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/list/AdventureCodecs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/list/BuildableCodecs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/list/DataCodecs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/list/ExtraCodecs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/list/MathCodecs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/list/StringRepresentableCodecs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/codec/list/TypeCodecs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/collection/ComponentList.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/collection/StringList.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/collection/TupleList.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/collection/TupleMap.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/collection/UnmodifiableDeque.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/collection/UnmodifiableIterator.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderLogic.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/TypedBehaviourCallback.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockTypeExtension.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/type/WorldExtension.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/util/HitResult.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalBias.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalOrientation.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/util/SwingType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/behaviour/util/UseContext.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/CustomType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/EitherType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/block/BlockStateDispatcher.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeLike.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/block/DefaultedCustomBlockType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/block/EitherBlockType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/item/CustomIngredients.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/item/LoreApplicator.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/custom/type/item/data/CustomConsumeEffect.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/event/RegisterBlockStateHolderEvent.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/function/BooleanBinaryOperator.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/function/IntBiConsumer.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/function/IntTriConsumer.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/function/QuadConsumer.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/function/QuadFunction.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/function/QuadPredicate.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/function/QuinFunction.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/function/QuinPredicate.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/function/TriConsumer.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/function/TriFunction.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/function/TriPredicate.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/manager/BasicMenuManager.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/manager/FutureTaskManager.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/manager/IMenuManager.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/manager/Manager.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/manager/TaskManager.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/manager/TranslationManager.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/package-info.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2d.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2f.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2i.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2l.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3d.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3f.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3i.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3l.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4d.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4f.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4i.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4l.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/optional/package-info.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2d.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2i.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2l.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3d.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3i.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3l.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4d.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4i.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4l.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/set/CardinalNeighbourShape.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/set/CountableVectorSet.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/set/Ellipse.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/set/Ellipsoid.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/set/Manhattan2.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/set/Manhattan3.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/math/set/Shapes.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/BasicMenu.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/DefaultedMenuType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/IDefaultedMenuType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/IMenuType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/Menu.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/MenuAction.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/MenuTypeProperties.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/handler/MenuClickHandler.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/handler/MenuCloseHandler.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/handler/MenuInventoryCallbackHandler.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/handler/MenuKeySwapHandler.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/handler/MenuSlotChangeHandler.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/handler/MenuSlotClickHandler.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/pagination/MultiplePagination.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/pagination/PageContentProvider.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/pagination/Pagination.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/pagination/PaginationButton.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/pagination/PaginationConfig.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/pagination/PaginationInitStage.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/pagination/PaginationType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/menu/pagination/SinglePagination.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/AttributeModifierTemplate.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/Box.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/CachedSupplier.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/CodecDataSerializable.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/DataOperator.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/DeferredValueContainer.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/InventoryDecorator.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/InventoryDecoratorImpl.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/InventoryOperator.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/InventoryOperatorImpl.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/ItemBuilder.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/MutableBigDec.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/MutableBigInt.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/MutableBigNumber.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/OptionalRotation.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/RequestedSupplier.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/SpongeCompletableFuture.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/Streamable.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/TypedKey.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/TypedKeyMap.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/UpdatableSupplier.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/ViewableInventoryBuilder.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/object/ViewableInventoryBuilderImpl.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalDataHolderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalImmutableDataHolderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalMutableDataHolderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalValueContainerProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityArchetypeProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityTypeProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalIEntityProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalLivingEntityProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalPlayerEntityProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalServerPlayerEntityProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/ColorProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/EnchantmentProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/EnchantmentTypeProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/PluginProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/PotionEffectProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/PotionEffectTypeProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/SchedulerProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/adventure/AudienceProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/adventure/ForwardingAudienceProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/adventure/ViewerProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/block/BlockStateProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/block/BlockTypeProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/block/StateContainerProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/codec/CodecProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/codec/DecoderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/codec/DynamicOpsProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/codec/EncoderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/codec/MapCodecProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/codec/MapDecoderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/codec/MapEncoderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/data/DataHolderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/data/DataManipulatorProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/data/ImmutableDataHolderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/data/ImmutableDataManipulatorProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/data/MutableDataHolderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/data/MutableDataManipulatorProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/data/TransitiveMutableDataHolderProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/data/ValueContainerProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityArchetypeProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityTypeProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/entity/IEntityProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/item/DirectItemStackProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/item/IItemProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/item/ItemStackProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/item/ItemStackSnapshotProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/proxy/solid/item/ItemTypeProxy.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/ItemTransform.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/Model.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/ModelPart.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/ModelTemplate.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/ModelTemplateProvider.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/ModelTemplates.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/TexturedModel.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/Textures.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/StatePart.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/StatePredicate.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/block/VariantPropertyValue.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/item/ConditionalProperty.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/item/ItemModel.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectProperty.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitch.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/item/SpecialModel.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/item/TintSource.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/meta/AnimationFrame.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/meta/GuiScaling.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/meta/Metadata.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataLike.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSection.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSectionLike.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/util/ChargeType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/util/CompassTarget.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/util/GuiLight.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/util/SkullType.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/util/TimeSource.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/util/VillagerHat.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/resourcepack/util/WoodTypes.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/BlockUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/CollectionUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/CompUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/EffectUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/EntityUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/EventUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/GeomUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/ItemUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/ModelUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/RNG.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/TaskUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/TickUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/TranslationUtil.java (100%) rename {src => api/src}/main/java/net/hellheim/spongetools/util/ViewerUtil.java (100%) create mode 100644 common/build.gradle create mode 100644 common/src/main/java/net/hellheim/spongetools/bridge/BlockStateBaseBridge.java create mode 100644 common/src/main/java/net/hellheim/spongetools/bridge/MobEffectBridge.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/SpongeToolsPlugin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/behaviour/BehaviourManagerImpl.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/behaviour/BlockStateArgs.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/behaviour/BlockStateDispatcherImpl.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/codec/AdventureCodecsFactory.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/codec/ExtraCodecsFactory.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/codec/SpongeToolsCodecs.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/codec/StringRepresentableCodecsFactory.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/event/RegisterBehaviourDataEventImpl.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/event/RegisterBlockStateBehaviourEventImpl.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/event/RegisterBlockStateHolderEventImpl.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/event/listener/BehaviourEventListener.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/event/listener/BlockStateDispatcherEventListener.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/event/listener/ItemEventListener.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/util/BlockHitResultBuilder.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/util/BucketUtil.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/util/Converter.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/util/EffectUtilFactory.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/util/HitResultFactory.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/util/InteractionResultFactory.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/util/MapColorUtil.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/util/SignalOrientationFactory.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/util/StatePropertyValueFactory.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/util/SwingTypeFactory.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/web/MineConnection.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/web/MineHttpd.java create mode 100644 common/src/main/java/net/hellheim/spongetools/common/web/WebUtil.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/InteractionResultMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/InteractionResult_SuccessMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/InteractionResult_SwingSourceMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/effect/MobEffectMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/entity/EntityMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/item/BucketItemMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/item/context/BlockPlaceContextMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/item/context/DirectionalPlaceContextMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/item/context/UseOnContextMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/item/crafting/IngredientMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/level/LevelMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/level/block/BlockMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/level/block/BlocksMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/level/block/piston/PistonBaseBlockMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/level/block/state/BlockBehaviourAccessor.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/level/block/state/BlockBehaviour_BlockStateBaseMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/level/block/state/BlockBehaviour_PropertiesAccessor.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/level/block/state/properties/Property_ValueMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/level/redstone/OrientationMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/level/redstone/Orientation_SideBiasMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/phys/BlockHitResultMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/phys/EntityHitResultMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/phys/HitResultMixin.java create mode 100644 common/src/main/java/net/hellheim/spongetools/mixin/world/spongetools/AttributeModifierTemplateMixin.java create mode 100644 common/src/main/resources/mixins.spongetools.json create mode 100644 gradle.properties diff --git a/src/main/java/net/hellheim/spongetools/SpongeTools.java b/api/src/main/java/net/hellheim/spongetools/SpongeTools.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/SpongeTools.java rename to api/src/main/java/net/hellheim/spongetools/SpongeTools.java diff --git a/src/main/java/net/hellheim/spongetools/codec/CodecDispatcher.java b/api/src/main/java/net/hellheim/spongetools/codec/CodecDispatcher.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/CodecDispatcher.java rename to api/src/main/java/net/hellheim/spongetools/codec/CodecDispatcher.java diff --git a/src/main/java/net/hellheim/spongetools/codec/CodecMapper.java b/api/src/main/java/net/hellheim/spongetools/codec/CodecMapper.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/CodecMapper.java rename to api/src/main/java/net/hellheim/spongetools/codec/CodecMapper.java diff --git a/src/main/java/net/hellheim/spongetools/codec/CodecMapperDispatcher.java b/api/src/main/java/net/hellheim/spongetools/codec/CodecMapperDispatcher.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/CodecMapperDispatcher.java rename to api/src/main/java/net/hellheim/spongetools/codec/CodecMapperDispatcher.java diff --git a/src/main/java/net/hellheim/spongetools/codec/LateBoundIdMapper.java b/api/src/main/java/net/hellheim/spongetools/codec/LateBoundIdMapper.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/LateBoundIdMapper.java rename to api/src/main/java/net/hellheim/spongetools/codec/LateBoundIdMapper.java diff --git a/src/main/java/net/hellheim/spongetools/codec/MapCodecMapper.java b/api/src/main/java/net/hellheim/spongetools/codec/MapCodecMapper.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/MapCodecMapper.java rename to api/src/main/java/net/hellheim/spongetools/codec/MapCodecMapper.java diff --git a/src/main/java/net/hellheim/spongetools/codec/StringRepresentableCodec.java b/api/src/main/java/net/hellheim/spongetools/codec/StringRepresentableCodec.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/StringRepresentableCodec.java rename to api/src/main/java/net/hellheim/spongetools/codec/StringRepresentableCodec.java diff --git a/src/main/java/net/hellheim/spongetools/codec/dispatched/TableEntryCodecs.java b/api/src/main/java/net/hellheim/spongetools/codec/dispatched/TableEntryCodecs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/dispatched/TableEntryCodecs.java rename to api/src/main/java/net/hellheim/spongetools/codec/dispatched/TableEntryCodecs.java diff --git a/src/main/java/net/hellheim/spongetools/codec/dispatched/VariableAmountCodecs.java b/api/src/main/java/net/hellheim/spongetools/codec/dispatched/VariableAmountCodecs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/dispatched/VariableAmountCodecs.java rename to api/src/main/java/net/hellheim/spongetools/codec/dispatched/VariableAmountCodecs.java diff --git a/src/main/java/net/hellheim/spongetools/codec/list/AdventureCodecs.java b/api/src/main/java/net/hellheim/spongetools/codec/list/AdventureCodecs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/list/AdventureCodecs.java rename to api/src/main/java/net/hellheim/spongetools/codec/list/AdventureCodecs.java diff --git a/src/main/java/net/hellheim/spongetools/codec/list/BuildableCodecs.java b/api/src/main/java/net/hellheim/spongetools/codec/list/BuildableCodecs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/list/BuildableCodecs.java rename to api/src/main/java/net/hellheim/spongetools/codec/list/BuildableCodecs.java diff --git a/src/main/java/net/hellheim/spongetools/codec/list/DataCodecs.java b/api/src/main/java/net/hellheim/spongetools/codec/list/DataCodecs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/list/DataCodecs.java rename to api/src/main/java/net/hellheim/spongetools/codec/list/DataCodecs.java diff --git a/src/main/java/net/hellheim/spongetools/codec/list/ExtraCodecs.java b/api/src/main/java/net/hellheim/spongetools/codec/list/ExtraCodecs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/list/ExtraCodecs.java rename to api/src/main/java/net/hellheim/spongetools/codec/list/ExtraCodecs.java diff --git a/src/main/java/net/hellheim/spongetools/codec/list/MathCodecs.java b/api/src/main/java/net/hellheim/spongetools/codec/list/MathCodecs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/list/MathCodecs.java rename to api/src/main/java/net/hellheim/spongetools/codec/list/MathCodecs.java diff --git a/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java b/api/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java rename to api/src/main/java/net/hellheim/spongetools/codec/list/RegistryCodecs.java diff --git a/src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java b/api/src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java rename to api/src/main/java/net/hellheim/spongetools/codec/list/SpongeCodecs.java diff --git a/src/main/java/net/hellheim/spongetools/codec/list/StringRepresentableCodecs.java b/api/src/main/java/net/hellheim/spongetools/codec/list/StringRepresentableCodecs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/list/StringRepresentableCodecs.java rename to api/src/main/java/net/hellheim/spongetools/codec/list/StringRepresentableCodecs.java diff --git a/src/main/java/net/hellheim/spongetools/codec/list/TypeCodecs.java b/api/src/main/java/net/hellheim/spongetools/codec/list/TypeCodecs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/codec/list/TypeCodecs.java rename to api/src/main/java/net/hellheim/spongetools/codec/list/TypeCodecs.java diff --git a/src/main/java/net/hellheim/spongetools/collection/ComponentList.java b/api/src/main/java/net/hellheim/spongetools/collection/ComponentList.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/collection/ComponentList.java rename to api/src/main/java/net/hellheim/spongetools/collection/ComponentList.java diff --git a/src/main/java/net/hellheim/spongetools/collection/StringList.java b/api/src/main/java/net/hellheim/spongetools/collection/StringList.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/collection/StringList.java rename to api/src/main/java/net/hellheim/spongetools/collection/StringList.java diff --git a/src/main/java/net/hellheim/spongetools/collection/TupleList.java b/api/src/main/java/net/hellheim/spongetools/collection/TupleList.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/collection/TupleList.java rename to api/src/main/java/net/hellheim/spongetools/collection/TupleList.java diff --git a/src/main/java/net/hellheim/spongetools/collection/TupleMap.java b/api/src/main/java/net/hellheim/spongetools/collection/TupleMap.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/collection/TupleMap.java rename to api/src/main/java/net/hellheim/spongetools/collection/TupleMap.java diff --git a/src/main/java/net/hellheim/spongetools/collection/UnmodifiableDeque.java b/api/src/main/java/net/hellheim/spongetools/collection/UnmodifiableDeque.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/collection/UnmodifiableDeque.java rename to api/src/main/java/net/hellheim/spongetools/collection/UnmodifiableDeque.java diff --git a/src/main/java/net/hellheim/spongetools/collection/UnmodifiableIterator.java b/api/src/main/java/net/hellheim/spongetools/collection/UnmodifiableIterator.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/collection/UnmodifiableIterator.java rename to api/src/main/java/net/hellheim/spongetools/collection/UnmodifiableIterator.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/Behaviour.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourArgs.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallback.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolder.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderLogic.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderLogic.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderLogic.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderLogic.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderProxy.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderProxy.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourCallbackHolderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolder.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourHolderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourManager.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/BehaviourType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/TypedBehaviourCallback.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/TypedBehaviourCallback.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/TypedBehaviourCallback.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/TypedBehaviourCallback.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/tag/TaggableInstance.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviour.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateBehaviours.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockStateExtension.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockTypeExtension.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockTypeExtension.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockTypeExtension.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/type/BlockTypeExtension.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/type/WorldExtension.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/type/WorldExtension.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/type/WorldExtension.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/type/WorldExtension.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/HitResult.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/HitResult.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/util/HitResult.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/HitResult.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/InteractionResult.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalBias.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalBias.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalBias.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalBias.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalOrientation.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalOrientation.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalOrientation.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SignalOrientation.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SwingType.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SwingType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/util/SwingType.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/SwingType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/behaviour/util/UseContext.java b/api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/UseContext.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/behaviour/util/UseContext.java rename to api/src/main/java/net/hellheim/spongetools/custom/behaviour/util/UseContext.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/CustomType.java b/api/src/main/java/net/hellheim/spongetools/custom/type/CustomType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/CustomType.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/CustomType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/EitherType.java b/api/src/main/java/net/hellheim/spongetools/custom/type/EitherType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/EitherType.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/EitherType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java b/api/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/block/BasicCustomBlockType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateDispatcher.java b/api/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateDispatcher.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateDispatcher.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateDispatcher.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java b/api/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateHolder.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java b/api/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/block/BlockStateProvider.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java b/api/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java b/api/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeBuilder.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeLike.java b/api/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeLike.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeLike.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeLike.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java b/api/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypePresets.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java b/api/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/block/CustomBlockTypeProperties.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/DefaultedCustomBlockType.java b/api/src/main/java/net/hellheim/spongetools/custom/type/block/DefaultedCustomBlockType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/block/DefaultedCustomBlockType.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/block/DefaultedCustomBlockType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/block/EitherBlockType.java b/api/src/main/java/net/hellheim/spongetools/custom/type/block/EitherBlockType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/block/EitherBlockType.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/block/EitherBlockType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomIngredients.java b/api/src/main/java/net/hellheim/spongetools/custom/type/item/CustomIngredients.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/item/CustomIngredients.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/item/CustomIngredients.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java b/api/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java b/api/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/item/CustomItemTypeProperties.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java b/api/src/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/item/DeferredItemType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java b/api/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/item/EitherItemType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java b/api/src/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/item/IDefaultedCustomItemType.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/LoreApplicator.java b/api/src/main/java/net/hellheim/spongetools/custom/type/item/LoreApplicator.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/item/LoreApplicator.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/item/LoreApplicator.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java b/api/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProcessor.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java b/api/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/item/LoreProvider.java diff --git a/src/main/java/net/hellheim/spongetools/custom/type/item/data/CustomConsumeEffect.java b/api/src/main/java/net/hellheim/spongetools/custom/type/item/data/CustomConsumeEffect.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/custom/type/item/data/CustomConsumeEffect.java rename to api/src/main/java/net/hellheim/spongetools/custom/type/item/data/CustomConsumeEffect.java diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java b/api/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java rename to api/src/main/java/net/hellheim/spongetools/event/RegisterBehaviourDataEvent.java diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java b/api/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java rename to api/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateBehaviourEvent.java diff --git a/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateHolderEvent.java b/api/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateHolderEvent.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/event/RegisterBlockStateHolderEvent.java rename to api/src/main/java/net/hellheim/spongetools/event/RegisterBlockStateHolderEvent.java diff --git a/src/main/java/net/hellheim/spongetools/function/BooleanBinaryOperator.java b/api/src/main/java/net/hellheim/spongetools/function/BooleanBinaryOperator.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/function/BooleanBinaryOperator.java rename to api/src/main/java/net/hellheim/spongetools/function/BooleanBinaryOperator.java diff --git a/src/main/java/net/hellheim/spongetools/function/IntBiConsumer.java b/api/src/main/java/net/hellheim/spongetools/function/IntBiConsumer.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/function/IntBiConsumer.java rename to api/src/main/java/net/hellheim/spongetools/function/IntBiConsumer.java diff --git a/src/main/java/net/hellheim/spongetools/function/IntTriConsumer.java b/api/src/main/java/net/hellheim/spongetools/function/IntTriConsumer.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/function/IntTriConsumer.java rename to api/src/main/java/net/hellheim/spongetools/function/IntTriConsumer.java diff --git a/src/main/java/net/hellheim/spongetools/function/QuadConsumer.java b/api/src/main/java/net/hellheim/spongetools/function/QuadConsumer.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/function/QuadConsumer.java rename to api/src/main/java/net/hellheim/spongetools/function/QuadConsumer.java diff --git a/src/main/java/net/hellheim/spongetools/function/QuadFunction.java b/api/src/main/java/net/hellheim/spongetools/function/QuadFunction.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/function/QuadFunction.java rename to api/src/main/java/net/hellheim/spongetools/function/QuadFunction.java diff --git a/src/main/java/net/hellheim/spongetools/function/QuadPredicate.java b/api/src/main/java/net/hellheim/spongetools/function/QuadPredicate.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/function/QuadPredicate.java rename to api/src/main/java/net/hellheim/spongetools/function/QuadPredicate.java diff --git a/src/main/java/net/hellheim/spongetools/function/QuinFunction.java b/api/src/main/java/net/hellheim/spongetools/function/QuinFunction.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/function/QuinFunction.java rename to api/src/main/java/net/hellheim/spongetools/function/QuinFunction.java diff --git a/src/main/java/net/hellheim/spongetools/function/QuinPredicate.java b/api/src/main/java/net/hellheim/spongetools/function/QuinPredicate.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/function/QuinPredicate.java rename to api/src/main/java/net/hellheim/spongetools/function/QuinPredicate.java diff --git a/src/main/java/net/hellheim/spongetools/function/TriConsumer.java b/api/src/main/java/net/hellheim/spongetools/function/TriConsumer.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/function/TriConsumer.java rename to api/src/main/java/net/hellheim/spongetools/function/TriConsumer.java diff --git a/src/main/java/net/hellheim/spongetools/function/TriFunction.java b/api/src/main/java/net/hellheim/spongetools/function/TriFunction.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/function/TriFunction.java rename to api/src/main/java/net/hellheim/spongetools/function/TriFunction.java diff --git a/src/main/java/net/hellheim/spongetools/function/TriPredicate.java b/api/src/main/java/net/hellheim/spongetools/function/TriPredicate.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/function/TriPredicate.java rename to api/src/main/java/net/hellheim/spongetools/function/TriPredicate.java diff --git a/src/main/java/net/hellheim/spongetools/manager/BasicMenuManager.java b/api/src/main/java/net/hellheim/spongetools/manager/BasicMenuManager.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/manager/BasicMenuManager.java rename to api/src/main/java/net/hellheim/spongetools/manager/BasicMenuManager.java diff --git a/src/main/java/net/hellheim/spongetools/manager/FutureTaskManager.java b/api/src/main/java/net/hellheim/spongetools/manager/FutureTaskManager.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/manager/FutureTaskManager.java rename to api/src/main/java/net/hellheim/spongetools/manager/FutureTaskManager.java diff --git a/src/main/java/net/hellheim/spongetools/manager/IMenuManager.java b/api/src/main/java/net/hellheim/spongetools/manager/IMenuManager.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/manager/IMenuManager.java rename to api/src/main/java/net/hellheim/spongetools/manager/IMenuManager.java diff --git a/src/main/java/net/hellheim/spongetools/manager/Manager.java b/api/src/main/java/net/hellheim/spongetools/manager/Manager.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/manager/Manager.java rename to api/src/main/java/net/hellheim/spongetools/manager/Manager.java diff --git a/src/main/java/net/hellheim/spongetools/manager/TaskManager.java b/api/src/main/java/net/hellheim/spongetools/manager/TaskManager.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/manager/TaskManager.java rename to api/src/main/java/net/hellheim/spongetools/manager/TaskManager.java diff --git a/src/main/java/net/hellheim/spongetools/manager/TranslationManager.java b/api/src/main/java/net/hellheim/spongetools/manager/TranslationManager.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/manager/TranslationManager.java rename to api/src/main/java/net/hellheim/spongetools/manager/TranslationManager.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/package-info.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/package-info.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/package-info.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/package-info.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2d.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2d.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2d.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2d.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2f.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2f.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2f.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2f.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2i.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2i.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2i.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2i.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2l.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2l.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2l.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector2l.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3d.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3d.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3d.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3d.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3f.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3f.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3f.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3f.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3i.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3i.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3i.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3i.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3l.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3l.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3l.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector3l.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4d.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4d.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4d.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4d.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4f.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4f.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4f.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4f.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4i.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4i.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4i.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4i.java diff --git a/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4l.java b/api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4l.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4l.java rename to api/src/main/java/net/hellheim/spongetools/math/mutable/vector/MutableVector4l.java diff --git a/src/main/java/net/hellheim/spongetools/math/optional/package-info.java b/api/src/main/java/net/hellheim/spongetools/math/optional/package-info.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/optional/package-info.java rename to api/src/main/java/net/hellheim/spongetools/math/optional/package-info.java diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2d.java b/api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2d.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2d.java rename to api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2d.java diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2i.java b/api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2i.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2i.java rename to api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2i.java diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2l.java b/api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2l.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2l.java rename to api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector2l.java diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3d.java b/api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3d.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3d.java rename to api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3d.java diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3i.java b/api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3i.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3i.java rename to api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3i.java diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3l.java b/api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3l.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3l.java rename to api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector3l.java diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4d.java b/api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4d.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4d.java rename to api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4d.java diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4i.java b/api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4i.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4i.java rename to api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4i.java diff --git a/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4l.java b/api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4l.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4l.java rename to api/src/main/java/net/hellheim/spongetools/math/optional/vector/OptionalVector4l.java diff --git a/src/main/java/net/hellheim/spongetools/math/set/CardinalNeighbourShape.java b/api/src/main/java/net/hellheim/spongetools/math/set/CardinalNeighbourShape.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/set/CardinalNeighbourShape.java rename to api/src/main/java/net/hellheim/spongetools/math/set/CardinalNeighbourShape.java diff --git a/src/main/java/net/hellheim/spongetools/math/set/CountableVectorSet.java b/api/src/main/java/net/hellheim/spongetools/math/set/CountableVectorSet.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/set/CountableVectorSet.java rename to api/src/main/java/net/hellheim/spongetools/math/set/CountableVectorSet.java diff --git a/src/main/java/net/hellheim/spongetools/math/set/Ellipse.java b/api/src/main/java/net/hellheim/spongetools/math/set/Ellipse.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/set/Ellipse.java rename to api/src/main/java/net/hellheim/spongetools/math/set/Ellipse.java diff --git a/src/main/java/net/hellheim/spongetools/math/set/Ellipsoid.java b/api/src/main/java/net/hellheim/spongetools/math/set/Ellipsoid.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/set/Ellipsoid.java rename to api/src/main/java/net/hellheim/spongetools/math/set/Ellipsoid.java diff --git a/src/main/java/net/hellheim/spongetools/math/set/Manhattan2.java b/api/src/main/java/net/hellheim/spongetools/math/set/Manhattan2.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/set/Manhattan2.java rename to api/src/main/java/net/hellheim/spongetools/math/set/Manhattan2.java diff --git a/src/main/java/net/hellheim/spongetools/math/set/Manhattan3.java b/api/src/main/java/net/hellheim/spongetools/math/set/Manhattan3.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/set/Manhattan3.java rename to api/src/main/java/net/hellheim/spongetools/math/set/Manhattan3.java diff --git a/src/main/java/net/hellheim/spongetools/math/set/Shapes.java b/api/src/main/java/net/hellheim/spongetools/math/set/Shapes.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/math/set/Shapes.java rename to api/src/main/java/net/hellheim/spongetools/math/set/Shapes.java diff --git a/src/main/java/net/hellheim/spongetools/menu/BasicMenu.java b/api/src/main/java/net/hellheim/spongetools/menu/BasicMenu.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/BasicMenu.java rename to api/src/main/java/net/hellheim/spongetools/menu/BasicMenu.java diff --git a/src/main/java/net/hellheim/spongetools/menu/DefaultedMenuType.java b/api/src/main/java/net/hellheim/spongetools/menu/DefaultedMenuType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/DefaultedMenuType.java rename to api/src/main/java/net/hellheim/spongetools/menu/DefaultedMenuType.java diff --git a/src/main/java/net/hellheim/spongetools/menu/IDefaultedMenuType.java b/api/src/main/java/net/hellheim/spongetools/menu/IDefaultedMenuType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/IDefaultedMenuType.java rename to api/src/main/java/net/hellheim/spongetools/menu/IDefaultedMenuType.java diff --git a/src/main/java/net/hellheim/spongetools/menu/IMenuType.java b/api/src/main/java/net/hellheim/spongetools/menu/IMenuType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/IMenuType.java rename to api/src/main/java/net/hellheim/spongetools/menu/IMenuType.java diff --git a/src/main/java/net/hellheim/spongetools/menu/Menu.java b/api/src/main/java/net/hellheim/spongetools/menu/Menu.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/Menu.java rename to api/src/main/java/net/hellheim/spongetools/menu/Menu.java diff --git a/src/main/java/net/hellheim/spongetools/menu/MenuAction.java b/api/src/main/java/net/hellheim/spongetools/menu/MenuAction.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/MenuAction.java rename to api/src/main/java/net/hellheim/spongetools/menu/MenuAction.java diff --git a/src/main/java/net/hellheim/spongetools/menu/MenuTypeProperties.java b/api/src/main/java/net/hellheim/spongetools/menu/MenuTypeProperties.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/MenuTypeProperties.java rename to api/src/main/java/net/hellheim/spongetools/menu/MenuTypeProperties.java diff --git a/src/main/java/net/hellheim/spongetools/menu/handler/MenuClickHandler.java b/api/src/main/java/net/hellheim/spongetools/menu/handler/MenuClickHandler.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/handler/MenuClickHandler.java rename to api/src/main/java/net/hellheim/spongetools/menu/handler/MenuClickHandler.java diff --git a/src/main/java/net/hellheim/spongetools/menu/handler/MenuCloseHandler.java b/api/src/main/java/net/hellheim/spongetools/menu/handler/MenuCloseHandler.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/handler/MenuCloseHandler.java rename to api/src/main/java/net/hellheim/spongetools/menu/handler/MenuCloseHandler.java diff --git a/src/main/java/net/hellheim/spongetools/menu/handler/MenuInventoryCallbackHandler.java b/api/src/main/java/net/hellheim/spongetools/menu/handler/MenuInventoryCallbackHandler.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/handler/MenuInventoryCallbackHandler.java rename to api/src/main/java/net/hellheim/spongetools/menu/handler/MenuInventoryCallbackHandler.java diff --git a/src/main/java/net/hellheim/spongetools/menu/handler/MenuKeySwapHandler.java b/api/src/main/java/net/hellheim/spongetools/menu/handler/MenuKeySwapHandler.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/handler/MenuKeySwapHandler.java rename to api/src/main/java/net/hellheim/spongetools/menu/handler/MenuKeySwapHandler.java diff --git a/src/main/java/net/hellheim/spongetools/menu/handler/MenuSlotChangeHandler.java b/api/src/main/java/net/hellheim/spongetools/menu/handler/MenuSlotChangeHandler.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/handler/MenuSlotChangeHandler.java rename to api/src/main/java/net/hellheim/spongetools/menu/handler/MenuSlotChangeHandler.java diff --git a/src/main/java/net/hellheim/spongetools/menu/handler/MenuSlotClickHandler.java b/api/src/main/java/net/hellheim/spongetools/menu/handler/MenuSlotClickHandler.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/handler/MenuSlotClickHandler.java rename to api/src/main/java/net/hellheim/spongetools/menu/handler/MenuSlotClickHandler.java diff --git a/src/main/java/net/hellheim/spongetools/menu/pagination/MultiplePagination.java b/api/src/main/java/net/hellheim/spongetools/menu/pagination/MultiplePagination.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/pagination/MultiplePagination.java rename to api/src/main/java/net/hellheim/spongetools/menu/pagination/MultiplePagination.java diff --git a/src/main/java/net/hellheim/spongetools/menu/pagination/PageContentProvider.java b/api/src/main/java/net/hellheim/spongetools/menu/pagination/PageContentProvider.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/pagination/PageContentProvider.java rename to api/src/main/java/net/hellheim/spongetools/menu/pagination/PageContentProvider.java diff --git a/src/main/java/net/hellheim/spongetools/menu/pagination/Pagination.java b/api/src/main/java/net/hellheim/spongetools/menu/pagination/Pagination.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/pagination/Pagination.java rename to api/src/main/java/net/hellheim/spongetools/menu/pagination/Pagination.java diff --git a/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationButton.java b/api/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationButton.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/pagination/PaginationButton.java rename to api/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationButton.java diff --git a/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationConfig.java b/api/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationConfig.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/pagination/PaginationConfig.java rename to api/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationConfig.java diff --git a/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationInitStage.java b/api/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationInitStage.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/pagination/PaginationInitStage.java rename to api/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationInitStage.java diff --git a/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationType.java b/api/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/pagination/PaginationType.java rename to api/src/main/java/net/hellheim/spongetools/menu/pagination/PaginationType.java diff --git a/src/main/java/net/hellheim/spongetools/menu/pagination/SinglePagination.java b/api/src/main/java/net/hellheim/spongetools/menu/pagination/SinglePagination.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/menu/pagination/SinglePagination.java rename to api/src/main/java/net/hellheim/spongetools/menu/pagination/SinglePagination.java diff --git a/src/main/java/net/hellheim/spongetools/object/AttributeModifierTemplate.java b/api/src/main/java/net/hellheim/spongetools/object/AttributeModifierTemplate.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/AttributeModifierTemplate.java rename to api/src/main/java/net/hellheim/spongetools/object/AttributeModifierTemplate.java diff --git a/src/main/java/net/hellheim/spongetools/object/Box.java b/api/src/main/java/net/hellheim/spongetools/object/Box.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/Box.java rename to api/src/main/java/net/hellheim/spongetools/object/Box.java diff --git a/src/main/java/net/hellheim/spongetools/object/CachedSupplier.java b/api/src/main/java/net/hellheim/spongetools/object/CachedSupplier.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/CachedSupplier.java rename to api/src/main/java/net/hellheim/spongetools/object/CachedSupplier.java diff --git a/src/main/java/net/hellheim/spongetools/object/CodecDataSerializable.java b/api/src/main/java/net/hellheim/spongetools/object/CodecDataSerializable.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/CodecDataSerializable.java rename to api/src/main/java/net/hellheim/spongetools/object/CodecDataSerializable.java diff --git a/src/main/java/net/hellheim/spongetools/object/DataOperator.java b/api/src/main/java/net/hellheim/spongetools/object/DataOperator.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/DataOperator.java rename to api/src/main/java/net/hellheim/spongetools/object/DataOperator.java diff --git a/src/main/java/net/hellheim/spongetools/object/DeferredValueContainer.java b/api/src/main/java/net/hellheim/spongetools/object/DeferredValueContainer.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/DeferredValueContainer.java rename to api/src/main/java/net/hellheim/spongetools/object/DeferredValueContainer.java diff --git a/src/main/java/net/hellheim/spongetools/object/InventoryDecorator.java b/api/src/main/java/net/hellheim/spongetools/object/InventoryDecorator.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/InventoryDecorator.java rename to api/src/main/java/net/hellheim/spongetools/object/InventoryDecorator.java diff --git a/src/main/java/net/hellheim/spongetools/object/InventoryDecoratorImpl.java b/api/src/main/java/net/hellheim/spongetools/object/InventoryDecoratorImpl.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/InventoryDecoratorImpl.java rename to api/src/main/java/net/hellheim/spongetools/object/InventoryDecoratorImpl.java diff --git a/src/main/java/net/hellheim/spongetools/object/InventoryOperator.java b/api/src/main/java/net/hellheim/spongetools/object/InventoryOperator.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/InventoryOperator.java rename to api/src/main/java/net/hellheim/spongetools/object/InventoryOperator.java diff --git a/src/main/java/net/hellheim/spongetools/object/InventoryOperatorImpl.java b/api/src/main/java/net/hellheim/spongetools/object/InventoryOperatorImpl.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/InventoryOperatorImpl.java rename to api/src/main/java/net/hellheim/spongetools/object/InventoryOperatorImpl.java diff --git a/src/main/java/net/hellheim/spongetools/object/ItemBuilder.java b/api/src/main/java/net/hellheim/spongetools/object/ItemBuilder.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/ItemBuilder.java rename to api/src/main/java/net/hellheim/spongetools/object/ItemBuilder.java diff --git a/src/main/java/net/hellheim/spongetools/object/MutableBigDec.java b/api/src/main/java/net/hellheim/spongetools/object/MutableBigDec.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/MutableBigDec.java rename to api/src/main/java/net/hellheim/spongetools/object/MutableBigDec.java diff --git a/src/main/java/net/hellheim/spongetools/object/MutableBigInt.java b/api/src/main/java/net/hellheim/spongetools/object/MutableBigInt.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/MutableBigInt.java rename to api/src/main/java/net/hellheim/spongetools/object/MutableBigInt.java diff --git a/src/main/java/net/hellheim/spongetools/object/MutableBigNumber.java b/api/src/main/java/net/hellheim/spongetools/object/MutableBigNumber.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/MutableBigNumber.java rename to api/src/main/java/net/hellheim/spongetools/object/MutableBigNumber.java diff --git a/src/main/java/net/hellheim/spongetools/object/OptionalRotation.java b/api/src/main/java/net/hellheim/spongetools/object/OptionalRotation.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/OptionalRotation.java rename to api/src/main/java/net/hellheim/spongetools/object/OptionalRotation.java diff --git a/src/main/java/net/hellheim/spongetools/object/RequestedSupplier.java b/api/src/main/java/net/hellheim/spongetools/object/RequestedSupplier.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/RequestedSupplier.java rename to api/src/main/java/net/hellheim/spongetools/object/RequestedSupplier.java diff --git a/src/main/java/net/hellheim/spongetools/object/SpongeCompletableFuture.java b/api/src/main/java/net/hellheim/spongetools/object/SpongeCompletableFuture.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/SpongeCompletableFuture.java rename to api/src/main/java/net/hellheim/spongetools/object/SpongeCompletableFuture.java diff --git a/src/main/java/net/hellheim/spongetools/object/Streamable.java b/api/src/main/java/net/hellheim/spongetools/object/Streamable.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/Streamable.java rename to api/src/main/java/net/hellheim/spongetools/object/Streamable.java diff --git a/src/main/java/net/hellheim/spongetools/object/TypedKey.java b/api/src/main/java/net/hellheim/spongetools/object/TypedKey.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/TypedKey.java rename to api/src/main/java/net/hellheim/spongetools/object/TypedKey.java diff --git a/src/main/java/net/hellheim/spongetools/object/TypedKeyMap.java b/api/src/main/java/net/hellheim/spongetools/object/TypedKeyMap.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/TypedKeyMap.java rename to api/src/main/java/net/hellheim/spongetools/object/TypedKeyMap.java diff --git a/src/main/java/net/hellheim/spongetools/object/UpdatableSupplier.java b/api/src/main/java/net/hellheim/spongetools/object/UpdatableSupplier.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/UpdatableSupplier.java rename to api/src/main/java/net/hellheim/spongetools/object/UpdatableSupplier.java diff --git a/src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java b/api/src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java rename to api/src/main/java/net/hellheim/spongetools/object/ValueSetBuilder.java diff --git a/src/main/java/net/hellheim/spongetools/object/ViewableInventoryBuilder.java b/api/src/main/java/net/hellheim/spongetools/object/ViewableInventoryBuilder.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/ViewableInventoryBuilder.java rename to api/src/main/java/net/hellheim/spongetools/object/ViewableInventoryBuilder.java diff --git a/src/main/java/net/hellheim/spongetools/object/ViewableInventoryBuilderImpl.java b/api/src/main/java/net/hellheim/spongetools/object/ViewableInventoryBuilderImpl.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/object/ViewableInventoryBuilderImpl.java rename to api/src/main/java/net/hellheim/spongetools/object/ViewableInventoryBuilderImpl.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalDataHolderProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalDataHolderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalDataHolderProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalDataHolderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalImmutableDataHolderProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalImmutableDataHolderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalImmutableDataHolderProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalImmutableDataHolderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalMutableDataHolderProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalMutableDataHolderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalMutableDataHolderProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalMutableDataHolderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalValueContainerProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalValueContainerProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalValueContainerProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/optional/data/OptionalValueContainerProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityArchetypeProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityArchetypeProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityArchetypeProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityArchetypeProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityTypeProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityTypeProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityTypeProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalEntityTypeProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalIEntityProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalIEntityProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalIEntityProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/OptionalIEntityProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalLivingEntityProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalLivingEntityProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalLivingEntityProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalLivingEntityProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalPlayerEntityProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalPlayerEntityProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalPlayerEntityProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalPlayerEntityProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalServerPlayerEntityProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalServerPlayerEntityProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalServerPlayerEntityProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/optional/entity/instance/OptionalServerPlayerEntityProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/ColorProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/ColorProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/ColorProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/ColorProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/EnchantmentProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/EnchantmentProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/EnchantmentProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/EnchantmentProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/EnchantmentTypeProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/EnchantmentTypeProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/EnchantmentTypeProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/EnchantmentTypeProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/PluginProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/PluginProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/PluginProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/PluginProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/PotionEffectProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/PotionEffectProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/PotionEffectProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/PotionEffectProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/PotionEffectTypeProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/PotionEffectTypeProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/PotionEffectTypeProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/PotionEffectTypeProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/SchedulerProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/SchedulerProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/SchedulerProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/SchedulerProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/AudienceProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/AudienceProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/adventure/AudienceProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/AudienceProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ForwardingAudienceProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ForwardingAudienceProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ForwardingAudienceProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ForwardingAudienceProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ViewerProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ViewerProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ViewerProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/adventure/ViewerProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/block/BlockStateProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/block/BlockStateProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/block/BlockStateProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/block/BlockStateProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/block/BlockTypeProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/block/BlockTypeProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/block/BlockTypeProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/block/BlockTypeProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/block/StateContainerProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/block/StateContainerProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/block/StateContainerProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/block/StateContainerProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/codec/CodecProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/CodecProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/codec/CodecProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/CodecProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/codec/DecoderProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/DecoderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/codec/DecoderProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/DecoderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/codec/DynamicOpsProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/DynamicOpsProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/codec/DynamicOpsProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/DynamicOpsProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/codec/EncoderProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/EncoderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/codec/EncoderProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/EncoderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapCodecProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapCodecProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapCodecProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapCodecProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapDecoderProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapDecoderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapDecoderProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapDecoderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapEncoderProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapEncoderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapEncoderProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/codec/MapEncoderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/data/DataHolderProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/data/DataHolderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/data/DataHolderProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/data/DataHolderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/data/DataManipulatorProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/data/DataManipulatorProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/data/DataManipulatorProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/data/DataManipulatorProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/data/ImmutableDataHolderProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/data/ImmutableDataHolderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/data/ImmutableDataHolderProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/data/ImmutableDataHolderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/data/ImmutableDataManipulatorProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/data/ImmutableDataManipulatorProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/data/ImmutableDataManipulatorProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/data/ImmutableDataManipulatorProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/data/MutableDataHolderProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/data/MutableDataHolderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/data/MutableDataHolderProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/data/MutableDataHolderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/data/MutableDataManipulatorProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/data/MutableDataManipulatorProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/data/MutableDataManipulatorProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/data/MutableDataManipulatorProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/data/TransitiveMutableDataHolderProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/data/TransitiveMutableDataHolderProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/data/TransitiveMutableDataHolderProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/data/TransitiveMutableDataHolderProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/data/ValueContainerProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/data/ValueContainerProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/data/ValueContainerProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/data/ValueContainerProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityArchetypeProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityArchetypeProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityArchetypeProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityArchetypeProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityTypeProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityTypeProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityTypeProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/entity/EntityTypeProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/entity/IEntityProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/entity/IEntityProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/entity/IEntityProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/entity/IEntityProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/item/DirectItemStackProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/item/DirectItemStackProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/item/DirectItemStackProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/item/DirectItemStackProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/item/IItemProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/item/IItemProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/item/IItemProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/item/IItemProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemStackProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemStackProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemStackProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemStackProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemStackSnapshotProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemStackSnapshotProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemStackSnapshotProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemStackSnapshotProxy.java diff --git a/src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemTypeProxy.java b/api/src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemTypeProxy.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemTypeProxy.java rename to api/src/main/java/net/hellheim/spongetools/proxy/solid/item/ItemTypeProxy.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ItemTransform.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/ItemTransform.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/ItemTransform.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/ItemTransform.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/Model.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/Model.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/Model.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/Model.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ModelPart.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/ModelPart.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/ModelPart.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/ModelPart.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartFace.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/ModelPartRotation.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplate.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplate.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplate.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplate.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplateProvider.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplateProvider.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplateProvider.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplateProvider.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplates.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplates.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplates.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/ModelTemplates.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlot.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/TextureSlots.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/TexturedModel.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/TexturedModel.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/TexturedModel.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/TexturedModel.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/Textures.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/Textures.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/Textures.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/Textures.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/BlockDefinition.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCodec.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/StateCondition.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/StateDispatch.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/StateOps.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePart.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePart.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/StatePart.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePart.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePredicate.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePredicate.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/StatePredicate.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePredicate.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/StatePropertyValue.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/StateSelector.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/Variant.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperties.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantProperty.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantPropertyValue.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantPropertyValue.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/block/VariantPropertyValue.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/block/VariantPropertyValue.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/ConditionalProperty.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/item/ConditionalProperty.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/item/ConditionalProperty.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/item/ConditionalProperty.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemDefinition.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemModel.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemModel.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/item/ItemModel.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/item/ItemModel.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectEntry.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectProperty.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectProperty.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectProperty.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/item/RangeSelectProperty.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectProperty.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitch.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitch.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitch.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitch.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/item/SelectSwitchCase.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/SpecialModel.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/item/SpecialModel.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/item/SpecialModel.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/item/SpecialModel.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/item/TintSource.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/item/TintSource.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/item/TintSource.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/item/TintSource.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/meta/AnimationFrame.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/meta/AnimationFrame.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/meta/AnimationFrame.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/meta/AnimationFrame.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/meta/GuiScaling.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/meta/GuiScaling.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/meta/GuiScaling.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/meta/GuiScaling.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/meta/Metadata.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/meta/Metadata.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/meta/Metadata.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/meta/Metadata.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataLike.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataLike.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataLike.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataLike.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSection.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSection.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSection.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSection.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSectionLike.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSectionLike.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSectionLike.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/meta/MetadataSectionLike.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/util/ChargeType.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/util/ChargeType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/util/ChargeType.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/util/ChargeType.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/util/CompassTarget.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/util/CompassTarget.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/util/CompassTarget.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/util/CompassTarget.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/util/GuiLight.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/util/GuiLight.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/util/GuiLight.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/util/GuiLight.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/util/SkullType.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/util/SkullType.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/util/SkullType.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/util/SkullType.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/util/TimeSource.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/util/TimeSource.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/util/TimeSource.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/util/TimeSource.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/util/VillagerHat.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/util/VillagerHat.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/util/VillagerHat.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/util/VillagerHat.java diff --git a/src/main/java/net/hellheim/spongetools/resourcepack/util/WoodTypes.java b/api/src/main/java/net/hellheim/spongetools/resourcepack/util/WoodTypes.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/resourcepack/util/WoodTypes.java rename to api/src/main/java/net/hellheim/spongetools/resourcepack/util/WoodTypes.java diff --git a/src/main/java/net/hellheim/spongetools/util/BlockUtil.java b/api/src/main/java/net/hellheim/spongetools/util/BlockUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/BlockUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/BlockUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/CollectionUtil.java b/api/src/main/java/net/hellheim/spongetools/util/CollectionUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/CollectionUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/CollectionUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/CompUtil.java b/api/src/main/java/net/hellheim/spongetools/util/CompUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/CompUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/CompUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/EffectUtil.java b/api/src/main/java/net/hellheim/spongetools/util/EffectUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/EffectUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/EffectUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/EntityUtil.java b/api/src/main/java/net/hellheim/spongetools/util/EntityUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/EntityUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/EntityUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/EventUtil.java b/api/src/main/java/net/hellheim/spongetools/util/EventUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/EventUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/EventUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/GeomUtil.java b/api/src/main/java/net/hellheim/spongetools/util/GeomUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/GeomUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/GeomUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/ItemUtil.java b/api/src/main/java/net/hellheim/spongetools/util/ItemUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/ItemUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/ItemUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/ModelUtil.java b/api/src/main/java/net/hellheim/spongetools/util/ModelUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/ModelUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/ModelUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/RNG.java b/api/src/main/java/net/hellheim/spongetools/util/RNG.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/RNG.java rename to api/src/main/java/net/hellheim/spongetools/util/RNG.java diff --git a/src/main/java/net/hellheim/spongetools/util/TaskUtil.java b/api/src/main/java/net/hellheim/spongetools/util/TaskUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/TaskUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/TaskUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/TickUtil.java b/api/src/main/java/net/hellheim/spongetools/util/TickUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/TickUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/TickUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/TranslationUtil.java b/api/src/main/java/net/hellheim/spongetools/util/TranslationUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/TranslationUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/TranslationUtil.java diff --git a/src/main/java/net/hellheim/spongetools/util/ViewerUtil.java b/api/src/main/java/net/hellheim/spongetools/util/ViewerUtil.java similarity index 100% rename from src/main/java/net/hellheim/spongetools/util/ViewerUtil.java rename to api/src/main/java/net/hellheim/spongetools/util/ViewerUtil.java diff --git a/build.gradle b/build.gradle index a3cd7b7..35c5dd1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,37 +1,109 @@ -plugins { - id 'java-library' +subprojects { + apply plugin: 'java-library' + + repositories { + jcenter() + maven { + name = 'sponge' + url = 'https://repo.spongepowered.org/repository/maven-public/' + } + maven { + name = "sonatype-oss-snapshots1" + url = "https://s01.oss.sonatype.org/content/repositories/snapshots/" + } + mavenLocal() + } + + version = project.plugin_version + group = project.plugin_group + java.toolchain.languageVersion = JavaLanguageVersion.of(project.java_version) + + compileJava.options.encoding = 'UTF-8' + targetCompatibility = 21 + sourceCompatibility = 21 } -compileJava.options.encoding = 'UTF-8' -targetCompatibility = 21 -sourceCompatibility = 21 +[sub_api, sub_common, sub_vanilla, sub_forge, sub_neoforge].each { + project(":$it").jar.destinationDirectory = file("$rootDir/artifacts") +} -group = 'net.hellheim' -version = '0.3-SNAPSHOT' -description = 'SpongeToolsAPI' +project(":$sub_api") { + dependencies { + // SpongeAPI + api "org.spongepowered:spongeapi:${spongeapi_version}" + + // DataFixerUpper + api 'com.mojang:datafixerupper:8.0.16' + } + + base.archivesName = project.plugin_name + "-api" +} + +project(":$sub_common") { + //apply plugin: 'com.gradleup.shadow' + //apply plugin: 'org.spongepowered.gradle.plugin' + //apply plugin: 'org.spongepowered.gradle.vanilla' + + dependencies { + // SpongeToolsAPI + implementation project(":$sub_api") + + // SpongeCommon + api "org.spongepowered:sponge:${sponge_version}" + + // Mixins + api 'org.spongepowered:mixin:0.8.7' + api 'io.github.llamalad7:mixinextras-neoforge:0.4.1' + } + + jar { + from project(":$sub_api").sourceSets.main.output + + manifest { + attributes( + "MixinConfigs": "mixins.spongetools.json" + ) + } + } + + base.archivesName = project.plugin_name + "-common" +} -repositories { - jcenter() - maven { - name = 'sponge' - url = 'https://repo.spongepowered.org/repository/maven-public/' +project(":$sub_vanilla") { + dependencies { + api project(":$sub_common") } - maven { - name = "sonatype-oss-snapshots1" - url = "https://s01.oss.sonatype.org/content/repositories/snapshots/" + + jar { + from project(":$sub_api").sourceSets.main.output + from project(":$sub_common").sourceSets.main.output } - mavenLocal() + base.archivesName = project.plugin_name + "-vanilla" } -dependencies { - // SpongeAPI - api 'org.spongepowered:spongeapi:14.1.0-SNAPSHOT' +project(":$sub_forge") { + dependencies { + api project(":$sub_common") + } - // DataFixerUpper - api 'com.mojang:datafixerupper:8.0.16' + jar { + from project(":$sub_api").sourceSets.main.output + from project(":$sub_common").sourceSets.main.output + } + + base.archivesName = project.plugin_name + "-forge" } -jar { - archiveBaseName = "SpongeToolsAPI" +project(":$sub_neoforge") { + dependencies { + api project(":$sub_common") + } + + jar { + from project(":$sub_api").sourceSets.main.output + from project(":$sub_common").sourceSets.main.output + } + + base.archivesName = project.plugin_name + "-neoforge" } diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 0000000..46e2199 --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,29 @@ +plugins { + id 'com.gradleup.shadow' version '8.3.5' + id 'org.spongepowered.gradle.plugin' version '2.3.0' + id 'org.spongepowered.gradle.vanilla' version '0.2.1-SNAPSHOT' +} + + +sponge { + apiVersion(project(":").spongeapi_version) + license("MIT") + loader { + name("java_plain") + version("1.0") + } + plugin("spongetools") { + displayName(project(":").plugin_name) + version(project(":").plugin_version) + entrypoint("net.hellheim.spongetools.impl.SpongeToolsPlugin") + description("SpongeTools plugin") + dependency("spongeapi") { + //loadOrder(PluginDependency.LoadOrder.AFTER) + optional(false) + } + } +} + +minecraft { + version(project.game_version) +} diff --git a/common/src/main/java/net/hellheim/spongetools/bridge/BlockStateBaseBridge.java b/common/src/main/java/net/hellheim/spongetools/bridge/BlockStateBaseBridge.java new file mode 100644 index 0000000..25618ee --- /dev/null +++ b/common/src/main/java/net/hellheim/spongetools/bridge/BlockStateBaseBridge.java @@ -0,0 +1,26 @@ +package net.hellheim.spongetools.bridge; + +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderLogic; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateExtension; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.LevelAccessor; +import org.checkerframework.checker.nullness.qual.Nullable; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.entity.BlockEntity; + +import java.util.Optional; + +public interface BlockStateBaseBridge { + + void spongetools$bridge$set(BehaviourCallbackHolderLogic callbacks); + + @Nullable BlockEntity spongetools$bridge$newBlockEntity(BlockGetter getter, BlockPos pos); + + ItemStack spongetools$bridge$bucketPickup$item(LevelAccessor accessor, BlockPos pos, @Nullable Player player); + + Optional spongetools$bridge$bucketPickup$sound(); +} diff --git a/common/src/main/java/net/hellheim/spongetools/bridge/MobEffectBridge.java b/common/src/main/java/net/hellheim/spongetools/bridge/MobEffectBridge.java new file mode 100644 index 0000000..5f78b6d --- /dev/null +++ b/common/src/main/java/net/hellheim/spongetools/bridge/MobEffectBridge.java @@ -0,0 +1,11 @@ +package net.hellheim.spongetools.bridge; + +import java.util.Map; + +import net.hellheim.spongetools.object.AttributeModifierTemplate; +import org.spongepowered.api.entity.attribute.type.AttributeType; + +public interface MobEffectBridge { + + Map spongetools$bridge$modifierTemplates(); +} diff --git a/common/src/main/java/net/hellheim/spongetools/common/SpongeToolsPlugin.java b/common/src/main/java/net/hellheim/spongetools/common/SpongeToolsPlugin.java new file mode 100644 index 0000000..94747be --- /dev/null +++ b/common/src/main/java/net/hellheim/spongetools/common/SpongeToolsPlugin.java @@ -0,0 +1,443 @@ +package net.hellheim.spongetools.common; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.lang.invoke.MethodHandles; +import java.net.URI; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.UnaryOperator; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.apache.logging.log4j.Logger; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.Server; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.config.ConfigDir; +import org.spongepowered.api.config.ConfigRoot; +import org.spongepowered.api.config.DefaultConfig; +import org.spongepowered.api.data.DataRegistration; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.lifecycle.FreezeRegistryEvent; +import org.spongepowered.api.event.lifecycle.RegisterBuilderEvent; +import org.spongepowered.api.event.lifecycle.RegisterDataEvent; +import org.spongepowered.api.event.lifecycle.RegisterFactoryEvent; +import org.spongepowered.api.event.lifecycle.RegisterRegistryEvent; +import org.spongepowered.api.event.lifecycle.RegisterRegistryValueEvent; +import org.spongepowered.api.event.lifecycle.StartedEngineEvent; +import org.spongepowered.api.event.network.ServerSideConnectionEvent; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.registry.RegistryEntry; +import org.spongepowered.api.registry.RegistryHolder; +import org.spongepowered.api.registry.RegistryType; +import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.configurate.CommentedConfigurationNode; +import org.spongepowered.configurate.ConfigurationOptions; +import org.spongepowered.configurate.loader.ConfigurationLoader; +import org.spongepowered.plugin.PluginContainer; +import org.spongepowered.plugin.builtin.jvm.Plugin; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.stream.JsonReader; +import com.google.inject.Inject; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.JsonOps; + +import net.hellheim.spongetools.SpongeTools; +import net.hellheim.spongetools.codec.list.AdventureCodecs; +import net.hellheim.spongetools.codec.list.ExtraCodecs; +import net.hellheim.spongetools.codec.list.StringRepresentableCodecs; +import net.hellheim.spongetools.common.behaviour.BehaviourManagerImpl; +import net.hellheim.spongetools.common.behaviour.BlockStateDispatcherImpl; +import net.hellheim.spongetools.common.codec.AdventureCodecsFactory; +import net.hellheim.spongetools.common.codec.ExtraCodecsFactory; +import net.hellheim.spongetools.common.codec.SpongeToolsCodecs; +import net.hellheim.spongetools.common.codec.StringRepresentableCodecsFactory; +import net.hellheim.spongetools.common.event.listener.BehaviourEventListener; +import net.hellheim.spongetools.common.event.listener.BlockStateDispatcherEventListener; +import net.hellheim.spongetools.common.event.listener.ItemEventListener; +import net.hellheim.spongetools.common.util.BlockHitResultBuilder; +import net.hellheim.spongetools.common.util.EffectUtilFactory; +import net.hellheim.spongetools.common.util.HitResultFactory; +import net.hellheim.spongetools.common.util.InteractionResultFactory; +import net.hellheim.spongetools.common.util.SignalOrientationFactory; +import net.hellheim.spongetools.common.util.StatePropertyValueFactory; +import net.hellheim.spongetools.common.util.SwingTypeFactory; +import net.hellheim.spongetools.common.web.MineHttpd; +import net.hellheim.spongetools.custom.behaviour.BehaviourManager; +import net.hellheim.spongetools.custom.behaviour.util.HitResult; +import net.hellheim.spongetools.custom.behaviour.util.InteractionResult; +import net.hellheim.spongetools.custom.behaviour.util.SignalBias; +import net.hellheim.spongetools.custom.behaviour.util.SignalOrientation; +import net.hellheim.spongetools.custom.behaviour.util.SwingType; +import net.hellheim.spongetools.custom.type.block.BlockStateDispatcher; +import net.hellheim.spongetools.custom.type.block.CustomBlockType; +import net.hellheim.spongetools.custom.type.block.EitherBlockType; +import net.hellheim.spongetools.custom.type.item.CustomItemType; +import net.hellheim.spongetools.custom.type.item.EitherItemType; +import net.hellheim.spongetools.custom.type.item.LoreProcessor; +import net.hellheim.spongetools.custom.type.item.LoreProvider; +import net.hellheim.spongetools.custom.type.item.data.CustomConsumeEffect; +import net.hellheim.spongetools.proxy.solid.PluginProxy; +import net.hellheim.spongetools.resourcepack.Model; +import net.hellheim.spongetools.resourcepack.block.BlockDefinition; +import net.hellheim.spongetools.resourcepack.block.StatePropertyValue; +import net.hellheim.spongetools.resourcepack.item.ItemDefinition; +import net.hellheim.spongetools.resourcepack.meta.Metadata; +import net.hellheim.spongetools.resourcepack.meta.MetadataSection; +import net.hellheim.spongetools.util.EffectUtil; +import net.kyori.adventure.resource.ResourcePackInfo; +import net.kyori.adventure.resource.ResourcePackRequest; +import net.kyori.adventure.text.Component; + +@Plugin(SpongeTools.NAMESPACE) +public final class SpongeToolsPlugin implements PluginProxy { + + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final ResourcePackInfo.Builder INFO_BUILDER = ResourcePackInfo.resourcePackInfo(); + private static final ResourcePackRequest.Builder REQUEST_BUILDER = ResourcePackRequest.resourcePackRequest() + .required(true) + .replace(false); + + private final PluginContainer plugin; + private final Logger logger; + private final Optional web; + + private Optional pack = Optional.empty(); + + // TODO should be configurable + private File packResult = new File("config/spongetools/pack.zip"); + private File assetsToCopy = new File("config/spongetools/copy_assets"); + private File assetsToLoad = new File("config/spongetools/load_assets"); + private int port = 8073; + + @Inject + public SpongeToolsPlugin(final PluginContainer plugin, final Logger logger) { + this.plugin = plugin; + this.logger = logger; + + final ConfigRoot root = Sponge.configManager().pluginConfig(plugin); + final ConfigurationLoader loader = root.config(); + final ConfigurationOptions options = loader.defaultOptions(); + + this.web = MineHttpd.tryCreate(this.logger, this.packResult, this.port); + + final var eventManager = Sponge.game().eventManager(); + final var lookup = MethodHandles.lookup(); + eventManager.registerListeners(this.plugin, new ItemEventListener(), lookup); + eventManager.registerListeners(this.plugin, new BehaviourEventListener(), lookup); + eventManager.registerListeners(this.plugin, new BlockStateDispatcherEventListener(), lookup); + this.web.ifPresent(web -> eventManager.registerListeners(this.plugin, web.eventListener(), lookup)); + } + + @Listener + public void registerFactories(final RegisterFactoryEvent event) { + event.register(StatePropertyValue.Factory.class, new StatePropertyValueFactory()); + event.register(SwingType.Factory.class, new SwingTypeFactory()); + event.register(InteractionResult.Factory.class, new InteractionResultFactory()); + event.register(HitResult.Factory.class, new HitResultFactory()); + event.register(SignalOrientation.Factory.class, new SignalOrientationFactory()); + event.register(SignalBias.Factory.class, new SignalOrientationFactory.BiasFactory()); + event.register(EffectUtil.Factory.class, new EffectUtilFactory()); + event.register(BehaviourManager.class, new BehaviourManagerImpl()); + event.register(BlockStateDispatcher.class, new BlockStateDispatcherImpl()); + event.register(ExtraCodecs.Factory.class, new ExtraCodecsFactory()); + event.register(AdventureCodecs.Factory.class, new AdventureCodecsFactory()); + event.register(StringRepresentableCodecs.Factory.class, new StringRepresentableCodecsFactory()); + } + + @Listener + public void registerBuilders(final RegisterBuilderEvent event) { + event.register(HitResult.BlockHitResult.Builder.class, BlockHitResultBuilder::new); + } + + @Listener + public void registerData(final RegisterDataEvent event) { + event.register(DataRegistration.of(CustomItemType.dataKey(), ItemStack.class)); + event.register(DataRegistration.of(LoreProcessor.dataKey(), ItemStack.class)); + event.register(DataRegistration.of(LoreProvider.dataKey(), ItemStack.class)); + event.register(DataRegistration.of(CustomConsumeEffect.dataKey(), ItemStack.class)); + + Sponge.dataManager().registerBuilder(CustomItemType.class, CustomItemType.dataBuilder()); + Sponge.dataManager().registerBuilder(LoreProcessor.class, LoreProcessor.dataBuilder()); + Sponge.dataManager().registerBuilder(LoreProvider.class, LoreProvider.dataBuilder()); + Sponge.dataManager().registerBuilder(CustomConsumeEffect.class, CustomConsumeEffect.dataBuilder()); + + SpongeToolsCodecs.bootstrap(); + } + + // Registry events + + @Listener + public void registerServerRegistries(final RegisterRegistryEvent.EngineScoped event) { + + // CustomType registries + + final var customItems = CustomItemType.registry(); + event.register(customItems.location(), true); + + final var customBlocks = CustomBlockType.registry(); + event.register(customBlocks.location(), true); + + // EitherType registries + + event.register(EitherItemType.registry().location(), false, $ -> { + final Map map = new HashMap<>(); + RegistryTypes.ITEM_TYPE.get().streamEntries().forEach(e -> map.put(e.key(), EitherItemType.common(e.value()))); + customItems.get().streamEntries().forEach(e -> map.put(e.key(), EitherItemType.custom(e.value()))); + return map; + }, customItems); + + event.register(EitherBlockType.registry().location(), false, $ -> { + final Map map = new HashMap<>(); + RegistryTypes.BLOCK_TYPE.get().streamEntries().forEach(e -> map.put(e.key(), EitherBlockType.common(e.value()))); + customBlocks.get().streamEntries().forEach(e -> map.put(e.key(), EitherBlockType.custom(e.value()))); + return map; + }, customBlocks); + + // Model registries + + event.register(Model.registry().location(), true); + + event.register(ItemDefinition.registry().location(), true, $ -> { + this.logger.info(customItems.defaultHolder().get()); + this.logger.info($); + this.logger.info($ == customItems.defaultHolder().get()); + final Map map = new HashMap<>(); + customItems.get().streamEntries().forEach(e -> { + e.value().model().ifPresent(model -> { + map.put(e.key(), model); + }); + }); + + return map; + }, customItems); + + event.register(BlockDefinition.registry().location(), true, $ -> { + // TODO Can this be in some nicer place? + BlockStateDispatcherEventListener.fireEvent(event); + + final Map map = new HashMap<>(); + customBlocks.get().stream() + .filter(block -> !block.model().isEmpty()) + .collect(Collectors.groupingBy(block -> block.state().type())) + .forEach((blockType, customBlockTypes) -> { + final ResourceKey blockKey = blockType.key(RegistryTypes.BLOCK_TYPE); + BlockDefinition model = this.decode( + BlockDefinition.CODEC, + BlockDefinition.registry(), + blockKey + ).getOrThrow(RuntimeException::new); + + for (final CustomBlockType customBlockType : customBlockTypes) { + model = model.expandWith(customBlockType.state(), customBlockType.model()); + } + + map.put(blockKey, model); + }); + + return map; + }, customBlocks); + + // Other registries + + event.register(LoreProcessor.registry().location(), true, () -> Map.of( + SpongeTools.key("plain"), LoreProcessor.Plain.CODEC, + SpongeTools.key("apply_fallback_style"), LoreProcessor.ApplyFallbackStyle.CODEC, + SpongeTools.key("separated"), LoreProcessor.Separated.CODEC + )); + event.register(LoreProvider.registry().location(), true, () -> Map.of( + SpongeTools.key("plain"), LoreProvider.Plain.CODEC + )); + event.register(CustomConsumeEffect.registry().location(), true); + } + + @Listener + public void registerServerRegistryValues(final RegisterRegistryValueEvent.EngineScoped event) { + // TODO Load & Register CustomItemTypes from configs + } + + @Listener + public void assembleResourcePack(final FreezeRegistryEvent.Post.EngineScoped event) throws IOException { + final RegistryHolder holder = event.holder(); + this.logger.info(RegistryTypes.ENCHANTMENT_TYPE.defaultHolder().get()); + this.logger.info(holder); + this.logger.info(holder == RegistryTypes.ENCHANTMENT_TYPE.defaultHolder().get()); + final Map items = holder.registry(ItemDefinition.registry()) + .streamEntries() + .collect(Collectors.toMap(RegistryEntry::key, RegistryEntry::value)); + + final Map blocks = holder.registry(BlockDefinition.registry()) + .streamEntries() + .collect(Collectors.toMap(RegistryEntry::key, RegistryEntry::value)); + + final Map models = holder.registry(Model.registry()) + .streamEntries() + .collect(Collectors.toMap(RegistryEntry::key, RegistryEntry::value)); + + // TODO + try (final ZipOutputStream out = new ZipOutputStream(new FileOutputStream(this.packResult))) { + final MetadataSection packmeta = MetadataSection.pack( + Component.text("Resource pack made with SpongeTools"), 46); + this.writeEntry(out, Metadata.CODEC, "pack.mcmeta", "pack.mcmeta", packmeta.asMetadata()); + + final File copy = this.assetsToCopy; + if (copy.exists() && copy.isDirectory()) { + final String pattern = Pattern.quote(copy.getPath()); + this.writeFile(out, copy, path -> path.replaceFirst(pattern, "assets")); + } + + for (final Map.Entry e : items.entrySet()) { + this.writeEntry(out, ItemDefinition.CODEC, "ItemDefinition", "items", e.getKey(), e.getValue()); + } + + for (final Map.Entry e : blocks.entrySet()) { + this.writeEntry(out, BlockDefinition.CODEC, "BlockDefinition", "blockstates", e.getKey(), e.getValue()); + } + + for (final Map.Entry e : models.entrySet()) { + this.writeEntry(out, Model.CODEC, "Model", "models", e.getKey(), e.getValue()); + } + } + + if (this.web.isEmpty()) { + return; + } + + if (Sponge.isServerAvailable()) { + this.assembleResourcePackRequest(Sponge.server()); + } + } + + @Listener + public void assembleResourcePackRequestOnServerStart(final StartedEngineEvent event) { + this.assembleResourcePackRequest(event.engine()); + } + + private void assembleResourcePackRequest(final Server server) { + server.boundAddress().ifPresentOrElse( + address -> { + INFO_BUILDER.uri(URI.create("http://" + address.getHostString() + ":" + this.port + "/resourcepack_id")) + .computeHashAndBuild() + .handle((info, ex) -> info != null + ? REQUEST_BUILDER.packs(info).build() + : null) + .thenApply(Optional::ofNullable) + .thenAccept(pack -> { + this.pack = pack; + pack.ifPresent(request -> + server.streamOnlinePlayers().forEach(player -> + player.sendResourcePacks(request))); + }); + }, + () -> { + this.logger.error("Server does not have bound address"); + }); + } + + private void writeFile( + final ZipOutputStream out, final File file, final UnaryOperator pathToName + ) throws IOException { + String entryName = pathToName.apply(file.getPath()).replace(File.separatorChar, '/'); + if (file.isFile()) { + final ZipEntry entry = new ZipEntry(entryName); + entry.setTime(file.lastModified()); + out.putNextEntry(entry); + Files.copy(file.toPath(), out); + out.closeEntry(); + } else if (file.isDirectory()) { + if (!entryName.endsWith("/")) { + entryName += "/"; + } + + final ZipEntry dirEntry = new ZipEntry(entryName); + dirEntry.setTime(file.lastModified()); + out.putNextEntry(dirEntry); + out.closeEntry(); + + for (final File subfile : file.listFiles()) { + writeFile(out, subfile, pathToName); + } + } else { + this.logger.warn("Weird file found while zipping pack: " + file.getAbsolutePath()); + } + } + + private void writeEntry( + final ZipOutputStream out, final Codec codec, + final String name, final String prefix, + final ResourceKey key, final T value + ) throws IOException { + this.writeEntry(out, codec, name, + "assets/" + key.namespace() + "/" + prefix + "/" + key.value() + ".json", value); + } + + private void writeEntry( + final ZipOutputStream out, final Codec codec, + final String name, final String entry, final T value + ) throws IOException { + final DataResult encoded = codec.encodeStart(JsonOps.INSTANCE, value); + if (encoded.isError()) { + this.logger.warn("Failed to encode " + name + ": " + encoded.error().get().message()); + return; + } + + out.putNextEntry(new ZipEntry(entry)); + out.write(GSON.toJson(encoded.result().get()).getBytes()); + out.closeEntry(); + } + + @Listener + public void sendResourcePack(final ServerSideConnectionEvent.Join event) { + this.logger.info("Player joined"); + this.pack.ifPresent(pack -> { + this.logger.info("Sending SpongeTools pack " + pack); + event.player().sendResourcePacks(pack); + }); + } + + public DataResult decode( + final Codec codec, final RegistryType registry, final ResourceKey key + ) { + File file = this.file(registry, key, ".json"); + if (file.exists() && file.isFile()) { + try { + final JsonReader reader = new JsonReader(new FileReader(file)); + final JsonObject json = GSON.fromJson(reader, JsonObject.class); + return codec.decode(JsonOps.INSTANCE, json).map(Pair::getFirst); + } catch (final Exception e) { + return DataResult.error(e::getMessage); + } + } + + return DataResult.error(() -> "Unknown file extension"); + } + + private File file( + final RegistryType registry, final ResourceKey key, final String suffix + ) { + final char separator = File.separatorChar; + return new File(this.assetsToLoad, + key.namespace() + separator + + registry.location().value().replace('/', separator) + separator + + key.value().replace('/', separator) + suffix + ); + } + + @Override + public PluginContainer plugin() { + return this.plugin; + } +} diff --git a/common/src/main/java/net/hellheim/spongetools/common/behaviour/BehaviourManagerImpl.java b/common/src/main/java/net/hellheim/spongetools/common/behaviour/BehaviourManagerImpl.java new file mode 100644 index 0000000..02d260f --- /dev/null +++ b/common/src/main/java/net/hellheim/spongetools/common/behaviour/BehaviourManagerImpl.java @@ -0,0 +1,206 @@ +package net.hellheim.spongetools.common.behaviour; + +import java.util.Collection; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import net.hellheim.spongetools.custom.behaviour.Behaviour; +import net.hellheim.spongetools.custom.behaviour.BehaviourArgs; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallback; +import net.hellheim.spongetools.custom.behaviour.BehaviourCallbackHolderLogic; +import net.hellheim.spongetools.custom.behaviour.BehaviourManager; +import net.hellheim.spongetools.custom.behaviour.BehaviourType; +import net.hellheim.spongetools.custom.behaviour.TypedBehaviourCallback; + +@SuppressWarnings("unchecked") +public final class BehaviourManagerImpl implements BehaviourManager { + + private final Map, BehaviourRegistrationImpl> registrations = new HashMap<>(); + + @Override + public boolean supportsBehaviour( + final H holder, final BehaviourType type + ) { + Objects.requireNonNull(holder, "holder"); + Objects.requireNonNull(type, "type"); + for (final var entry : this.registrations.entrySet()) { + if (entry.getKey().isInstance(holder) + && entry.getValue().behaviourProviders.containsKey(type)) { + return true; + } + } + + return false; + } + + @Override + public > Optional behaviour( + final H holder, final BehaviourType type + ) { + Objects.requireNonNull(holder, "holder"); + Objects.requireNonNull(type, "type"); + for (final var entry : this.registrations.entrySet()) { + if (!entry.getKey().isInstance(holder)) { + continue; + } + + final BehaviourRegistrationImpl registration = (BehaviourRegistrationImpl) entry.getValue(); + final var provider = registration.behaviourProviders.get(type); + if (provider != null) { + return Optional.ofNullable((B) provider.apply(holder)); + } + } + + return Optional.empty(); + } + + @Override + public Collection> callbacks( + final H behaviourHolder, final Class callbackHolder + ) { + Objects.requireNonNull(behaviourHolder, "behaviourHolder"); + Objects.requireNonNull(callbackHolder, "callbackHolder"); + final BehaviourCallbackHolderLogic.Mutable callbacks = BehaviourCallbackHolderLogic.mutable(); + for (final var behaviourEntry : this.registrations.entrySet()) { + if (!behaviourEntry.getKey().isInstance(behaviourHolder)) { + continue; + } + + final BehaviourRegistrationImpl behaviourRegistration = (BehaviourRegistrationImpl) behaviourEntry.getValue(); + for (final var callbackEntry : behaviourRegistration.registrations.entrySet()) { + if (!callbackHolder.isAssignableFrom(callbackEntry.getKey())) { + continue; + } + + final CallbackRegistrationImpl callbackRegistration = (CallbackRegistrationImpl) callbackEntry.getValue(); + for (final var providerEntry : callbackRegistration.callbackProviders.entrySet()) { + final var callback = providerEntry.getValue().apply(behaviourHolder); + if (callback != null) { + this.appendCallback(callbacks, providerEntry.getKey(), callback); + } + } + } + } + + return callbacks.callbacks(); + } + + private void appendCallback( + final BehaviourCallbackHolderLogic.Mutable callbacks, + final BehaviourType type, + final BehaviourCallback callback + ) { + callbacks.offer((BehaviourType>) type, (BehaviourCallback) callback); + } + + @Override + public Optional> callback( + final H behaviourHolder, final Class callbackHolder, + final BehaviourType> type + ) { + Objects.requireNonNull(behaviourHolder, "behaviourHolder"); + Objects.requireNonNull(callbackHolder, "callbackHolder"); + Objects.requireNonNull(type, "type"); + for (final var behaviourEntry : this.registrations.entrySet()) { + if (!behaviourEntry.getKey().isInstance(behaviourHolder)) { + continue; + } + + final BehaviourRegistrationImpl behaviourRegistration = (BehaviourRegistrationImpl) behaviourEntry.getValue(); + for (final var callbackEntry : behaviourRegistration.registrations.entrySet()) { + if (!callbackHolder.isAssignableFrom(callbackEntry.getKey())) { + continue; + } + + final CallbackRegistrationImpl callbackRegistration = callbackEntry.getValue(); + final var provider = callbackRegistration.callbackProviders.get(type); + if (provider != null) { + return Optional.ofNullable((BehaviourCallback) provider.apply(behaviourHolder)); + } + } + } + + return Optional.empty(); + } + + @Override + public BehaviourRegistration behaviour(final Class behaviourHolder) { + Objects.requireNonNull(behaviourHolder, "behaviourHolder"); + return (BehaviourRegistration) this.registrations.computeIfAbsent(behaviourHolder, BehaviourRegistrationImpl::new); + } + + public static final class BehaviourRegistrationImpl implements BehaviourManager.BehaviourRegistration { + + private final Class behaviourHolder; + private final Map, Function>> behaviourProviders; + private final Map, CallbackRegistrationImpl> registrations; + + private BehaviourRegistrationImpl(final Class behaviourHolder) { + this.behaviourHolder = behaviourHolder; + this.behaviourProviders = new IdentityHashMap<>(); + this.registrations = new HashMap<>(); + } + + @Override + public > BehaviourRegistration register( + final BehaviourType type, + final Function behaviourProvider + ) { + Objects.requireNonNull(type, "type"); + Objects.requireNonNull(behaviourProvider, "behaviourProvider"); + if (this.behaviourProviders.containsKey(type)) { + throw new IllegalArgumentException(String.format( + "Behaviour provider is already registered for type %s for behaviour holder %s", + type, this.behaviourHolder + )); + } + + this.behaviourProviders.put(type, (Function>) behaviourProvider); + return this; + } + + @Override + public CallbackRegistration callbacks(final Class callbackHolder) { + Objects.requireNonNull(callbackHolder, "callbackHolder"); + return (CallbackRegistration) this.registrations + .computeIfAbsent(callbackHolder, $ -> new CallbackRegistrationImpl<>(this.behaviourHolder, callbackHolder)); + } + } + + public static final class CallbackRegistrationImpl implements BehaviourManager.CallbackRegistration { + + private final Class behaviourHolder; + private final Class callbackHolder; + private final Map, Function>> callbackProviders; + + private CallbackRegistrationImpl(final Class behaviourHolder, final Class callbackHolder) { + this.behaviourHolder = behaviourHolder; + this.callbackHolder = callbackHolder; + this.callbackProviders = new IdentityHashMap<>(); + } + + @Override + public CallbackRegistration register( + final BehaviourType> type, + final Function> callbackProvider + ) { + Objects.requireNonNull(type, "type"); + Objects.requireNonNull(callbackProvider, "callbackProvider"); + if (this.callbackProviders.containsKey(type)) { + throw new IllegalArgumentException(String.format( + "Callback provider is already registered for type %s for behaviour holder %s & callback holder %s", + type, this.behaviourHolder, this.callbackHolder + )); + } + + this.callbackProviders.put(type, (Function>) (Object) callbackProvider); + return this; + } + } +} diff --git a/common/src/main/java/net/hellheim/spongetools/common/behaviour/BlockStateArgs.java b/common/src/main/java/net/hellheim/spongetools/common/behaviour/BlockStateArgs.java new file mode 100644 index 0000000..6fe301a --- /dev/null +++ b/common/src/main/java/net/hellheim/spongetools/common/behaviour/BlockStateArgs.java @@ -0,0 +1,322 @@ +package net.hellheim.spongetools.common.behaviour; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiConsumer; + +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.data.type.HandType; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.fluid.FluidType; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackLike; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.util.RandomProvider; +import org.spongepowered.api.world.World; +import org.spongepowered.api.world.explosion.Explosion; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.api.world.volume.Volume; +import org.spongepowered.api.world.volume.game.PrimitiveGameVolume; +import org.spongepowered.api.world.volume.game.Region; +import org.spongepowered.api.world.volume.game.UpdatableVolume; +import org.spongepowered.math.vector.Vector3i; + +import net.hellheim.spongetools.custom.behaviour.BehaviourArgs; +import net.hellheim.spongetools.custom.behaviour.type.BlockStateBehaviour; +import net.hellheim.spongetools.custom.behaviour.util.HitResult; +import net.hellheim.spongetools.custom.behaviour.util.SignalOrientation; +import net.hellheim.spongetools.custom.behaviour.util.UseContext; +import net.hellheim.spongetools.custom.behaviour.util.UseContext.BlockPlace; + +public final class BlockStateArgs { + + public static BehaviourArgs empty() { + return Empty.INSTANCE; + } + + private record Empty() implements BehaviourArgs { + public static final Empty INSTANCE = new Empty(); + } + + public record Locatable(V volume, Vector3i position) + implements BlockStateBehaviour.Locatable.Args { + + @Override + public Locatable withVolume(final V volume) { + return new BlockStateArgs.Locatable<>(Objects.requireNonNull(volume, "volume"), this.position); + } + + @Override + public Locatable withPosition(final Vector3i position) { + return new BlockStateArgs.Locatable<>(this.volume, Objects.requireNonNull(position, "position")); + } + } + + public record LocatableEntity(V volume, Vector3i position, E entity) + implements BlockStateBehaviour.LocatableEntity.Args { + + @Override + public LocatableEntity withVolume(final V volume) { + return new BlockStateArgs.LocatableEntity<>(Objects.requireNonNull(volume, "volume"), this.position, this.entity); + } + + @Override + public LocatableEntity withPosition(final Vector3i position) { + return new BlockStateArgs.LocatableEntity<>(this.volume, Objects.requireNonNull(position, "position"), this.entity); + } + + @Override + public LocatableEntity withEntity(final E entity) { + return new BlockStateArgs.LocatableEntity<>(this.volume, this.position, Objects.requireNonNull(entity, "entity")); + } + } + + public record SignalPower(PrimitiveGameVolume volume, Vector3i position, Direction direction) + implements BlockStateBehaviour.SignalPower.Args { + + @Override + public SignalPower withVolume(final PrimitiveGameVolume volume) { + return new SignalPower(Objects.requireNonNull(volume, "volume"), this.position, this.direction); + } + + @Override + public SignalPower withPosition(final Vector3i position) { + return new SignalPower(this.volume, Objects.requireNonNull(position, "position"), this.direction); + } + + @Override + public SignalPower withDirection(final Direction direction) { + return new SignalPower(this.volume, this.position, Objects.requireNonNull(direction, "direction")); + } + } + + public record Tick(ServerWorld volume, Vector3i position, RandomProvider.Source random) + implements BlockStateBehaviour.Tick.Args { + + @Override + public Tick withVolume(final ServerWorld volume) { + return new Tick(Objects.requireNonNull(volume, "volume"), this.position, this.random); + } + + @Override + public Tick withPosition(final Vector3i position) { + return new Tick(this.volume, Objects.requireNonNull(position, "position"), this.random); + } + + @Override + public Tick withRandom(final RandomProvider.Source random) { + return new Tick(this.volume, this.position, Objects.requireNonNull(random, "random")); + } + } + + public record Replace(World volume, Vector3i position, BlockState otherState, boolean movedByPiston) + implements BlockStateBehaviour.Replace.Args { + + @Override + public Replace withVolume(final World volume) { + return new Replace(Objects.requireNonNull(volume, "volume"), this.position, this.otherState, this.movedByPiston); + } + + @Override + public Replace withPosition(final Vector3i position) { + return new Replace(this.volume, Objects.requireNonNull(position, "position"), this.otherState, this.movedByPiston); + } + + @Override + public Replace withOtherState(final BlockState otherState) { + return new Replace(this.volume, this.position, Objects.requireNonNull(otherState, "otherState"), this.movedByPiston); + } + + @Override + public Replace withMovedByPiston(final boolean movedByPiston) { + return new Replace(this.volume, this.position, this.otherState, movedByPiston); + } + } + + public record ExplosionHit(ServerWorld volume, Vector3i position, Explosion explosion, BiConsumer drop) + implements BlockStateBehaviour.ExplosionHit.Args { + + @Override + public ExplosionHit withVolume(final ServerWorld volume) { + return new ExplosionHit(Objects.requireNonNull(volume, "volume"), this.position, this.explosion, this.drop); + } + + @Override + public ExplosionHit withPosition(final Vector3i position) { + return new ExplosionHit(this.volume, Objects.requireNonNull(position, "position"), this.explosion, this.drop); + } + + @Override + public ExplosionHit withExplosion(final Explosion explosion) { + return new ExplosionHit(this.volume, this.position, Objects.requireNonNull(explosion, "explosion"), this.drop); + } + + @Override + public ExplosionHit withDrop(final BiConsumer drop) { + return new ExplosionHit(this.volume, this.position, this.explosion, drop); + } + } + + public record ShapeUpdate( + Region volume, UpdatableVolume updates, Vector3i position, + Direction direction, Vector3i neighbourPosition, BlockState neighbourState, + RandomProvider.Source random + ) implements BlockStateBehaviour.ShapeUpdate.Args { + + @Override + public ShapeUpdate withVolume(final Region volume) { + return new ShapeUpdate(Objects.requireNonNull(volume, "volume"), this.updates, this.position, this.direction, this.neighbourPosition, this.neighbourState, this.random); + } + + @Override + public ShapeUpdate withUpdates(final UpdatableVolume updates) { + return new ShapeUpdate(this.volume, Objects.requireNonNull(updates, "updates"), this.position, this.direction, this.neighbourPosition, this.neighbourState, this.random); + } + + @Override + public ShapeUpdate withPosition(final Vector3i position) { + return new ShapeUpdate(this.volume, this.updates, Objects.requireNonNull(position, "position"), this.direction, this.neighbourPosition, this.neighbourState, this.random); + } + + @Override + public ShapeUpdate withDirection(final Direction direction) { + return new ShapeUpdate(this.volume, this.updates, this.position, Objects.requireNonNull(direction, "direction"), this.neighbourPosition, this.neighbourState, this.random); + } + + @Override + public ShapeUpdate withNeighbourPosition(final Vector3i neighbourPosition) { + return new ShapeUpdate(this.volume, this.updates, this.position, this.direction, Objects.requireNonNull(neighbourPosition, "neighbourPosition"), this.neighbourState, this.random); + } + + @Override + public ShapeUpdate withNeighbourState(final BlockState neighbourState) { + return new ShapeUpdate(this.volume, this.updates, this.position, this.direction, this.neighbourPosition, Objects.requireNonNull(neighbourState, "neighbourState"), this.random); + } + + @Override + public ShapeUpdate withRandom(final RandomProvider.Source random) { + return new ShapeUpdate(this.volume, this.updates, this.position, this.direction, this.neighbourPosition, this.neighbourState, Objects.requireNonNull(random, "random")); + } + } + + public record SignalUpdate( + World volume, Vector3i position, BlockType notifier, + Optional orientation, boolean movedByPiston + ) implements BlockStateBehaviour.SignalUpdate.Args { + + @Override + public SignalUpdate withVolume(final World volume) { + return new SignalUpdate(Objects.requireNonNull(volume, "volume"), this.position, this.notifier, this.orientation, this.movedByPiston); + } + + @Override + public SignalUpdate withPosition(final Vector3i position) { + return new SignalUpdate(this.volume, Objects.requireNonNull(position, "position"), this.notifier, this.orientation, this.movedByPiston); + } + + @Override + public SignalUpdate withNotifier(final BlockType notifier) { + return new SignalUpdate(this.volume, this.position, Objects.requireNonNull(notifier, "notifier"), this.orientation, this.movedByPiston); + } + + @Override + public SignalUpdate withOrientation(final Optional orientation) { + return new SignalUpdate(this.volume, this.position, this.notifier, Objects.requireNonNull(orientation, "orientation"), this.movedByPiston); + } + + @Override + public SignalUpdate withMovedByPiston(final boolean movedByPiston) { + return new SignalUpdate(this.volume, this.position, this.notifier, this.orientation, movedByPiston); + } + } + + public record UseWithItem( + World volume, Player entity, HitResult.BlockHitResult hit, HandType hand, ItemStack item + ) implements BlockStateBehaviour.UseWithItem.Args { + + @Override + public UseWithItem withVolume(final World volume) { + return new UseWithItem(Objects.requireNonNull(volume, "volume"), this.entity, this.hit, this.hand, this.item); + } + + @Override + public UseWithItem withEntity(final Player entity) { + return new UseWithItem(this.volume, Objects.requireNonNull(entity, "entity"), this.hit, this.hand, this.item); + } + + @Override + public UseWithItem withHit(final HitResult.BlockHitResult hit) { + return new UseWithItem(this.volume, this.entity, Objects.requireNonNull(hit, "hit"), this.hand, this.item); + } + + @Override + public UseWithItem withHand(final HandType hand) { + return new UseWithItem(this.volume, this.entity, this.hit, Objects.requireNonNull(hand, "hand"), this.item); + } + + @Override + public UseWithItem withItem(final ItemStackLike item) { + return new UseWithItem(this.volume, this.entity, this.hit, this.hand, Objects.requireNonNull(item, "item").asMutable()); + } + } + + public record UseWithoutItem(World volume, Player entity, HitResult.BlockHitResult hit) + implements BlockStateBehaviour.UseWithoutItem.Args { + + @Override + public UseWithoutItem withVolume(final World volume) { + return new UseWithoutItem(Objects.requireNonNull(volume, "volume"), this.entity, this.hit); + } + + @Override + public UseWithoutItem withEntity(final Player entity) { + return new UseWithoutItem(this.volume, Objects.requireNonNull(entity, "entity"), this.hit); + } + + @Override + public UseWithoutItem withHit(final HitResult.BlockHitResult hit) { + return new UseWithoutItem(this.volume, this.entity, Objects.requireNonNull(hit, "hit")); + } + } + + public record ReplaceableByFluid(FluidType fluid) + implements BlockStateBehaviour.ReplaceableByFluid.Args { + + @Override + public ReplaceableByFluid withFluid(final FluidType fluid) { + return new ReplaceableByFluid(Objects.requireNonNull(fluid, "fluid")); + } + } + + public record ReplaceableByBlock(UseContext.BlockPlace context) + implements BlockStateBehaviour.ReplaceableByBlock.Args { + + @Override + public ReplaceableByBlock withContext(final BlockPlace context) { + return new ReplaceableByBlock(Objects.requireNonNull(context, "context")); + } + } + + public record CloneItem(Region volume, Vector3i position, boolean data) + implements BlockStateBehaviour.CloneItem.Args { + + @Override + public CloneItem withVolume(final Region volume) { + return new CloneItem(Objects.requireNonNull(volume, "volume"), this.position, this.data); + } + + @Override + public CloneItem withPosition(final Vector3i position) { + return new CloneItem(this.volume, Objects.requireNonNull(position, "position"), this.data); + } + + @Override + public CloneItem withData(final boolean data) { + return new CloneItem(this.volume, this.position, Objects.requireNonNull(data, "data")); + } + } + + private BlockStateArgs() { + } +} diff --git a/common/src/main/java/net/hellheim/spongetools/common/behaviour/BlockStateDispatcherImpl.java b/common/src/main/java/net/hellheim/spongetools/common/behaviour/BlockStateDispatcherImpl.java new file mode 100644 index 0000000..ff2fa52 --- /dev/null +++ b/common/src/main/java/net/hellheim/spongetools/common/behaviour/BlockStateDispatcherImpl.java @@ -0,0 +1,53 @@ +package net.hellheim.spongetools.common.behaviour; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import org.spongepowered.api.block.BlockState; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; + +import net.hellheim.spongetools.custom.type.block.BlockStateDispatcher; +import net.hellheim.spongetools.custom.type.block.BlockStateHolder; +import net.hellheim.spongetools.custom.type.block.BlockStateProvider; + +public final class BlockStateDispatcherImpl implements BlockStateDispatcher { + + private final BiMap dispatched = HashBiMap.create(); + private final Map undispatched = new HashMap<>(); + + @Override + public Optional get(final BlockState state) { + return Optional.ofNullable(this.dispatched.get(Objects.requireNonNull(state, "state"))); + } + + @Override + public boolean isOccupied(final BlockState state) { + return this.dispatched.containsKey(Objects.requireNonNull(state, "state")); + } + + @Override + public void submit(final BlockStateHolder holder, final BlockStateProvider provider) { + Objects.requireNonNull(holder, "holder"); + Objects.requireNonNull(provider, "provider"); + if (!this.dispatched.containsValue(holder)) { + this.undispatched.put(holder, provider); + } + } + + @Override + public void dispatch() { + if (this.undispatched.isEmpty()) { + return; + } + + this.undispatched.forEach((holder, provider) -> { + final BlockState state = provider.provide(); + holder.bind(state); + this.dispatched.put(state, holder); + }); + } +} diff --git a/common/src/main/java/net/hellheim/spongetools/common/codec/AdventureCodecsFactory.java b/common/src/main/java/net/hellheim/spongetools/common/codec/AdventureCodecsFactory.java new file mode 100644 index 0000000..258ce1b --- /dev/null +++ b/common/src/main/java/net/hellheim/spongetools/common/codec/AdventureCodecsFactory.java @@ -0,0 +1,211 @@ +package net.hellheim.spongetools.common.codec; + +import java.util.List; +import java.util.Set; + +import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.adventure.SpongeAdventure; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.hellheim.spongetools.codec.list.AdventureCodecs; +import net.hellheim.spongetools.codec.list.ExtraCodecs; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.chat.ChatType; +import net.kyori.adventure.inventory.Book; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.event.HoverEvent.ShowEntity; +import net.kyori.adventure.text.event.HoverEvent.ShowItem; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextColor; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.network.chat.HoverEvent.EntityTooltipInfo; +import net.minecraft.network.chat.HoverEvent.ItemStackInfo; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +public final class AdventureCodecsFactory implements AdventureCodecs.Factory { + + public static final Codec COMPONENT = ComponentSerialization.CODEC.xmap(SpongeAdventure::asAdventure, SpongeAdventure::asVanilla); + + public static final Codec BOSS_BAR_COLOR = ExtraCodecs.idResolver(Codec.STRING, BossBar.Color.NAMES); + + public static final Codec BOSS_BAR_FLAG = ExtraCodecs.idResolver(Codec.STRING, BossBar.Flag.NAMES); + + public static final Codec BOSS_BAR_OVERLAY = ExtraCodecs.idResolver(Codec.STRING, BossBar.Overlay.NAMES); + + public static final Codec BOSS_BAR = RecordCodecBuilder.create( + instance -> instance.group( + AdventureCodecsFactory.COMPONENT.fieldOf("name").forGetter(BossBar::name), + Codec.floatRange(0, 1).optionalFieldOf("progress", 1.0F).forGetter(BossBar::progress), + AdventureCodecsFactory.BOSS_BAR_COLOR.fieldOf("color").forGetter(BossBar::color), + AdventureCodecsFactory.BOSS_BAR_OVERLAY.fieldOf("overlay").forGetter(BossBar::overlay), + ExtraCodecs.setOf(AdventureCodecsFactory.BOSS_BAR_FLAG).optionalFieldOf("flags", Set.of()).forGetter(BossBar::flags) + ).apply(instance, BossBar::bossBar)); + + public static final Codec BOOK = RecordCodecBuilder.create( + instance -> instance.group( + AdventureCodecsFactory.COMPONENT.fieldOf("title").forGetter(Book::title), + AdventureCodecsFactory.COMPONENT.fieldOf("author").forGetter(Book::author), + AdventureCodecsFactory.COMPONENT.listOf().optionalFieldOf("pages", List.of()).forGetter(Book::pages) + ).apply(instance, Book::book)); + + @Override + public Codec namedTextColor() { + return ExtraCodecs.idResolver(Codec.STRING, NamedTextColor.NAMES); + } + + @Override + public Codec textColor() { + return net.minecraft.network.chat.TextColor.CODEC.xmap(SpongeAdventure::asAdventure, SpongeAdventure::asVanillaNullable); + } + + @Override + public Codec showText() { + return this.component(); + } + + @Override + public Codec showItem() { + return ItemStackInfo.CODEC.xmap(AdventureCodecsFactory::asAdventure, AdventureCodecsFactory::asVanilla); + } + + @Override + public Codec showEntity() { + return EntityTooltipInfo.CODEC.xmap(AdventureCodecsFactory::asAdventure, AdventureCodecsFactory::asVanilla); + } + + @Override + public Codec> hoverEventAction() { + return net.minecraft.network.chat.HoverEvent.Action.CODEC.xmap(AdventureCodecsFactory::asAdventure, SpongeAdventure::asVanilla); + } + + @Override + public Codec> hoverEvent() { + return net.minecraft.network.chat.HoverEvent.CODEC.xmap(SpongeAdventure::asAdventure, SpongeAdventure::asVanillaNullable); + } + + @Override + public Codec clickEventAction() { + return net.minecraft.network.chat.ClickEvent.Action.CODEC.codec().xmap(SpongeAdventure::asAdventure, SpongeAdventure::asVanilla); + } + + @Override + public Codec clickEvent() { + return net.minecraft.network.chat.ClickEvent.CODEC.xmap(AdventureCodecsFactory::asAdventure, SpongeAdventure::asVanillaNullable); + } + + @Override + public Codec