From 8a12734ecde7537f2bb371fd389bfd2669709b3c Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Mon, 2 Dec 2024 03:26:30 -0500 Subject: [PATCH 001/224] Added deprecations. Signed-off-by: = --- .../common/internal/common/cache/object/BakedGeoModel.java | 3 +++ .../mod/azure/azurelib/core/animatable/GeoAnimatable.java | 3 +++ .../core/animatable/instance/AnimatableInstanceCache.java | 3 +++ .../animatable/instance/InstancedAnimatableInstanceCache.java | 3 +++ .../animatable/instance/SingletonAnimatableInstanceCache.java | 3 +++ .../azurelib/core/animatable/model/CoreBakedGeoModel.java | 3 +++ .../mod/azure/azurelib/core/animatable/model/CoreGeoBone.java | 3 +++ .../azure/azurelib/core/animatable/model/CoreGeoModel.java | 3 +++ .../mod/azure/azurelib/core/animation/AnimatableManager.java | 3 +++ .../java/mod/azure/azurelib/core/animation/Animation.java | 3 +++ .../azure/azurelib/core/animation/AnimationController.java | 2 ++ .../mod/azure/azurelib/core/animation/AnimationProcessor.java | 4 ++++ .../mod/azure/azurelib/core/animation/AnimationState.java | 3 +++ .../core/animation/ContextAwareAnimatableManager.java | 3 +++ .../java/mod/azure/azurelib/core/animation/EasingType.java | 3 +++ .../java/mod/azure/azurelib/core/animation/RawAnimation.java | 2 ++ .../main/java/mod/azure/azurelib/core/state/BoneSnapshot.java | 3 +++ 17 files changed, 50 insertions(+) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java index 4e1a25fcb..d38c74a28 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java @@ -17,7 +17,10 @@ /** * Baked model object for AzureLib models. + * + * @deprecated */ +@Deprecated(forRemoval = true) public class BakedGeoModel implements CoreBakedGeoModel { public final Map bonesByName; diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java b/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java index 6ecb4a43f..345578a21 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java @@ -23,7 +23,10 @@ *
  • {@code GeoEntity}
  • *
  • {@code GeoItem}
  • * + * + * @deprecated */ +@Deprecated(forRemoval = true) public interface GeoAnimatable { /** diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java index 92ad6b7d6..3b3993cb6 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java @@ -22,7 +22,10 @@ * The base cache class responsible for returning the {@link AnimatableManager} for a given instanceof of a * {@link GeoAnimatable}. This class is abstracted and not intended for direct use. See either * {@link SingletonAnimatableInstanceCache} or {@link InstancedAnimatableInstanceCache} + * + * @deprecated */ +@Deprecated(forRemoval = true) public abstract class AnimatableInstanceCache { protected final GeoAnimatable animatable; diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java index 4f373f4b4..6baa602dd 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java @@ -13,7 +13,10 @@ /** * AnimatableInstanceCache implementation for instantiated objects such as Entities or BlockEntities. Returns a single * {@link AnimatableManager} instance per cache. + * + * @deprecated */ +@Deprecated(forRemoval = true) public class InstancedAnimatableInstanceCache extends AnimatableInstanceCache { protected AnimatableManager manager; diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java index 64c11ae0c..16392952e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java @@ -15,7 +15,10 @@ /** * AnimatableInstanceCache implementation for singleton/flyweight objects such as Items. Utilises a keyed map to * differentiate different instances of the object. + * + * @deprecated */ +@Deprecated(forRemoval = true) public class SingletonAnimatableInstanceCache extends AnimatableInstanceCache { protected final Long2ObjectMap> managers = new Long2ObjectOpenHashMap<>(); diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java index c524a9935..a6d436fc2 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java @@ -13,7 +13,10 @@ /** * Baked model object for AzureLib models.
    * Mostly an internal placeholder to allow for splitting up core (non-Minecraft) libraries + * + * @deprecated */ +@Deprecated(forRemoval = true) public interface CoreBakedGeoModel { List getBones(); diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java index 513f843b9..acb57349e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java @@ -14,7 +14,10 @@ /** * Base class for AzureLib {@link CoreGeoModel model} bones.
    * Mostly a placeholder to allow for splitting up core (non-Minecraft) libraries + * + * @deprecated */ +@Deprecated(forRemoval = true) public interface CoreGeoBone { String getName(); diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java index 6669ec019..3c9514aed 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java @@ -18,7 +18,10 @@ /** * Base class for AzureLib models.
    * Mostly an internal placeholder to allow for splitting up core (non-Minecraft) libraries + * + * @deprecated */ +@Deprecated(forRemoval = true) public interface CoreGeoModel { /** diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java index eddb48401..c55efdad7 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java @@ -22,7 +22,10 @@ * The animation data collection for a given animatable instance.
    * Generally speaking, a single working-instance of an {@link GeoAnimatable Animatable} will have a single instance of * {@code AnimatableManager} associated with it.
    + * + * @deprecated */ +@Deprecated(forRemoval = true) public class AnimatableManager { private final Map boneSnapshotCollection = new Object2ObjectOpenHashMap<>(); diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java index fa78b85b6..5b1a94509 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java @@ -22,7 +22,10 @@ * A compiled animation instance for use by the {@link AnimationController}
    * Modifications or extensions of a compiled Animation are not supported, and therefore an instance of * Animation is considered final and immutable. + * + * @deprecated */ +@Deprecated(forRemoval = true) public record Animation( String name, double length, diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java index 6da9f63af..651bf006b 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java @@ -38,7 +38,9 @@ * The actual controller that handles the playing and usage of animations, including their various keyframes and * instruction markers. Each controller can only play a single animation at a time - for example you may have one * controller to animate walking, one to control attacks, one to control size, etc. + * @deprecated */ +@Deprecated(forRemoval = true) public class AnimationController { protected static final Logger LOGGER = LoggerFactory.getLogger(AnimationController.class); diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java index ae2517605..2d95754a2 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java @@ -21,6 +21,10 @@ import java.util.*; +/** + * @deprecated + */ +@Deprecated(forRemoval = true) public class AnimationProcessor { private static final Logger LOGGER = LoggerFactory.getLogger(AnimationProcessor.class); diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java index 5e3d2fba2..892136062 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java @@ -19,7 +19,10 @@ * Animation state handler for end-users.
    * This is where users would set their selected animation to play, stop the controller, or any number of other * animation-related actions. + * + * @deprecated */ +@Deprecated(forRemoval = true) public class AnimationState { private final T animatable; diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java b/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java index c3dd6cbdb..41707bf49 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java @@ -19,7 +19,10 @@ * This can be used for things like perspective-dependent animation handling and other similar functionality.
    * This relies entirely on data present in {@link AnimatableManager#extraData} saved to this manager to determine * context + * + * @deprecated */ +@Deprecated(forRemoval = true) public abstract class ContextAwareAnimatableManager extends AnimatableManager { private final Map> managers; diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java b/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java index 7d52da261..c662a9a18 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java @@ -25,7 +25,10 @@ * For more information on easings, see:
    * Easings.net
    * Cubic-Bezier.com
    + * + * @deprecated */ +@Deprecated(forRemoval = true) @FunctionalInterface public interface EasingType { diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java index d5ef9a6f7..82c887e04 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java @@ -25,7 +25,9 @@ *
    {@code
      * RawAnimation.begin().thenPlay("action.open_box").thenLoop("state.stay_open")
      * }
    + * @deprecated */ +@Deprecated(forRemoval = true) public final class RawAnimation { private final List animationList = new ObjectArrayList<>(); diff --git a/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java b/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java index 43c581425..29228f8a5 100644 --- a/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java +++ b/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java @@ -15,7 +15,10 @@ * A state monitoring class for a given {@link CoreGeoBone}.
    * Transformations applied to the bone is monitored by the {@link AnimationProcessor} in the course of animations, and * stored here for monitoring. + * + * @deprecated */ +@Deprecated(forRemoval = true) public class BoneSnapshot { private final CoreGeoBone bone; From 27791cee7b07f5e6d06829bda3761fde8a6729e3 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Mon, 2 Dec 2024 23:36:56 -0500 Subject: [PATCH 002/224] Ease back on the @Deprecated usage. Signed-off-by: = --- .../internal/client/renderer/GeoRenderer.java | 2 + .../common/cache/object/BakedGeoModel.java | 1 - .../common/loading/json/raw/Bone.java | 110 +++++++++--------- .../loading/object/BakedModelFactory.java | 2 + .../core/animatable/GeoAnimatable.java | 1 - .../instance/AnimatableInstanceCache.java | 1 - .../InstancedAnimatableInstanceCache.java | 1 - .../SingletonAnimatableInstanceCache.java | 1 - .../animatable/model/CoreBakedGeoModel.java | 1 - .../core/animatable/model/CoreGeoBone.java | 1 - .../core/animatable/model/CoreGeoModel.java | 1 - .../core/animation/AnimatableManager.java | 1 - .../azurelib/core/animation/Animation.java | 1 - .../core/animation/AnimationController.java | 1 - .../core/animation/AnimationProcessor.java | 1 - .../core/animation/AnimationState.java | 1 - .../ContextAwareAnimatableManager.java | 1 - .../azurelib/core/animation/EasingType.java | 1 - .../azurelib/core/animation/RawAnimation.java | 2 +- .../azurelib/core/state/BoneSnapshot.java | 1 - 20 files changed, 60 insertions(+), 72 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java index 28b4426bb..8d1844232 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java @@ -33,6 +33,8 @@ /** * Base interface for all AzureLib renderers.
    + * + * @deprecated */ public interface GeoRenderer { /** diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java index d38c74a28..4c74ef6a5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java @@ -20,7 +20,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public class BakedGeoModel implements CoreBakedGeoModel { public final Map bonesByName; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java index e305f3a22..ca3a924be 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java @@ -21,70 +21,70 @@ * Container class for cube information, only used in deserialization at startup */ public record Bone( - double[] bindPoseRotation, - Cube[] cubes, - @Nullable Boolean debug, - @Nullable Double inflate, - @Nullable Map locators, - @Nullable Boolean mirror, - @Nullable String name, - @Nullable Boolean neverRender, - @Nullable String parent, - double[] pivot, - @Nullable PolyMesh polyMesh, - @Nullable Long renderGroupId, - @Nullable Boolean reset, - double[] rotation, - @Nullable TextureMesh[] textureMeshes + double[] bindPoseRotation, + Cube[] cubes, + @Nullable Boolean debug, + @Nullable Double inflate, + @Nullable Map locators, + @Nullable Boolean mirror, + @Nullable String name, + @Nullable Boolean neverRender, + @Nullable String parent, + double[] pivot, + @Nullable PolyMesh polyMesh, + @Nullable Long renderGroupId, + @Nullable Boolean reset, + double[] rotation, + @Nullable TextureMesh[] textureMeshes ) { public static JsonDeserializer deserializer() throws JsonParseException { return (json, type, context) -> { - JsonObject obj = json.getAsJsonObject(); - double[] bindPoseRotation = JsonUtil.jsonArrayToDoubleArray( - GsonHelper.getAsJsonArray(obj, "bind_pose_rotation", null) + var obj = json.getAsJsonObject(); + var bindPoseRotation = JsonUtil.jsonArrayToDoubleArray( + GsonHelper.getAsJsonArray(obj, "bind_pose_rotation", null) ); - Cube[] cubes = JsonUtil.jsonArrayToObjectArray( - GsonHelper.getAsJsonArray(obj, "cubes", new JsonArray(0)), - context, - Cube.class + var cubes = JsonUtil.jsonArrayToObjectArray( + GsonHelper.getAsJsonArray(obj, "cubes", new JsonArray(0)), + context, + Cube.class ); - Boolean debug = JsonUtil.getOptionalBoolean(obj, "debug"); - Double inflate = JsonUtil.getOptionalDouble(obj, "inflate"); - Map locators = obj.has("locators") - ? JsonUtil.jsonObjToMap(GsonHelper.getAsJsonObject(obj, "locators"), context, LocatorValue.class) - : null; - Boolean mirror = JsonUtil.getOptionalBoolean(obj, "mirror"); - String name = GsonHelper.getAsString(obj, "name", null); - Boolean neverRender = JsonUtil.getOptionalBoolean(obj, "neverRender"); - String parent = GsonHelper.getAsString(obj, "parent", null); - double[] pivot = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "pivot", new JsonArray(0))); - PolyMesh polyMesh = GsonHelper.getAsObject(obj, "poly_mesh", null, context, PolyMesh.class); - Long renderGroupId = JsonUtil.getOptionalLong(obj, "render_group_id"); - Boolean reset = JsonUtil.getOptionalBoolean(obj, "reset"); - double[] rotation = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "rotation", null)); - TextureMesh[] textureMeshes = JsonUtil.jsonArrayToObjectArray( - GsonHelper.getAsJsonArray(obj, "texture_meshes", new JsonArray(0)), - context, - TextureMesh.class + var debug = JsonUtil.getOptionalBoolean(obj, "debug"); + var inflate = JsonUtil.getOptionalDouble(obj, "inflate"); + var locators = obj.has("locators") + ? JsonUtil.jsonObjToMap(GsonHelper.getAsJsonObject(obj, "locators"), context, LocatorValue.class) + : null; + var mirror = JsonUtil.getOptionalBoolean(obj, "mirror"); + var name = GsonHelper.getAsString(obj, "name", null); + var neverRender = JsonUtil.getOptionalBoolean(obj, "neverRender"); + var parent = GsonHelper.getAsString(obj, "parent", null); + var pivot = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "pivot", new JsonArray(0))); + var polyMesh = GsonHelper.getAsObject(obj, "poly_mesh", null, context, PolyMesh.class); + var renderGroupId = JsonUtil.getOptionalLong(obj, "render_group_id"); + var reset = JsonUtil.getOptionalBoolean(obj, "reset"); + var rotation = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "rotation", null)); + var textureMeshes = JsonUtil.jsonArrayToObjectArray( + GsonHelper.getAsJsonArray(obj, "texture_meshes", new JsonArray(0)), + context, + TextureMesh.class ); return new Bone( - bindPoseRotation, - cubes, - debug, - inflate, - locators, - mirror, - name, - neverRender, - parent, - pivot, - polyMesh, - renderGroupId, - reset, - rotation, - textureMeshes + bindPoseRotation, + cubes, + debug, + inflate, + locators, + mirror, + name, + neverRender, + parent, + pivot, + polyMesh, + renderGroupId, + reset, + rotation, + textureMeshes ); }; } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java index 313ee8afb..53fa77ea5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java @@ -23,6 +23,8 @@ /** * Base interface for a factory of {@link BakedGeoModel} objects. Handled by default by AzureLib, but custom * implementations may be added by other mods for special needs + * + * @deprecated */ public interface BakedModelFactory { diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java b/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java index 345578a21..c6a32c50c 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java @@ -26,7 +26,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public interface GeoAnimatable { /** diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java index 3b3993cb6..8cbdb1f0f 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java @@ -25,7 +25,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public abstract class AnimatableInstanceCache { protected final GeoAnimatable animatable; diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java index 6baa602dd..c67b2a313 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java @@ -16,7 +16,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public class InstancedAnimatableInstanceCache extends AnimatableInstanceCache { protected AnimatableManager manager; diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java index 16392952e..f23562202 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java @@ -18,7 +18,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public class SingletonAnimatableInstanceCache extends AnimatableInstanceCache { protected final Long2ObjectMap> managers = new Long2ObjectOpenHashMap<>(); diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java index a6d436fc2..f3ae33a46 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java @@ -16,7 +16,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public interface CoreBakedGeoModel { List getBones(); diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java index acb57349e..d6c3f2eb6 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java @@ -17,7 +17,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public interface CoreGeoBone { String getName(); diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java index 3c9514aed..112501422 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java @@ -21,7 +21,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public interface CoreGeoModel { /** diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java index c55efdad7..c02342105 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java @@ -25,7 +25,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public class AnimatableManager { private final Map boneSnapshotCollection = new Object2ObjectOpenHashMap<>(); diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java index 5b1a94509..4385e9da7 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java @@ -25,7 +25,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public record Animation( String name, double length, diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java index 651bf006b..8f1dd40cf 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java @@ -40,7 +40,6 @@ * controller to animate walking, one to control attacks, one to control size, etc. * @deprecated */ -@Deprecated(forRemoval = true) public class AnimationController { protected static final Logger LOGGER = LoggerFactory.getLogger(AnimationController.class); diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java index 2d95754a2..7a77ff1e6 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java @@ -24,7 +24,6 @@ /** * @deprecated */ -@Deprecated(forRemoval = true) public class AnimationProcessor { private static final Logger LOGGER = LoggerFactory.getLogger(AnimationProcessor.class); diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java index 892136062..9766fdb93 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java @@ -22,7 +22,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public class AnimationState { private final T animatable; diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java b/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java index 41707bf49..2e2d6d5f7 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java @@ -22,7 +22,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public abstract class ContextAwareAnimatableManager extends AnimatableManager { private final Map> managers; diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java b/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java index c662a9a18..b6f5475dd 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java @@ -28,7 +28,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) @FunctionalInterface public interface EasingType { diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java index 82c887e04..e46f8762d 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java @@ -25,9 +25,9 @@ *
    {@code
      * RawAnimation.begin().thenPlay("action.open_box").thenLoop("state.stay_open")
      * }
    + * * @deprecated */ -@Deprecated(forRemoval = true) public final class RawAnimation { private final List animationList = new ObjectArrayList<>(); diff --git a/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java b/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java index 29228f8a5..570ca63f5 100644 --- a/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java +++ b/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java @@ -18,7 +18,6 @@ * * @deprecated */ -@Deprecated(forRemoval = true) public class BoneSnapshot { private final CoreGeoBone bone; From 48014e1412fcdc59dd4d2d7e51fc25a7b308c434 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Mon, 2 Dec 2024 23:56:58 -0500 Subject: [PATCH 003/224] Added AzBone.java. Signed-off-by: = --- .../azure/azurelib/core2/model/AzBone.java | 467 ++++++++++++++++++ 1 file changed, 467 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java new file mode 100644 index 000000000..2c5b1676c --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java @@ -0,0 +1,467 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. + * Original source: https://github.com/bernie-g/geckolib + * Copyright © 2024 Bernie-G. + * Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.model; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.state.BoneSnapshot; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3f; +import org.joml.Matrix4f; +import org.joml.Vector3d; +import org.joml.Vector4f; + +import java.util.List; +import java.util.Objects; + +/** + * Mutable bone object representing a set of cubes, as well as child bones.
    + * This is the object that is directly modified by animations to handle movement + */ +public class AzBone implements CoreGeoBone { + + private final AzBone parent; + + private final String name; + + private final List children = new ObjectArrayList<>(); + + private final List cubes = new ObjectArrayList<>(); + + private final Boolean mirror; + + private final Double inflate; + + private final Boolean dontRender; + + private final Boolean reset; + private final Matrix4f modelSpaceMatrix = new Matrix4f(); + private final Matrix4f localSpaceMatrix = new Matrix4f(); + private final Matrix4f worldSpaceMatrix = new Matrix4f(); + private BoneSnapshot initialSnapshot; + private boolean hidden; + private boolean childrenHidden = false; + private float scaleX = 1; + private float scaleY = 1; + private float scaleZ = 1; + private float positionX; + private float positionY; + private float positionZ; + private float pivotX; + private float pivotY; + private float pivotZ; + private float rotX; + private float rotY; + private float rotZ; + private boolean positionChanged = false; + private boolean rotationChanged = false; + private boolean scaleChanged = false; + private Matrix3f worldSpaceNormal = new Matrix3f(); + + private boolean trackingMatrices; + + public AzBone( + @Nullable AzBone parent, + String name, + Boolean mirror, + @Nullable Double inflate, + @Nullable Boolean dontRender, + @Nullable Boolean reset + ) { + this.parent = parent; + this.name = name; + this.mirror = mirror; + this.inflate = inflate; + this.dontRender = dontRender; + this.reset = reset; + this.trackingMatrices = false; + this.hidden = this.dontRender == Boolean.TRUE; + + this.worldSpaceNormal.identity(); + this.worldSpaceMatrix.identity(); + this.localSpaceMatrix.identity(); + this.modelSpaceMatrix.identity(); + } + + @Override + public String getName() { + return this.name; + } + + @Override + public AzBone getParent() { + return this.parent; + } + + @Override + public float getRotX() { + return this.rotX; + } + + @Override + public void setRotX(float value) { + this.rotX = value; + + markRotationAsChanged(); + } + + @Override + public float getRotY() { + return this.rotY; + } + + @Override + public void setRotY(float value) { + this.rotY = value; + + markRotationAsChanged(); + } + + @Override + public float getRotZ() { + return this.rotZ; + } + + @Override + public void setRotZ(float value) { + this.rotZ = value; + + markRotationAsChanged(); + } + + @Override + public float getPosX() { + return this.positionX; + } + + @Override + public void setPosX(float value) { + this.positionX = value; + + markPositionAsChanged(); + } + + @Override + public float getPosY() { + return this.positionY; + } + + @Override + public void setPosY(float value) { + this.positionY = value; + + markPositionAsChanged(); + } + + @Override + public float getPosZ() { + return this.positionZ; + } + + @Override + public void setPosZ(float value) { + this.positionZ = value; + + markPositionAsChanged(); + } + + @Override + public float getScaleX() { + return this.scaleX; + } + + @Override + public void setScaleX(float value) { + this.scaleX = value; + + markScaleAsChanged(); + } + + @Override + public float getScaleY() { + return this.scaleY; + } + + @Override + public void setScaleY(float value) { + this.scaleY = value; + + markScaleAsChanged(); + } + + @Override + public float getScaleZ() { + return this.scaleZ; + } + + @Override + public void setScaleZ(float value) { + this.scaleZ = value; + + markScaleAsChanged(); + } + + @Override + public boolean isHidden() { + return this.hidden; + } + + @Override + public void setHidden(boolean hidden) { + this.hidden = hidden; + + setChildrenHidden(hidden); + } + + @Override + public void setChildrenHidden(boolean hideChildren) { + this.childrenHidden = hideChildren; + } + + @Override + public float getPivotX() { + return this.pivotX; + } + + @Override + public void setPivotX(float value) { + this.pivotX = value; + } + + @Override + public float getPivotY() { + return this.pivotY; + } + + @Override + public void setPivotY(float value) { + this.pivotY = value; + } + + @Override + public float getPivotZ() { + return this.pivotZ; + } + + @Override + public void setPivotZ(float value) { + this.pivotZ = value; + } + + @Override + public boolean isHidingChildren() { + return this.childrenHidden; + } + + @Override + public void markScaleAsChanged() { + this.scaleChanged = true; + } + + @Override + public void markRotationAsChanged() { + this.rotationChanged = true; + } + + @Override + public void markPositionAsChanged() { + this.positionChanged = true; + } + + @Override + public boolean hasScaleChanged() { + return this.scaleChanged; + } + + @Override + public boolean hasRotationChanged() { + return this.rotationChanged; + } + + @Override + public boolean hasPositionChanged() { + return this.positionChanged; + } + + @Override + public void resetStateChanges() { + this.scaleChanged = false; + this.rotationChanged = false; + this.positionChanged = false; + } + + @Override + public BoneSnapshot getInitialSnapshot() { + return this.initialSnapshot; + } + + @Override + public List getChildBones() { + return this.children; + } + + @Override + public void saveInitialSnapshot() { + if (this.initialSnapshot == null) + this.initialSnapshot = saveSnapshot(); + } + + public Boolean getMirror() { + return this.mirror; + } + + public Double getInflate() { + return this.inflate; + } + + public Boolean shouldNeverRender() { + return this.dontRender; + } + + public Boolean getReset() { + return this.reset; + } + + public List getCubes() { + return this.cubes; + } + + public boolean isTrackingMatrices() { + return trackingMatrices; + } + + public void setTrackingMatrices(boolean trackingMatrices) { + this.trackingMatrices = trackingMatrices; + } + + public Matrix4f getModelSpaceMatrix() { + setTrackingMatrices(true); + + return this.modelSpaceMatrix; + } + + public void setModelSpaceMatrix(Matrix4f matrix) { + this.modelSpaceMatrix.set(matrix); + } + + public Matrix4f getLocalSpaceMatrix() { + setTrackingMatrices(true); + + return this.localSpaceMatrix; + } + + public void setLocalSpaceMatrix(Matrix4f matrix) { + this.localSpaceMatrix.set(matrix); + } + + public Matrix4f getWorldSpaceMatrix() { + setTrackingMatrices(true); + + return this.worldSpaceMatrix; + } + + public void setWorldSpaceMatrix(Matrix4f matrix) { + this.worldSpaceMatrix.set(matrix); + } + + public Matrix3f getWorldSpaceNormal() { + return worldSpaceNormal; + } + + public void setWorldSpaceNormal(Matrix3f matrix) { + this.worldSpaceNormal = matrix; + } + + /** + * Get the position of the bone relative to its owner + */ + public Vector3d getLocalPosition() { + Vector4f vec = getLocalSpaceMatrix().transform(new Vector4f(0, 0, 0, 1)); + + return new Vector3d(vec.x(), vec.y(), vec.z()); + } + + /** + * Get the position of the bone relative to the model it belongs to + */ + public Vector3d getModelPosition() { + Vector4f vec = getModelSpaceMatrix().transform(new Vector4f(0, 0, 0, 1)); + + return new Vector3d(-vec.x() * 16f, vec.y() * 16f, vec.z() * 16f); + } + + public void setModelPosition(Vector3d pos) { + // Doesn't work on bones with parent transforms + AzBone parent = getParent(); + Matrix4f matrix = (parent == null ? new Matrix4f().identity() : new Matrix4f(parent.getModelSpaceMatrix())) + .invert(); + Vector4f vec = matrix.transform( + new Vector4f(-(float) pos.x / 16f, (float) pos.y / 16f, (float) pos.z / 16f, 1) + ); + + updatePosition(-vec.x() * 16f, vec.y() * 16f, vec.z() * 16f); + } + + /** + * Get the position of the bone relative to the world + */ + public Vector3d getWorldPosition() { + Vector4f vec = getWorldSpaceMatrix().transform(new Vector4f(0, 0, 0, 1)); + + return new Vector3d(vec.x(), vec.y(), vec.z()); + } + + public Matrix4f getModelRotationMatrix() { + Matrix4f matrix = new Matrix4f(getModelSpaceMatrix()); + matrix.m03(0); + matrix.m13(0); + matrix.m23(0); + + return matrix; + } + + public Vector3d getPositionVector() { + return new Vector3d(getPosX(), getPosY(), getPosZ()); + } + + public Vector3d getRotationVector() { + return new Vector3d(getRotX(), getRotY(), getRotZ()); + } + + public Vector3d getScaleVector() { + return new Vector3d(getScaleX(), getScaleY(), getScaleZ()); + } + + public void addRotationOffsetFromBone(AzBone source) { + setRotX(getRotX() + source.getRotX() - source.getInitialSnapshot().getRotX()); + setRotY(getRotY() + source.getRotY() - source.getInitialSnapshot().getRotY()); + setRotZ(getRotZ() + source.getRotZ() - source.getInitialSnapshot().getRotZ()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + + if (obj == null || getClass() != obj.getClass()) + return false; + + return hashCode() == obj.hashCode(); + } + + @Override + public int hashCode() { + return Objects.hash( + getName(), + (getParent() != null ? getParent().getName() : 0), + getCubes().size(), + getChildBones().size() + ); + } +} From 62bfc179471448ba062d879a386864d515800e9d Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Mon, 2 Dec 2024 23:57:57 -0500 Subject: [PATCH 004/224] Added AzBakedModel.java. Signed-off-by: = --- .../azurelib/core2/model/AzBakedModel.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java new file mode 100644 index 000000000..ca10d01cc --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.core2.model; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class AzBakedModel { + + private final Map bonesByName; + + private final List topLevelBones; + + public AzBakedModel(List topLevelBones) { + this.topLevelBones = Collections.unmodifiableList(topLevelBones); + this.bonesByName = Collections.unmodifiableMap(mapBonesByName(topLevelBones)); + } + + public List getTopLevelBones() { + return topLevelBones; + } + + public Optional getBoneByName(String name) { + return Optional.ofNullable(bonesByName.get(name)); + } + + private Map mapBonesByName(List bones) { + return bones.stream() + .collect( + Collectors.toMap( + AzBone::getName, + Function.identity(), + (left, right) -> right + ) + ); + } +} From 56adc4d7fe44e2bdcad505b345e50241af1ba685 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Tue, 3 Dec 2024 00:02:41 -0500 Subject: [PATCH 005/224] Added AzBakedModelFactory.java, AzBuiltinBakedModelFactory.java and AzBakedModelFactoryRegistry.java. Signed-off-by: = --- .../model/factory/AzBakedModelFactory.java | 137 ++++++++++++++++++ .../impl/AzBuiltinBakedModelFactory.java | 88 +++++++++++ .../registry/AzBakedModelFactoryRegistry.java | 31 ++++ 3 files changed, 256 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/model/factory/registry/AzBakedModelFactoryRegistry.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java new file mode 100644 index 000000000..a360ca108 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java @@ -0,0 +1,137 @@ +package mod.azure.azurelib.core2.model.factory; + +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Cube; +import mod.azure.azurelib.common.internal.common.loading.json.raw.FaceUV; +import mod.azure.azurelib.common.internal.common.loading.json.raw.ModelProperties; +import mod.azure.azurelib.common.internal.common.loading.json.raw.UVUnion; +import mod.azure.azurelib.common.internal.common.loading.object.BoneStructure; +import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.factory.primitive.VertexSet; +import net.minecraft.core.Direction; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; + +public abstract class AzBakedModelFactory { + + + /** + * Construct the output model from the given {@link GeometryTree}.
    + */ + public abstract AzBakedModel constructGeoModel(GeometryTree geometryTree); + + /** + * Construct a {@link AzBone} from the relevant raw input data + * + * @param boneStructure The {@code BoneStructure} comprising the structure of the bone and its children + * @param properties The loaded properties for the model + * @param parent The parent bone for this bone, or null if a top-level bone + */ + public abstract AzBone constructBone(BoneStructure boneStructure, ModelProperties properties, @Nullable AzBone parent); + + /** + * Construct a {@link GeoCube} from the relevant raw input data + * + * @param cube The raw {@code Cube} comprising the structure and properties of the cube + * @param properties The loaded properties for the model + * @param bone The bone this cube belongs to + */ + public abstract GeoCube constructCube(Cube cube, ModelProperties properties, AzBone bone); + + /** + * Builtin method to construct the quad list from the various vertices and related data, to make it easier.
    + * Vertices have already been mirrored here if {@code mirror} is true + */ + public GeoQuad[] buildQuads( + UVUnion uvUnion, + VertexSet vertices, + Cube cube, + float textureWidth, + float textureHeight, + boolean mirror + ) { + GeoQuad[] quads = new GeoQuad[6]; + + quads[0] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.WEST); + quads[1] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.EAST); + quads[2] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.NORTH); + quads[3] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.SOUTH); + quads[4] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.UP); + quads[5] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.DOWN); + + return quads; + } + + /** + * Build an individual quad + */ + public GeoQuad buildQuad( + VertexSet vertices, + Cube cube, + UVUnion uvUnion, + float textureWidth, + float textureHeight, + boolean mirror, + Direction direction + ) { + if (!uvUnion.isBoxUV()) { + FaceUV faceUV = uvUnion.faceUV().fromDirection(direction); + + if (faceUV == null) + return null; + + return GeoQuad.build( + vertices.verticesForQuad(direction, false, mirror || cube.mirror() == Boolean.TRUE), + faceUV.uv(), + faceUV.uvSize(), + textureWidth, + textureHeight, + mirror, + direction + ); + } + + double[] uv = cube.uv().boxUVCoords(); + double[] uvSize = cube.size(); + Vec3 uvSizeVec = new Vec3(Math.floor(uvSize[0]), Math.floor(uvSize[1]), Math.floor(uvSize[2])); + double[][] uvData = switch (direction) { + case WEST -> new double[][]{ + new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z}, + new double[]{uvSizeVec.z, uvSizeVec.y} + }; + case EAST -> new double[][]{ + new double[]{uv[0], uv[1] + uvSizeVec.z}, + new double[]{uvSizeVec.z, uvSizeVec.y} + }; + case NORTH -> new double[][]{ + new double[]{uv[0] + uvSizeVec.z, uv[1] + uvSizeVec.z}, + new double[]{uvSizeVec.x, uvSizeVec.y} + }; + case SOUTH -> new double[][]{ + new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x + uvSizeVec.z, uv[1] + uvSizeVec.z}, + new double[]{uvSizeVec.x, uvSizeVec.y} + }; + case UP -> new double[][]{ + new double[]{uv[0] + uvSizeVec.z, uv[1]}, + new double[]{uvSizeVec.x, uvSizeVec.z} + }; + case DOWN -> new double[][]{ + new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z}, + new double[]{uvSizeVec.x, -uvSizeVec.z} + }; + }; + + return GeoQuad.build( + vertices.verticesForQuad(direction, true, mirror || cube.mirror() == Boolean.TRUE), + uvData[0], + uvData[1], + textureWidth, + textureHeight, + mirror, + direction + ); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java new file mode 100644 index 000000000..32567b9b4 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java @@ -0,0 +1,88 @@ +package mod.azure.azurelib.core2.model.factory.impl; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Cube; +import mod.azure.azurelib.common.internal.common.loading.json.raw.ModelProperties; +import mod.azure.azurelib.common.internal.common.loading.object.BoneStructure; +import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.factory.AzBakedModelFactory; +import mod.azure.azurelib.core2.model.factory.primitive.VertexSet; +import net.minecraft.world.phys.Vec3; + +public final class AzBuiltinBakedModelFactory extends AzBakedModelFactory { + + @Override + public AzBakedModel constructGeoModel(GeometryTree geometryTree) { + var bones = new ObjectArrayList(); + + for (var boneStructure : geometryTree.topLevelBones().values()) { + bones.add(constructBone(boneStructure, geometryTree.properties(), null)); + } + + return new AzBakedModel(bones); + } + + @Override + public AzBone constructBone(BoneStructure boneStructure, ModelProperties properties, AzBone parent) { + var bone = boneStructure.self(); + var newBone = new AzBone( + parent, + bone.name(), + bone.mirror(), + bone.inflate(), + bone.neverRender(), + bone.reset() + ); + var rotation = RenderUtils.arrayToVec(bone.rotation()); + var pivot = RenderUtils.arrayToVec(bone.pivot()); + + newBone.updateRotation( + (float) Math.toRadians(-rotation.x), + (float) Math.toRadians(-rotation.y), + (float) Math.toRadians(rotation.z) + ); + newBone.updatePivot((float) -pivot.x, (float) pivot.y, (float) pivot.z); + + for (var cube : bone.cubes()) { + newBone.getCubes().add(constructCube(cube, properties, newBone)); + } + + // TODO: Avoid recursive calls here. + for (var child : boneStructure.children().values()) { + newBone.getChildBones().add(constructBone(child, properties, newBone)); + } + + return newBone; + } + + @Override + public GeoCube constructCube(Cube cube, ModelProperties properties, AzBone bone) { + var mirror = cube.mirror() == Boolean.TRUE; + var inflate = cube.inflate() != null + ? cube.inflate() / 16f + : (bone.getInflate() == null ? 0 : bone.getInflate() / 16f); + var size = RenderUtils.arrayToVec(cube.size()); + var origin = RenderUtils.arrayToVec(cube.origin()); + var rotation = RenderUtils.arrayToVec(cube.rotation()); + var pivot = RenderUtils.arrayToVec(cube.pivot()); + origin = new Vec3(-(origin.x + size.x) / 16d, origin.y / 16d, origin.z / 16d); + var vertexSize = size.multiply(1 / 16d, 1 / 16d, 1 / 16d); + + pivot = pivot.multiply(-1, 1, 1); + rotation = new Vec3(Math.toRadians(-rotation.x), Math.toRadians(-rotation.y), Math.toRadians(rotation.z)); + var quads = buildQuads( + cube.uv(), + new VertexSet(origin, vertexSize, inflate), + cube, + (float) properties.textureWidth(), + (float) properties.textureHeight(), + mirror + ); + + return new GeoCube(quads, pivot, rotation, size, inflate, mirror); + } +} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/registry/AzBakedModelFactoryRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/registry/AzBakedModelFactoryRegistry.java new file mode 100644 index 000000000..2d948954e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/registry/AzBakedModelFactoryRegistry.java @@ -0,0 +1,31 @@ +package mod.azure.azurelib.core2.model.factory.registry; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.core2.model.factory.AzBakedModelFactory; +import mod.azure.azurelib.core2.model.factory.impl.AzBuiltinBakedModelFactory; + +import java.util.Map; + +public class AzBakedModelFactoryRegistry { + + private static final Map FACTORIES = new Object2ObjectOpenHashMap<>(1); + private static final AzBakedModelFactory DEFAULT_FACTORY = new AzBuiltinBakedModelFactory(); + + public static AzBakedModelFactory getForNamespace(String namespace) { + return FACTORIES.getOrDefault(namespace, DEFAULT_FACTORY); + } + + /** + * Register a custom {@link AzBakedModelFactory} to handle loading models in a custom way.
    + * MUST be called during mod construct
    + * It is recommended you don't call this directly, and instead call it via + * {@link AzureLibUtil#addCustomBakedModelFactory} + * + * @param namespace The namespace (modid) to register the factory for + * @param factory The factory responsible for model loading under the given namespace + */ + public static void register(String namespace, AzBakedModelFactory factory) { + FACTORIES.put(namespace, factory); + } +} From b7c622a1e791d3f8fc17e90ce08ccbf7687ef62f Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Tue, 3 Dec 2024 00:03:12 -0500 Subject: [PATCH 006/224] Added AzResourceCache.java, AzBakedModelCache.java and AzBakedAnimationCache.java. Signed-off-by: = --- .../internal/common/cache/AzureLibCache.java | 80 ++++++++++++++----- .../azure/azurelib/core2/AzResourceCache.java | 55 +++++++++++++ .../cache/AzBakedAnimationCache.java | 42 ++++++++++ .../core2/model/cache/AzBakedModelCache.java | 44 ++++++++++ 4 files changed, 199 insertions(+), 22 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java index 3fa012d87..170b50273 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java @@ -19,6 +19,8 @@ import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; import mod.azure.azurelib.core.animatable.model.CoreGeoModel; import mod.azure.azurelib.core.animation.Animation; +import mod.azure.azurelib.core2.animation.cache.AzBakedAnimationCache; +import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.PreparableReloadListener.PreparationBarrier; @@ -38,9 +40,14 @@ /** * Cache class for holding loaded {@link Animation Animations} and {@link CoreGeoModel Models} + * + * @deprecated Use {@link mod.azure.azurelib.core2.model.cache.AzBakedModelCache AzBakedModelCache}, instead. */ public final class AzureLibCache { + /** + * @deprecated + */ private static final Set EXCLUDED_NAMESPACES = ObjectOpenHashSet.of( "moreplayermodels", "customnpcs", @@ -51,14 +58,23 @@ public final class AzureLibCache { "neoforge" ); + /** + * @deprecated + */ private static Map ANIMATIONS = Collections.emptyMap(); + /** + * @deprecated + */ private static Map MODELS = Collections.emptyMap(); private AzureLibCache() { throw new UnsupportedOperationException(); } + /** + * @deprecated + */ public static Map getBakedAnimations() { if (!AzureLib.hasInitialized) throw new AzureLibException("AzureLib was never initialized! Please read the documentation!"); @@ -66,6 +82,9 @@ public static Map getBakedAnimations() { return ANIMATIONS; } + /** + * @deprecated + */ public static Map getBakedModels() { if (!AzureLib.hasInitialized) throw new AzureLibException("AzureLib was never initialized! Please read the documentation!"); @@ -76,10 +95,13 @@ public static Map getBakedModels() { public static void registerReloadListener() { Minecraft mc = Minecraft.getInstance(); - if (mc == null) return; + if (mc == null) { + return; + } - if (!(mc.getResourceManager() instanceof ReloadableResourceManager resourceManager)) + if (!(mc.getResourceManager() instanceof ReloadableResourceManager resourceManager)) { throw new AzureLibException("AzureLib was initialized too early!"); + } resourceManager.registerReloadListener(AzureLibCache::reload); } @@ -92,13 +114,18 @@ public static CompletableFuture reload( Executor backgroundExecutor, Executor gameExecutor ) { + // TODO: Remove these. Map animations = new Object2ObjectOpenHashMap<>(); Map models = new Object2ObjectOpenHashMap<>(); return CompletableFuture .allOf( - loadAnimations(backgroundExecutor, resourceManager, animations::put), - loadModels(backgroundExecutor, resourceManager, models::put) + // TODO: Remove these. + loadAnimations(backgroundExecutor, resourceManager, animations::put), + loadModels(backgroundExecutor, resourceManager, models::put), + // Forward-support for new cache components + AzBakedAnimationCache.getInstance().loadAnimations(backgroundExecutor, resourceManager), + AzBakedModelCache.getInstance().loadModels(backgroundExecutor, resourceManager) ) .thenCompose(stage::wait) .thenAcceptAsync(empty -> { @@ -107,6 +134,9 @@ public static CompletableFuture reload( }, gameExecutor); } + /** + * @deprecated + */ private static CompletableFuture loadAnimations( Executor backgroundExecutor, ResourceManager resourceManager, @@ -121,6 +151,9 @@ private static CompletableFuture loadAnimations( ); } + /** + * @deprecated + */ private static CompletableFuture loadModels( Executor backgroundExecutor, ResourceManager resourceManager, @@ -134,6 +167,9 @@ private static CompletableFuture loadModels( }, elementConsumer); } + /** + * @deprecated + */ private static CompletableFuture loadResources( Executor executor, ResourceManager resourceManager, @@ -142,23 +178,23 @@ private static CompletableFuture loadResources( BiConsumer map ) { return CompletableFuture.supplyAsync( - () -> resourceManager.listResources(type, fileName -> fileName.toString().endsWith(".json")), - executor - ) - .thenApplyAsync(resources -> { - Map> tasks = new Object2ObjectOpenHashMap<>(); - - for (ResourceLocation resource : resources.keySet()) { - tasks.put(resource, CompletableFuture.supplyAsync(() -> loader.apply(resource), executor)); - } - - return tasks; - }, executor) - .thenAcceptAsync(tasks -> { - for (Entry> entry : tasks.entrySet()) { - if (!EXCLUDED_NAMESPACES.contains(entry.getKey().getNamespace().toLowerCase(Locale.ROOT))) - map.accept(entry.getKey(), entry.getValue().join()); - } - }, executor); + () -> resourceManager.listResources(type, fileName -> fileName.toString().endsWith(".json")), + executor + ) + .thenApplyAsync(resources -> { + Map> tasks = new Object2ObjectOpenHashMap<>(); + + for (ResourceLocation resource : resources.keySet()) { + tasks.put(resource, CompletableFuture.supplyAsync(() -> loader.apply(resource), executor)); + } + + return tasks; + }, executor) + .thenAcceptAsync(tasks -> { + for (Entry> entry : tasks.entrySet()) { + if (!EXCLUDED_NAMESPACES.contains(entry.getKey().getNamespace().toLowerCase(Locale.ROOT))) + map.accept(entry.getKey(), entry.getValue().join()); + } + }, executor); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java b/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java new file mode 100644 index 000000000..f5d38109b --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java @@ -0,0 +1,55 @@ +package mod.azure.azurelib.core2; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; + +import java.util.Locale; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.BiConsumer; +import java.util.function.Function; + +public abstract class AzResourceCache { + + private static final Set EXCLUDED_NAMESPACES = ObjectOpenHashSet.of( + "moreplayermodels", + "customnpcs", + "creeperoverhaul", + "geckolib", + "gunsrpg", + "born_in_chaos_v1", + "neoforge" + ); + + protected final CompletableFuture loadResources( + Executor executor, + ResourceManager resourceManager, + String type, + Function loader, + BiConsumer map + ) { + return CompletableFuture.supplyAsync( + () -> resourceManager.listResources(type, fileName -> fileName.toString().endsWith(".json")), + executor + ) + .thenApplyAsync(resources -> { + var tasks = new Object2ObjectOpenHashMap>(); + + for (var resource : resources.keySet()) { + tasks.put(resource, CompletableFuture.supplyAsync(() -> loader.apply(resource), executor)); + } + + return tasks; + }, executor) + .thenAcceptAsync(tasks -> { + for (var entry : tasks.entrySet()) { + if (!EXCLUDED_NAMESPACES.contains(entry.getKey().getNamespace().toLowerCase(Locale.ROOT))) { + map.accept(entry.getKey(), entry.getValue().join()); + } + } + }, executor); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java new file mode 100644 index 000000000..02cb802b9 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java @@ -0,0 +1,42 @@ +package mod.azure.azurelib.core2.animation.cache; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mod.azure.azurelib.common.internal.common.loading.FileLoader; +import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; +import mod.azure.azurelib.core2.AzResourceCache; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +public class AzBakedAnimationCache extends AzResourceCache { + + private static final AzBakedAnimationCache INSTANCE = new AzBakedAnimationCache(); + + public static AzBakedAnimationCache getInstance() { + return INSTANCE; + } + + private final Map bakedAnimations; + + private AzBakedAnimationCache() { + this.bakedAnimations = new Object2ObjectOpenHashMap<>(); + } + + public CompletableFuture loadAnimations(Executor backgroundExecutor, ResourceManager resourceManager) { + return loadResources( + backgroundExecutor, + resourceManager, + "animations", + resource -> FileLoader.loadAnimationsFile(resource, resourceManager), + bakedAnimations::put + ); + } + + public @Nullable BakedAnimations getNullable(ResourceLocation resourceLocation) { + return bakedAnimations.get(resourceLocation); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java b/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java new file mode 100644 index 000000000..884f17e9f --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java @@ -0,0 +1,44 @@ +package mod.azure.azurelib.core2.model.cache; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mod.azure.azurelib.common.internal.common.loading.FileLoader; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; +import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; +import mod.azure.azurelib.core2.AzResourceCache; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.factory.registry.AzBakedModelFactoryRegistry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +public class AzBakedModelCache extends AzResourceCache { + + private static final AzBakedModelCache INSTANCE = new AzBakedModelCache(); + + public static AzBakedModelCache getInstance() { + return INSTANCE; + } + + private final Map bakedModels; + + private AzBakedModelCache() { + this.bakedModels = new Object2ObjectOpenHashMap<>(); + } + + public CompletableFuture loadModels(Executor backgroundExecutor, ResourceManager resourceManager) { + return loadResources(backgroundExecutor, resourceManager, "geo", resource -> { + Model model = FileLoader.loadModelFile(resource, resourceManager); + + return AzBakedModelFactoryRegistry.getForNamespace(resource.getNamespace()) + .constructGeoModel(GeometryTree.fromModel(model)); + }, bakedModels::put); + } + + public @Nullable AzBakedModel getNullable(ResourceLocation resourceLocation) { + return bakedModels.get(resourceLocation); + } +} From 5f887dc49088cf2e0eecff2f2dd384e4132d9ff1 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Tue, 3 Dec 2024 00:16:33 -0500 Subject: [PATCH 007/224] Added AzRenderLayer.java. Signed-off-by: = --- .../core2/render/layer/AzRenderLayer.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java new file mode 100644 index 000000000..5ee99bc8a --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java @@ -0,0 +1,48 @@ +package mod.azure.azurelib.core2.render.layer; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; + +/** + * Render layer base class for rendering additional layers of effects or textures over an existing model at runtime.
    + * Contains the base boilerplate and helper code for various render layer features + */ +public abstract class AzRenderLayer { + + public AzRenderLayer() {} + + /** + * This method is called by the {@link AzRendererPipeline} before rendering, immediately after {@link AzRendererPipeline#preRender} has been called.
    + * This allows for RenderLayers to perform pre-render manipulations such as hiding or showing bones + */ + public abstract void preRender(PoseStack poseStack, T animatable, AzBakedModel bakedModel, RenderType renderType, + MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, + int packedLight, int packedOverlay); + + /** + * This is the method that is actually called by the render for your render layer to function.
    + * This is called after the animatable has been rendered, but before supplementary rendering like nametags. + */ + public abstract void render(PoseStack poseStack, T animatable, AzBakedModel bakedModel, RenderType renderType, + MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, + int packedLight, int packedOverlay); + + /** + * This method is called by the {@link AzRendererPipeline} for each bone being rendered.
    + * This is a more expensive call, particularly if being used to render something on a different buffer.
    + * It does however have the benefit of having the matrix translations and other transformations already applied from render-time.
    + * It's recommended to avoid using this unless necessary.
    + *
    + * The {@link AzBone} in question has already been rendered by this stage.
    + *
    + * If you do use it, and you render something that changes the {@link VertexConsumer buffer}, you need to reset it back to the previous buffer + * using {@link MultiBufferSource#getBuffer} before ending the method + */ + public abstract void renderForBone(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, + MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay); +} \ No newline at end of file From 6b2520bce56b5e25b063793ad25ed030bdd6eb3a Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Tue, 3 Dec 2024 00:16:47 -0500 Subject: [PATCH 008/224] Added AzRendererPipeline.java. Signed-off-by: = --- .../render/pipeline/AzRendererPipeline.java | 301 ++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java new file mode 100644 index 000000000..52a8aef27 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -0,0 +1,301 @@ +package mod.azure.azurelib.core2.render.pipeline; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; +import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core.object.Color; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3f; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.joml.Vector4f; + +import java.util.List; + +public abstract class AzRendererPipeline { + + protected abstract @NotNull ResourceLocation getTextureLocation(@NotNull T animatable); + + /** + * Gets the {@link RenderType} to render the given animatable with.
    + * Uses the {@link RenderType#entityCutoutNoCull} {@code RenderType} by default.
    + * Override this to change the way a model will render (such as translucent models, etc) + */ + public abstract RenderType getDefaultRenderType(T animatable, ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, float partialTick); + + /** + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this GeoRenderer.
    + * This should only be called immediately prior to rendering, and only + * @see AnimatableTexture#setAndUpdate + */ + protected abstract void updateAnimatedTextureFrame(T animatable); + + /** + * Create and fire the relevant {@code CompileLayers} event hook for this renderer + */ + protected abstract void fireCompileRenderLayersEvent(); + + /** + * Create and fire the relevant {@code Pre-Render} event hook for this renderer.
    + * @return Whether the renderer should proceed based on the cancellation state of the event + */ + protected abstract boolean firePreRenderEvent(PoseStack poseStack, AzBakedModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + + /** + * Create and fire the relevant {@code Post-Render} event hook for this renderer + */ + protected abstract void firePostRenderEvent(PoseStack poseStack, AzBakedModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + + /** + * Initial access point for rendering. It all begins here.
    + * All AzureLib renderers should immediately defer their respective default {@code render} calls to this, for consistent handling + */ + public void defaultRender(PoseStack poseStack, AzBakedModel model, T animatable, MultiBufferSource bufferSource, @Nullable RenderType renderType, @Nullable VertexConsumer buffer, + float yaw, float partialTick, int packedLight) { + poseStack.pushPose(); + + var renderColor = getRenderColor(animatable, partialTick, packedLight).argbInt(); + var packedOverlay = getPackedOverlay(animatable, 0, partialTick); + + if (renderType == null) { + renderType = getDefaultRenderType(animatable, getTextureLocation(animatable), bufferSource, partialTick); + } + + if (buffer == null) { + buffer = bufferSource.getBuffer(renderType); + } + + preRender(poseStack, animatable, model, bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); + + if (firePreRenderEvent(poseStack, model, bufferSource, partialTick, packedLight)) { + preApplyRenderLayers(poseStack, animatable, model, renderType, bufferSource, buffer, packedLight, packedLight, packedOverlay); + actuallyRender(poseStack, animatable, model, renderType, + bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); + applyRenderLayers(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + postRender(poseStack, animatable, model, bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); + firePostRenderEvent(poseStack, model, bufferSource, partialTick, packedLight); + } + + poseStack.popPose(); + + renderFinal(poseStack, animatable, model, bufferSource, buffer, partialTick, packedLight, packedOverlay, renderColor); + doPostRenderCleanup(); + } + + /** + * Re-renders the provided {@link AzBakedModel}.
    + * Usually you'd use this for rendering alternate {@link RenderType} layers or for sub-model rendering whilst inside a {@link AzRenderLayer} or similar + */ + public void reRender(AzBakedModel model, PoseStack poseStack, MultiBufferSource bufferSource, T animatable, + RenderType renderType, VertexConsumer buffer, float partialTick, + int packedLight, int packedOverlay, int colour) { + poseStack.pushPose(); + preRender(poseStack, animatable, model, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); + actuallyRender(poseStack, animatable, model, renderType, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); + postRender(poseStack, animatable, model, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); + poseStack.popPose(); + } + + /** + * The actual render method that sub-type renderers should override to handle their specific rendering tasks.
    + */ + public void actuallyRender(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, + MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, + int packedLight, int packedOverlay, int colour) { + updateAnimatedTextureFrame(animatable); + + for (var bone : model.getTopLevelBones()) { + renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, + packedOverlay, colour); + } + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + public void renderRecursively(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, + VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, + int packedOverlay, int colour) { + poseStack.pushPose(); + RenderUtils.prepMatrixForBone(poseStack, bone); + renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); + + if (!isReRender) { + applyRenderLayersForBone(poseStack, animatable, bone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + } + + renderChildBones(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour); + poseStack.popPose(); + } + + /** + * Renders the {@link GeoCube GeoCubes} associated with a given {@link AzBone} + */ + public void renderCubesOfBone(PoseStack poseStack, AzBone bone, VertexConsumer buffer, int packedLight, + int packedOverlay, int colour) { + if (bone.isHidden()) + return; + + for (GeoCube cube : bone.getCubes()) { + poseStack.pushPose(); + renderCube(poseStack, cube, buffer, packedLight, packedOverlay, colour); + poseStack.popPose(); + } + } + + /** + * Render the child bones of a given {@link AzBone}.
    + * Note that this does not render the bone itself. That should be done through {@link AzRendererPipeline#renderCubesOfBone} separately + */ + public void renderChildBones(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, + boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) { + if (bone.isHidingChildren()) + return; + + for (var childBone : bone.getChildBones()) { + renderRecursively(poseStack, animatable, childBone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour); + } + } + + /** + * Renders an individual {@link GeoCube}.
    + * This tends to be called recursively from something like {@link AzRendererPipeline#renderCubesOfBone} + */ + public void renderCube(PoseStack poseStack, GeoCube cube, VertexConsumer buffer, int packedLight, + int packedOverlay, int colour) { + RenderUtils.translateToPivotPoint(poseStack, cube); + RenderUtils.rotateMatrixAroundCube(poseStack, cube); + RenderUtils.translateAwayFromPivotPoint(poseStack, cube); + + Matrix3f normalisedPoseState = poseStack.last().normal(); + Matrix4f poseState = new Matrix4f(poseStack.last().pose()); + + for (GeoQuad quad : cube.quads()) { + if (quad == null) + continue; + + Vector3f normal = normalisedPoseState.transform(new Vector3f(quad.normal())); + + RenderUtils.fixInvertedFlatCube(cube, normal); + createVerticesOfQuad(quad, poseState, normal, buffer, packedLight, packedOverlay, colour); + } + } + + /** + * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for rendering + */ + public void createVerticesOfQuad(GeoQuad quad, Matrix4f poseState, Vector3f normal, VertexConsumer buffer, + int packedLight, int packedOverlay, int colour) { + for (var vertex : quad.vertices()) { + var position = vertex.position(); + var vector4f = poseState.transform(new Vector4f(position.x(), position.y(), position.z(), 1.0f)); + + buffer.addVertex(vector4f.x(), vector4f.y(), vector4f.z(), colour, vertex.texU(), + vertex.texV(), packedOverlay, packedLight, normal.x(), normal.y(), normal.z()); + } + } + + /** + * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#preRender pre-render} actions. + */ + public void preApplyRenderLayers(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, MultiBufferSource bufferSource, + VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + for (var renderLayer : getRenderLayers()) { + renderLayer.preRender(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + } + } + + /** + * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#renderForBone per-bone} render actions. + */ + public void applyRenderLayersForBone(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, + VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + for (var renderLayer : getRenderLayers()) { + renderLayer.renderForBone(poseStack, animatable, bone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + } + } + + /** + * Render the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer + */ + public void applyRenderLayers(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, MultiBufferSource bufferSource, + VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + for (var renderLayer : getRenderLayers()) { + renderLayer.render(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + } + } + + /** + * Called before rendering the model to buffer. Allows for render modifications and preparatory + * work such as scaling and translating.
    + * {@link PoseStack} translations made here are kept until the end of the render process + */ + public void preRender(PoseStack poseStack, T animatable, AzBakedModel model, @Nullable MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, + int packedOverlay, int colour) {} + + /** + * Called after rendering the model to buffer. Post-render modifications should be performed here.
    + * {@link PoseStack} transformations will be unused and lost once this method ends + */ + public void postRender(PoseStack poseStack, T animatable, AzBakedModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {} + + /** + * Call after all other rendering work has taken place, including reverting the {@link PoseStack}'s state. This method is not called in {@link AzRendererPipeline#reRender re-render} + */ + public void renderFinal(PoseStack poseStack, T animatable, AzBakedModel model, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, + int packedOverlay, int colour) {} + + /** + * Called after all render operations are completed and the render pass is considered functionally complete. + *

    + * Use this method to clean up any leftover persistent objects stored during rendering or any other post-render maintenance tasks as required + */ + public void doPostRenderCleanup() {} + + /** + * Scales the {@link PoseStack} in preparation for rendering the model, excluding when re-rendering the model as part of a {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer} or external render call.
    + * Override and call super with modified scale values as needed to further modify the scale of the model (E.G. child entities) + */ + public void scaleModelForRender(float widthScale, float heightScale, PoseStack poseStack, T animatable, AzBakedModel model, boolean isReRender, float partialTick, int packedLight, int packedOverlay) { + if (!isReRender && (widthScale != 1 || heightScale != 1)) + poseStack.scale(widthScale, heightScale, widthScale); + } + + /** + * Gets a tint-applying color to render the given animatable with.
    + * Returns {@link Color#WHITE} by default + */ + public Color getRenderColor(T animatable, float partialTick, int packedLight) { + return Color.WHITE; + } + + /** + * Gets a packed overlay coordinate pair for rendering.
    + * Mostly just used for the red tint when an entity is hurt, + * but can be used for other things like the {@link net.minecraft.world.entity.monster.Creeper} + * white tint when exploding. + */ + public int getPackedOverlay(T animatable, float u, float partialTick) { + return OverlayTexture.NO_OVERLAY; + } + + /** + * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer + */ + protected List> getRenderLayers() { + return List.of(); + } +} From 2ecdc049d7ee805030a727723639470773d34ad0 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Tue, 3 Dec 2024 00:17:28 -0500 Subject: [PATCH 009/224] Added AzEntityRenderer.java, AzEntityRendererPipeline.java and RenderLeashUtil.java. Signed-off-by: = --- .../core2/render/entity/AzEntityRenderer.java | 148 ++++++ .../core2/render/entity/RenderLeashUtil.java | 154 ++++++ .../impl/AzEntityRendererPipeline.java | 481 ++++++++++++++++++ 3 files changed, 783 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/entity/RenderLeashUtil.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java new file mode 100644 index 000000000..6ed6e3c9e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -0,0 +1,148 @@ +package mod.azure.azurelib.core2.render.entity; + +import com.mojang.blaze3d.vertex.PoseStack; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import mod.azure.azurelib.core2.render.pipeline.impl.AzEntityRendererPipeline; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Objects; + +public abstract class AzEntityRenderer extends EntityRenderer { + + private float scaleWidth = 1; + private float scaleHeight = 1; + private final AzEntityRendererPipeline azEntityRendererPipeline; + private final List> renderLayers; + private final AzAnimator azAnimator; + + protected AzEntityRenderer(EntityRendererProvider.Context context) { + super(context); + this.azEntityRendererPipeline = new AzEntityRendererPipeline<>(this); + this.renderLayers = new ObjectArrayList<>(); + this.azAnimator = createAnimator(); + } + + protected abstract @Nullable AzAnimator createAnimator(); + protected abstract @NotNull ResourceLocation getModelLocation(T entity); + + @Override + public void render(@NotNull T entity, float entityYaw, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource bufferSource, int packedLight) { + var modelResourceLocation = getModelLocation(entity); + var bakedGeoModel = AzBakedModelCache.getInstance().getNullable(modelResourceLocation); + azEntityRendererPipeline.defaultRender(poseStack, bakedGeoModel, entity, bufferSource, null, null, entityYaw, partialTick, packedLight); + } + + /** + * Sets a scale override for this renderer, telling AzureLib to pre-scale the model + */ + public AzEntityRenderer withScale(float scale) { + return withScale(scale, scale); + } + + /** + * Sets a scale override for this renderer, telling AzureLib to pre-scale the model + */ + public AzEntityRenderer withScale(float scaleWidth, float scaleHeight) { + this.scaleWidth = scaleWidth; + this.scaleHeight = scaleHeight; + + return this; + } + + /** + * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer + */ + public List> getRenderLayers() { + return this.renderLayers; + } + + /** + * Adds a {@link AzRenderLayer} to this renderer, to be called after the main model is rendered each frame + */ + public AzEntityRenderer addRenderLayer(AzRenderLayer renderLayer) { + this.renderLayers.add(renderLayer); + + return this; + } + + /** + * Whether the entity's nametag should be rendered or not.
    + * Pretty much exclusively used in {@link EntityRenderer#renderNameTag} + */ + @Override + public boolean shouldShowName(T entity) { + var nameRenderDistance = entity.isDiscrete() ? 32d : 64d; + + if (!(entity instanceof LivingEntity)) { + return false; + } + + if (this.entityRenderDispatcher.distanceToSqr(entity) >= nameRenderDistance * nameRenderDistance) { + return false; + } + + if ( + entity instanceof Mob && (!entity.shouldShowName() && (!entity.hasCustomName() + || entity != this.entityRenderDispatcher.crosshairPickEntity)) + ) { + return false; + } + + final var minecraft = Minecraft.getInstance(); + // TODO: See if we can do this null check better. + var player = Objects.requireNonNull(minecraft.player); + var visibleToClient = !entity.isInvisibleTo(player); + var entityTeam = entity.getTeam(); + + if (entityTeam == null) { + return Minecraft.renderNames() && entity != minecraft.getCameraEntity() && visibleToClient + && !entity.isVehicle(); + } + + var playerTeam = minecraft.player.getTeam(); + + return switch (entityTeam.getNameTagVisibility()) { + case ALWAYS -> visibleToClient; + case NEVER -> false; + case HIDE_FOR_OTHER_TEAMS -> playerTeam == null + ? visibleToClient + : entityTeam.isAlliedTo( + playerTeam + ) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); + case HIDE_FOR_OWN_TEAM -> + playerTeam == null ? visibleToClient : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; + }; + } + + // Proxy method override for super.getBlockLightLevel external access. + @Override + public int getBlockLightLevel(@NotNull T entity, @NotNull BlockPos pos) { + return super.getBlockLightLevel(entity, pos); + } + + public AzAnimator getAnimator() { + return azAnimator; + } + + public float getScaleHeight() { + return scaleHeight; + } + + public float getScaleWidth() { + return scaleWidth; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/RenderLeashUtil.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/RenderLeashUtil.java new file mode 100644 index 000000000..5d67368c7 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/RenderLeashUtil.java @@ -0,0 +1,154 @@ +package mod.azure.azurelib.core2.render.entity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; + +public class RenderLeashUtil { + + /** + * Static rendering code for rendering a leash segment.
    + * It's a like-for-like from {@link net.minecraft.client.renderer.entity.MobRenderer#renderLeash} that had to be + * duplicated here for flexible usage + */ + public static void renderLeash( + AzEntityRenderer azEntityRenderer, + M mob, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + E leashHolder + ) { + double lerpBodyAngle = (Mth.lerp(partialTick, mob.yBodyRotO, mob.yBodyRot) * Mth.DEG_TO_RAD) + Mth.HALF_PI; + Vec3 leashOffset = mob.getLeashOffset(); + double xAngleOffset = Math.cos(lerpBodyAngle) * leashOffset.z + Math.sin(lerpBodyAngle) * leashOffset.x; + double zAngleOffset = Math.sin(lerpBodyAngle) * leashOffset.z - Math.cos(lerpBodyAngle) * leashOffset.x; + double lerpOriginX = Mth.lerp(partialTick, mob.xo, mob.getX()) + xAngleOffset; + double lerpOriginY = Mth.lerp(partialTick, mob.yo, mob.getY()) + leashOffset.y; + double lerpOriginZ = Mth.lerp(partialTick, mob.zo, mob.getZ()) + zAngleOffset; + Vec3 ropeGripPosition = leashHolder.getRopeHoldPosition(partialTick); + float xDif = (float) (ropeGripPosition.x - lerpOriginX); + float yDif = (float) (ropeGripPosition.y - lerpOriginY); + float zDif = (float) (ropeGripPosition.z - lerpOriginZ); + float offsetMod = Mth.invSqrt(xDif * xDif + zDif * zDif) * 0.025f / 2f; + float xOffset = zDif * offsetMod; + float zOffset = xDif * offsetMod; + VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.leash()); + BlockPos entityEyePos = BlockPos.containing(mob.getEyePosition(partialTick)); + BlockPos holderEyePos = BlockPos.containing(leashHolder.getEyePosition(partialTick)); + int entityBlockLight = azEntityRenderer.getBlockLightLevel((T) mob, entityEyePos); + int holderBlockLight = leashHolder.isOnFire() + ? 15 + : leashHolder.level() + .getBrightness( + LightLayer.BLOCK, + holderEyePos + ); + int entitySkyLight = mob.level().getBrightness(LightLayer.SKY, entityEyePos); + int holderSkyLight = mob.level().getBrightness(LightLayer.SKY, holderEyePos); + + poseStack.pushPose(); + poseStack.translate(xAngleOffset, leashOffset.y, zAngleOffset); + + Matrix4f posMatrix = new Matrix4f(poseStack.last().pose()); + + for (int segment = 0; segment <= 24; ++segment) { + renderLeashPiece( + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.025f, + xOffset, + zOffset, + segment, + false + ); + } + + for (int segment = 24; segment >= 0; --segment) { + renderLeashPiece( + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.0f, + xOffset, + zOffset, + segment, + true + ); + } + + poseStack.popPose(); + } + + /** + * Static rendering code for rendering a leash segment.
    + * It's a like-for-like from {@link net.minecraft.client.renderer.entity.MobRenderer#addVertexPair} that had to be + * duplicated here for flexible usage + */ + private static void renderLeashPiece( + VertexConsumer buffer, + Matrix4f positionMatrix, + float xDif, + float yDif, + float zDif, + int entityBlockLight, + int holderBlockLight, + int entitySkyLight, + int holderSkyLight, + float width, + float yOffset, + float xOffset, + float zOffset, + int segment, + boolean isLeashKnot + ) { + var piecePosPercent = segment / 24f; + var lerpBlockLight = (int) Mth.lerp(piecePosPercent, entityBlockLight, holderBlockLight); + var lerpSkyLight = (int) Mth.lerp(piecePosPercent, entitySkyLight, holderSkyLight); + var packedLight = LightTexture.pack(lerpBlockLight, lerpSkyLight); + var knotColourMod = segment % 2 == (isLeashKnot ? 1 : 0) ? 0.7f : 1f; + var red = 0.5f * knotColourMod; + var green = 0.4f * knotColourMod; + var blue = 0.3f * knotColourMod; + var x = xDif * piecePosPercent; + var y = yDif > 0.0f + ? yDif * piecePosPercent * piecePosPercent + : yDif - yDif * (1.0f - piecePosPercent) * (1.0f - piecePosPercent); + var z = zDif * piecePosPercent; + + buffer.addVertex(positionMatrix, x - xOffset, y + yOffset, z + zOffset) + .setColor(red, green, blue, 1) + .setLight(packedLight); + buffer.addVertex(positionMatrix, x + xOffset, y + width - yOffset, z - zOffset) + .setColor(red, green, blue, 1) + .setLight(packedLight); + } + + private RenderLeashUtil() { + throw new UnsupportedOperationException(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java new file mode 100644 index 000000000..aead41f11 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -0,0 +1,481 @@ +package mod.azure.azurelib.core2.render.pipeline.impl; + +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import mod.azure.azurelib.core2.render.entity.RenderLeashUtil; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.LivingEntityRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.Pose; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4f; + +public class AzEntityRendererPipeline extends AzRendererPipeline { + + private final AzEntityRenderer azEntityRenderer; + + protected Matrix4f entityRenderTranslations = new Matrix4f(); + protected Matrix4f modelRenderTranslations = new Matrix4f(); + + public AzEntityRendererPipeline(AzEntityRenderer azEntityRenderer) { + this.azEntityRenderer = azEntityRenderer; + } + + @Override + protected @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { + return azEntityRenderer.getTextureLocation(animatable); + } + + @Override + public RenderType getDefaultRenderType(T animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityCutoutNoCull(texture); + } + + /** + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
    + * This should only be called immediately prior to rendering, and only + * + * @see AnimatableTexture#setAndUpdate(ResourceLocation, int) + */ + @Override + public void updateAnimatedTextureFrame(T entity) { + AnimatableTexture.setAndUpdate( + getTextureLocation(entity), + entity.getId() + entity.tickCount + ); + } + + /** + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
    + * {@link PoseStack} translations made here are kept until the end of the render process + */ + @Override + public void preRender( + PoseStack poseStack, + T animatable, + AzBakedModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { + this.entityRenderTranslations = new Matrix4f(poseStack.last().pose()); + + scaleModelForRender( + this.azEntityRenderer.getScaleWidth(), + this.azEntityRenderer.getScaleHeight(), + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay + ); + } + + /** + * The actual render method that subtype renderers should override to handle their specific rendering tasks.
    + * {@link AzEntityRendererPipeline#preRender} has already been called by this stage, and {@link AzEntityRendererPipeline#postRender} will be + * called directly after + */ + @Override + public void actuallyRender( + PoseStack poseStack, + T animatable, + AzBakedModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { + poseStack.pushPose(); + + LivingEntity livingEntity = animatable instanceof LivingEntity entity ? entity : null; + + boolean shouldSit = animatable.isPassenger() && (animatable.getVehicle() != null); + float lerpBodyRot = livingEntity == null + ? 0 + : Mth.rotLerp( + partialTick, + livingEntity.yBodyRotO, + livingEntity.yBodyRot + ); + float lerpHeadRot = livingEntity == null + ? 0 + : Mth.rotLerp( + partialTick, + livingEntity.yHeadRotO, + livingEntity.yHeadRot + ); + float netHeadYaw = lerpHeadRot - lerpBodyRot; + + if (shouldSit && animatable.getVehicle() instanceof LivingEntity livingentity) { + lerpBodyRot = Mth.rotLerp(partialTick, livingentity.yBodyRotO, livingentity.yBodyRot); + netHeadYaw = lerpHeadRot - lerpBodyRot; + float clampedHeadYaw = Mth.clamp(Mth.wrapDegrees(netHeadYaw), -85, 85); + lerpBodyRot = lerpHeadRot - clampedHeadYaw; + + if (clampedHeadYaw * clampedHeadYaw > 2500f) + lerpBodyRot += clampedHeadYaw * 0.2f; + + netHeadYaw = lerpHeadRot - lerpBodyRot; + } + + if (animatable.getPose() == Pose.SLEEPING && livingEntity != null) { + Direction bedDirection = livingEntity.getBedOrientation(); + + if (bedDirection != null) { + float eyePosOffset = livingEntity.getEyeHeight(Pose.STANDING) - 0.1F; + + poseStack.translate( + -bedDirection.getStepX() * eyePosOffset, + 0, + -bedDirection.getStepZ() * eyePosOffset + ); + } + } + + float nativeScale = livingEntity != null ? livingEntity.getScale() : 1; + float ageInTicks = animatable.tickCount + partialTick; + float limbSwingAmount = 0; + float limbSwing = 0; + + poseStack.scale(nativeScale, nativeScale, nativeScale); + applyRotations(animatable, poseStack, ageInTicks, lerpBodyRot, partialTick, nativeScale); + + if (!shouldSit && animatable.isAlive() && livingEntity != null) { + limbSwingAmount = Mth.lerp( + partialTick, + livingEntity.walkAnimation.speedOld, + livingEntity.walkAnimation.speed() + ); + limbSwing = livingEntity.walkAnimation.position() - livingEntity.walkAnimation.speed() * (1 - partialTick); + + if (livingEntity.isBaby()) + limbSwing *= 3f; + + if (limbSwingAmount > 1f) + limbSwingAmount = 1f; + } + + if (!isReRender) { + // FIXME: + float headPitch = Mth.lerp(partialTick, animatable.xRotO, animatable.getXRot()); + var velocity = animatable.getDeltaMovement(); + float avgVelocity = (float) (Math.abs(velocity.x) + Math.abs(velocity.z) / 2f); + +// float motionThreshold = getMotionAnimThreshold(animatable); +// AnimationState animationState = new AnimationState( +// animatable, +// limbSwing, +// limbSwingAmount, +// partialTick, +// avgVelocity >= motionThreshold && limbSwingAmount != 0 +// ); +// +// long instanceId = getInstanceId(animatable); +// +// animationState.setData(DataTickets.TICK, animatable.getTick(animatable)); +// animationState.setData(DataTickets.ENTITY, animatable); +// animationState.setData( +// DataTickets.ENTITY_MODEL_DATA, +// new EntityModelData( +// shouldSit, +// livingEntity != null && livingEntity.isBaby(), +// -netHeadYaw, +// -headPitch +// ) +// ); + + // FIXME: +// this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); +// this.model.handleAnimations(animatable, instanceId, animationState); +// runAnimations(animatable, animationState); + + var geoAnimationProvider = azEntityRenderer.getAnimator(); + geoAnimationProvider.runAnimations(animatable); + } + + this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); + + if (!animatable.isInvisibleTo(Minecraft.getInstance().player)) { + AzEntityRendererPipeline.super.actuallyRender( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour + ); + } + + poseStack.popPose(); + } + + /** + * Render the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer + */ + @Override + public void applyRenderLayers( + PoseStack poseStack, + T animatable, + AzBakedModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) { + if (!animatable.isSpectator()) { + AzEntityRendererPipeline.super.applyRenderLayers( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); + } + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + @Override + public void renderRecursively( + PoseStack poseStack, + T entity, + AzBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { + poseStack.pushPose(); + RenderUtils.translateMatrixToBone(poseStack, bone); + RenderUtils.translateToPivotPoint(poseStack, bone); + RenderUtils.rotateMatrixAroundBone(poseStack, bone); + RenderUtils.scaleMatrixForBone(poseStack, bone); + + if (bone.isTrackingMatrices()) { + Matrix4f poseState = new Matrix4f(poseStack.last().pose()); + Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices(poseState, this.entityRenderTranslations); + + bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); + bone.setLocalSpaceMatrix( + RenderUtils.translateMatrix(localMatrix, azEntityRenderer.getRenderOffset(entity, 1).toVector3f()) + ); + bone.setWorldSpaceMatrix( + RenderUtils.translateMatrix(new Matrix4f(localMatrix), entity.position().toVector3f()) + ); + } + + RenderUtils.translateAwayFromPivotPoint(poseStack, bone); + + if (!isReRender && buffer instanceof BufferBuilder builder && !builder.building) + buffer = bufferSource.getBuffer(renderType); + + renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); + + if (!isReRender) + applyRenderLayersForBone( + poseStack, + entity, + bone, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); + + renderChildBones( + poseStack, + entity, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour + ); + + poseStack.popPose(); + } + + @Override + public void renderFinal(PoseStack poseStack, T entity, AzBakedModel model, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay, int colour) { + azEntityRenderer.render(entity, 0, partialTick, poseStack, bufferSource, packedLight); + + if (entity instanceof Mob mob) { + var leashHolder = mob.getLeashHolder(); + + if (leashHolder != null) { + RenderLeashUtil.renderLeash(azEntityRenderer, mob, partialTick, poseStack, bufferSource, leashHolder); + } + } + } + + /** + * Create and fire the relevant {@code CompileLayers} event hook for this renderer + */ + @Override + public void fireCompileRenderLayersEvent() { + // FIXME: +// Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireCompileEntityRenderLayers(geoEntityRenderer); + } + + /** + * Create and fire the relevant {@code Pre-Render} event hook for this renderer.
    + * + * @return Whether the renderer should proceed based on the cancellation state of the event + */ + @Override + public boolean firePreRenderEvent( + PoseStack poseStack, + AzBakedModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + // FIXME: + return true; +// return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPreRender(geoEntityRenderer, poseStack, model, bufferSource, partialTick, packedLight); + } + + /** + * Create and fire the relevant {@code Post-Render} event hook for this renderer + */ + @Override + public void firePostRenderEvent( + PoseStack poseStack, + AzBakedModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + // FIXME: +// Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPostRender(geoEntityRenderer, poseStack, model, bufferSource, partialTick, packedLight); + } + + /** + * Applies rotation transformations to the renderer prior to render time to account for various entity states, default scale of 1 + */ + protected void applyRotations( + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick + ) { + applyRotations(animatable, poseStack, ageInTicks, rotationYaw, partialTick, 1); + } + + /** + * Applies rotation transformations to the renderer prior to render time to account for various entity states, scalable + */ + protected void applyRotations(T animatable, PoseStack poseStack, float ageInTicks, float rotationYaw, + float partialTick, float nativeScale) { + if (isShaking(animatable)) + rotationYaw += (float)(Math.cos(animatable.tickCount * 3.25d) * Math.PI * 0.4d); + + if (!animatable.hasPose(Pose.SLEEPING)) + poseStack.mulPose(Axis.YP.rotationDegrees(180f - rotationYaw)); + + if (animatable instanceof LivingEntity livingEntity) { + if (livingEntity.deathTime > 0) { + float deathRotation = (livingEntity.deathTime + partialTick - 1f) / 20f * 1.6f; + + poseStack.mulPose(Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable))); + } + else if (livingEntity.isAutoSpinAttack()) { + poseStack.mulPose(Axis.XP.rotationDegrees(-90f - livingEntity.getXRot())); + poseStack.mulPose(Axis.YP.rotationDegrees((livingEntity.tickCount + partialTick) * -75f)); + } + else if (animatable.hasPose(Pose.SLEEPING)) { + Direction bedOrientation = livingEntity.getBedOrientation(); + + poseStack.mulPose(Axis.YP.rotationDegrees(bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw)); + poseStack.mulPose(Axis.ZP.rotationDegrees(getDeathMaxRotation(animatable))); + poseStack.mulPose(Axis.YP.rotationDegrees(270f)); + } + else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { + poseStack.translate(0, (animatable.getBbHeight() + 0.1f) / nativeScale, 0); + poseStack.mulPose(Axis.ZP.rotationDegrees(180f)); + } + } + } + + /** + * Gets the max rotation value for dying entities.
    + * You might want to modify this for different aesthetics, such as a + * {@link net.minecraft.world.entity.monster.Spider} flipping upside down on death.
    + * Functionally equivalent to {@link net.minecraft.client.renderer.entity.LivingEntityRenderer#getFlipDegrees} + */ + protected float getDeathMaxRotation(T entity) { + return 90f; + } + + public boolean isShaking(T entity) { + return entity.isFullyFrozen(); + } + + /** + * Gets a packed overlay coordinate pair for rendering.
    + * Mostly just used for the red tint when an entity is hurt, but can be used for other things like the + * {@link net.minecraft.world.entity.monster.Creeper} white tint when exploding. + */ + @Override + public int getPackedOverlay(T entity, float u, float partialTick) { + if (!(entity instanceof LivingEntity livingEntity)) { + return OverlayTexture.NO_OVERLAY; + } + + return OverlayTexture.pack(OverlayTexture.u(u), OverlayTexture.v(livingEntity.hurtTime > 0 || livingEntity.deathTime > 0)); + } +} From a85104e11e255f294e14368798224a0bd91c93e1 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Tue, 3 Dec 2024 00:17:40 -0500 Subject: [PATCH 010/224] Added VertexSet.java. Signed-off-by: = --- .../model/factory/primitive/VertexSet.java | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/model/factory/primitive/VertexSet.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/primitive/VertexSet.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/primitive/VertexSet.java new file mode 100644 index 000000000..ed18f4e4c --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/primitive/VertexSet.java @@ -0,0 +1,120 @@ +package mod.azure.azurelib.core2.model.factory.primitive; + +import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; +import net.minecraft.core.Direction; +import net.minecraft.world.phys.Vec3; + +/** + * Holder class to make it easier to store and refer to vertices for a given cube + */ +public record VertexSet( + GeoVertex bottomLeftBack, + GeoVertex bottomRightBack, + GeoVertex topLeftBack, + GeoVertex topRightBack, + GeoVertex topLeftFront, + GeoVertex topRightFront, + GeoVertex bottomLeftFront, + GeoVertex bottomRightFront +) { + + public VertexSet(Vec3 origin, Vec3 vertexSize, double inflation) { + this( + new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z - inflation), + new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z + vertexSize.z + inflation), + new GeoVertex(origin.x - inflation, origin.y + vertexSize.y + inflation, origin.z - inflation), + new GeoVertex( + origin.x - inflation, + origin.y + vertexSize.y + inflation, + origin.z + vertexSize.z + inflation + ), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y + vertexSize.y + inflation, + origin.z - inflation + ), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y + vertexSize.y + inflation, + origin.z + vertexSize.z + inflation + ), + new GeoVertex(origin.x + vertexSize.x + inflation, origin.y - inflation, origin.z - inflation), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y - inflation, + origin.z + vertexSize.z + inflation + ) + ); + } + + /** + * Returns the normal vertex array for a west-facing quad + */ + public GeoVertex[] quadWest() { + return new GeoVertex[]{ this.topRightBack, this.topLeftBack, this.bottomLeftBack, this.bottomRightBack }; + } + + /** + * Returns the normal vertex array for an east-facing quad + */ + public GeoVertex[] quadEast() { + return new GeoVertex[] { + this.topLeftFront, + this.topRightFront, + this.bottomRightFront, + this.bottomLeftFront + }; + } + + /** + * Returns the normal vertex array for a north-facing quad + */ + public GeoVertex[] quadNorth() { + return new GeoVertex[]{ this.topLeftBack, this.topLeftFront, this.bottomLeftFront, this.bottomLeftBack }; + } + + /** + * Returns the normal vertex array for a south-facing quad + */ + public GeoVertex[] quadSouth() { + return new GeoVertex[] { + this.topRightFront, + this.topRightBack, + this.bottomRightBack, + this.bottomRightFront + }; + } + + /** + * Returns the normal vertex array for a top-facing quad + */ + public GeoVertex[] quadUp() { + return new GeoVertex[]{ this.topRightBack, this.topRightFront, this.topLeftFront, this.topLeftBack }; + } + + /** + * Returns the normal vertex array for a bottom-facing quad + */ + public GeoVertex[] quadDown() { + return new GeoVertex[] { + this.bottomLeftBack, + this.bottomLeftFront, + this.bottomRightFront, + this.bottomRightBack + }; + } + + /** + * Return the vertex array relevant to the quad being built, taking into account mirroring and quad type + */ + public GeoVertex[] verticesForQuad(Direction direction, boolean boxUv, boolean mirror) { + return switch (direction) { + case WEST -> mirror ? quadEast() : quadWest(); + case EAST -> mirror ? quadWest() : quadEast(); + case NORTH -> quadNorth(); + case SOUTH -> quadSouth(); + case UP -> mirror && !boxUv ? quadDown() : quadUp(); + case DOWN -> mirror && !boxUv ? quadUp() : quadDown(); + }; + } +} \ No newline at end of file From 61ea4c93aedd5fa245c0328e00d58595e91532c6 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Tue, 3 Dec 2024 04:03:32 -0500 Subject: [PATCH 011/224] Committing progress. Signed-off-by: = --- .../internal/common/loading/FileLoader.java | 14 + .../azurelib/core/animation/Animation.java | 2 +- .../core/animation/AnimationController.java | 8 + .../azurelib/core/animation/RawAnimation.java | 2 +- .../event/CustomInstructionKeyframeEvent.java | 2 + .../core/keyframe/event/KeyFrameEvent.java | 2 + .../keyframe/event/ParticleKeyframeEvent.java | 2 + .../keyframe/event/SoundKeyframeEvent.java | 2 + .../core2/animation/AzAnimationProcessor.java | 300 +++++++ .../core2/animation/AzAnimationState.java | 193 +++++ .../azurelib/core2/animation/AzAnimator.java | 179 ++++ .../cache/AzBakedAnimationCache.java | 8 +- .../animation/cache/AzBoneSnapshotCache.java | 27 + .../controller/AzAnimationController.java | 819 ++++++++++++++++++ .../AzAnimationControllerContainer.java | 28 + .../AzAnimationControllerState.java | 8 + .../handler/AzAnimationStateHandler.java | 34 + .../handler/AzCustomKeyframeHandler.java | 14 + .../handler/AzParticleKeyframeHandler.java | 14 + .../handler/AzSoundKeyframeHandler.java | 14 + .../AzCustomInstructionKeyframeEvent.java | 28 + .../animation/event/AzKeyFrameEvent.java | 60 ++ .../event/AzParticleKeyframeEvent.java | 36 + .../animation/event/AzSoundKeyframeEvent.java | 36 + .../animation/impl/AzEntityAnimator.java | 71 ++ .../animation/primitive/AzAnimation.java | 32 + .../primitive/AzBakedAnimations.java | 25 + .../animation/primitive/AzKeyframes.java | 11 + .../core2/animation/primitive/AzLoopType.java | 95 ++ .../primitive/AzQueuedAnimation.java | 9 + .../animation/primitive/AzRawAnimation.java | 149 ++++ .../core2/animation/primitive/AzStage.java | 38 + .../core2/render/entity/AzEntityRenderer.java | 11 +- .../impl/AzEntityRendererPipeline.java | 35 +- 34 files changed, 2276 insertions(+), 32 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerContainer.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzCustomKeyframeHandler.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzParticleKeyframeHandler.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzSoundKeyframeHandler.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/event/AzKeyFrameEvent.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimations.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzKeyframes.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzQueuedAnimation.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzRawAnimation.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzStage.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java index 7d4b63346..2d85017a6 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java @@ -15,6 +15,8 @@ import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; import mod.azure.azurelib.common.internal.common.util.JsonUtil; import mod.azure.azurelib.core.animation.Animation; +import mod.azure.azurelib.core2.animation.primitive.AzAnimation; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.util.GsonHelper; @@ -37,11 +39,23 @@ private FileLoader() { * * @param location The resource path of the animations file * @param manager The Minecraft {@code ResourceManager} responsible for maintaining in-memory resource access + * + * @deprecated */ public static BakedAnimations loadAnimationsFile(ResourceLocation location, ResourceManager manager) { return JsonUtil.GEO_GSON.fromJson(loadFile(location, manager), BakedAnimations.class); } + /** + * Load up and deserialize an animation json file to its respective {@link AzAnimation} components + * + * @param location The resource path of the animations file + * @param manager The Minecraft {@code ResourceManager} responsible for maintaining in-memory resource access + */ + public static AzBakedAnimations loadAzAnimationsFile(ResourceLocation location, ResourceManager manager) { + return JsonUtil.GEO_GSON.fromJson(loadFile(location, manager), AzBakedAnimations.class); + } + /** * Load up and deserialize a geo model json file to its respective {@link BakedGeoModel} format * diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java index 4385e9da7..ca22625a9 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java @@ -33,7 +33,7 @@ public record Animation( Keyframes keyFrames ) { - static Animation generateWaitAnimation(double length) { + public static Animation generateWaitAnimation(double length) { return new Animation( RawAnimation.Stage.WAIT, length, diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java index 8f1dd40cf..fd70a6aec 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java @@ -197,6 +197,10 @@ public AnimationController setAnimationSpeedHandler(ToDoubleFunction speed return this; } + public void setJustStarting(boolean justStarting) { + isJustStarting = justStarting; + } + /** * Sets the controller's {@link EasingType} override for animations.
    * By default, the controller will use whatever {@code EasingType} was defined in the animation json @@ -208,6 +212,10 @@ public AnimationController setOverrideEasingType(EasingType easingTypeFunctio return setOverrideEasingTypeFunction(obj -> easingTypeFunction); } + public Function getOverrideEasingTypeFunction() { + return overrideEasingTypeFunction; + } + /** * Sets the controller's {@link EasingType} override function for animations.
    * By default, the controller will use whatever {@code EasingType} was defined in the animation json diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java index e46f8762d..c571cdff6 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java @@ -162,7 +162,7 @@ public record Stage( int additionalTicks ) { - static final String WAIT = "internal.wait"; + public static final String WAIT = "internal.wait"; public Stage(String animationName, Animation.LoopType loopType) { this(animationName, loopType, 0); diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java index ab024e7cb..5107bd073 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java @@ -14,6 +14,8 @@ /** * The {@link KeyFrameEvent} specific to the {@link AnimationController#customKeyframeHandler}.
    * Called when a custom instruction keyframe is encountered + * + * @deprecated */ public class CustomInstructionKeyframeEvent extends KeyFrameEvent { diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java index 8f8002a42..f65aed61c 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java @@ -19,6 +19,8 @@ * @see CustomInstructionKeyframeEvent * @see ParticleKeyframeEvent * @see SoundKeyframeEvent + * + * @deprecated */ public abstract class KeyFrameEvent { diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java index 08aade003..520753668 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java @@ -14,6 +14,8 @@ /** * The {@link KeyFrameEvent} specific to the {@link AnimationController#particleKeyframeHandler}.
    * Called when a particle instruction keyframe is encountered + * + * @deprecated */ public class ParticleKeyframeEvent extends KeyFrameEvent { diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java index 01ecf9758..efd790cba 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java @@ -14,6 +14,8 @@ /** * The {@link KeyFrameEvent} specific to the {@link AnimationController#soundKeyframeHandler}.
    * Called when a sound instruction keyframe is encountered + * + * @deprecated */ public class SoundKeyframeEvent extends KeyFrameEvent { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java new file mode 100644 index 000000000..feffd23ea --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -0,0 +1,300 @@ +package mod.azure.azurelib.core2.animation; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.animation.EasingType; +import mod.azure.azurelib.core.state.BoneSnapshot; +import mod.azure.azurelib.core.utils.Interpolations; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.primitive.AzAnimation; +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; +import mod.azure.azurelib.core2.animation.primitive.AzStage; +import mod.azure.azurelib.core2.model.AzBakedModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +public class AzAnimationProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(AzAnimationProcessor.class); + + private final AzAnimator animator; + private final Map bonesByName; + + public boolean reloadAnimations; + + public AzAnimationProcessor(AzAnimator animator) { + this.animator = animator; + this.bonesByName = new Object2ObjectOpenHashMap<>(); + this.reloadAnimations = false; + } + + /** + * Build an animation queue for the given {@link AzRawAnimation} + * + * @param animatable The animatable object being rendered + * @param rawAnimation The raw animation to be compiled + * @return A queue of animations and loop types to play + */ + public Queue buildAnimationQueue(T animatable, AzRawAnimation rawAnimation) { + var animations = new LinkedList(); + + for (var stage : rawAnimation.getAnimationStages()) { + AzAnimation animation; + + if (Objects.equals(stage.animationName(), AzStage.WAIT)) { + animation = AzAnimation.generateWaitAnimation(stage.additionalTicks()); + } else { + animation = animator.getAnimation(animatable, stage.animationName()); + } + + if (animation == null) { + LOGGER.warn( + "Unable to find animation: {} for {}", + stage.animationName(), + animatable.getClass().getSimpleName() + ); + return null; + } else { + animations.add(new AzQueuedAnimation(animation, stage.loopType())); + } + } + + return animations; + } + + /** + * Tick and apply transformations to the model based on the current state of the {@link AzAnimationController} + * + * @param animatable The animatable object relevant to the animation being played + */ + public void tickAnimation(T animatable, AzAnimationState event) { + var animTime = animator.getAnimTime(); + var boneSnapshotCollection = animator.getBoneSnapshotCache().getAll(); + // TODO: This mutates the bone snapshot cache in a way that is... well, terrible. find another way! + var boneSnapshots = updateBoneSnapshots(boneSnapshotCollection); + + for (var controller : animator.getAnimationControllerContainer().getAll()) { + if (this.reloadAnimations) { + controller.forceAnimationReset(); + controller.getBoneAnimationQueues().clear(); + } + + controller.setJustStarting(animator.isFirstTick()); + + event.withController(controller); + controller.process(event, this.bonesByName, boneSnapshots, animTime, animator.crashIfBoneMissing()); + + for (var boneAnimation : controller.getBoneAnimationQueues().values()) { + var bone = boneAnimation.bone(); + var snapshot = boneSnapshots.get(bone.getName()); + var initialSnapshot = bone.getInitialSnapshot(); + + var rotXPoint = boneAnimation.rotationXQueue().poll(); + var rotYPoint = boneAnimation.rotationYQueue().poll(); + var rotZPoint = boneAnimation.rotationZQueue().poll(); + var posXPoint = boneAnimation.positionXQueue().poll(); + var posYPoint = boneAnimation.positionYQueue().poll(); + var posZPoint = boneAnimation.positionZQueue().poll(); + var scaleXPoint = boneAnimation.scaleXQueue().poll(); + var scaleYPoint = boneAnimation.scaleYQueue().poll(); + var scaleZPoint = boneAnimation.scaleZQueue().poll(); + var easingType = controller.getOverrideEasingTypeFunction().apply(animatable); + + if (rotXPoint != null && rotYPoint != null && rotZPoint != null) { + bone.setRotX( + (float) EasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() + ); + bone.setRotY( + (float) EasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() + ); + bone.setRotZ( + (float) EasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() + ); + snapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); + snapshot.startRotAnim(); + bone.markRotationAsChanged(); + } + + if (posXPoint != null && posYPoint != null && posZPoint != null) { + bone.setPosX((float) EasingType.lerpWithOverride(posXPoint, easingType)); + bone.setPosY((float) EasingType.lerpWithOverride(posYPoint, easingType)); + bone.setPosZ((float) EasingType.lerpWithOverride(posZPoint, easingType)); + snapshot.updateOffset(bone.getPosX(), bone.getPosY(), bone.getPosZ()); + snapshot.startPosAnim(); + bone.markPositionAsChanged(); + } + + if (scaleXPoint != null && scaleYPoint != null && scaleZPoint != null) { + bone.setScaleX((float) EasingType.lerpWithOverride(scaleXPoint, easingType)); + bone.setScaleY((float) EasingType.lerpWithOverride(scaleYPoint, easingType)); + bone.setScaleZ((float) EasingType.lerpWithOverride(scaleZPoint, easingType)); + snapshot.updateScale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); + snapshot.startScaleAnim(); + bone.markScaleAsChanged(); + } + } + } + + this.reloadAnimations = false; + double resetTickLength = animator.getBoneResetTime(); + + for (var bone : getRegisteredBones()) { + if (!bone.hasRotationChanged()) { + var initialSnapshot = bone.getInitialSnapshot(); + var saveSnapshot = boneSnapshots.get(bone.getName()); + + if (saveSnapshot.isRotAnimInProgress()) + saveSnapshot.stopRotAnim(animTime); + + double percentageReset = Math.min( + (animTime - saveSnapshot.getLastResetRotationTick()) / resetTickLength, + 1 + ); + + bone.setRotX( + (float) Interpolations.lerp(saveSnapshot.getRotX(), initialSnapshot.getRotX(), percentageReset) + ); + bone.setRotY( + (float) Interpolations.lerp(saveSnapshot.getRotY(), initialSnapshot.getRotY(), percentageReset) + ); + bone.setRotZ( + (float) Interpolations.lerp(saveSnapshot.getRotZ(), initialSnapshot.getRotZ(), percentageReset) + ); + + if (percentageReset >= 1) { + saveSnapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); + } + } + + if (!bone.hasPositionChanged()) { + var initialSnapshot = bone.getInitialSnapshot(); + var saveSnapshot = boneSnapshots.get(bone.getName()); + + if (saveSnapshot.isPosAnimInProgress()) { + saveSnapshot.stopPosAnim(animTime); + } + + var percentageReset = Math.min((animTime - saveSnapshot.getLastResetPositionTick()) / resetTickLength, 1); + + bone.setPosX( + (float) Interpolations.lerp( + saveSnapshot.getOffsetX(), + initialSnapshot.getOffsetX(), + percentageReset + ) + ); + bone.setPosY( + (float) Interpolations.lerp( + saveSnapshot.getOffsetY(), + initialSnapshot.getOffsetY(), + percentageReset + ) + ); + bone.setPosZ( + (float) Interpolations.lerp( + saveSnapshot.getOffsetZ(), + initialSnapshot.getOffsetZ(), + percentageReset + ) + ); + + if (percentageReset >= 1) { + saveSnapshot.updateOffset(bone.getPosX(), bone.getPosY(), bone.getPosZ()); + } + } + + if (!bone.hasScaleChanged()) { + var initialSnapshot = bone.getInitialSnapshot(); + var saveSnapshot = boneSnapshots.get(bone.getName()); + + if (saveSnapshot.isScaleAnimInProgress()) { + saveSnapshot.stopScaleAnim(animTime); + } + + double percentageReset = Math.min((animTime - saveSnapshot.getLastResetScaleTick()) / resetTickLength, 1); + + bone.setScaleX( + (float) Interpolations.lerp(saveSnapshot.getScaleX(), initialSnapshot.getScaleX(), percentageReset) + ); + bone.setScaleY( + (float) Interpolations.lerp(saveSnapshot.getScaleY(), initialSnapshot.getScaleY(), percentageReset) + ); + bone.setScaleZ( + (float) Interpolations.lerp(saveSnapshot.getScaleZ(), initialSnapshot.getScaleZ(), percentageReset) + ); + + if (percentageReset >= 1) { + saveSnapshot.updateScale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); + } + } + } + + resetBoneTransformationMarkers(); + animator.finishFirstTick(); + } + + /** + * Reset the transformation markers applied to each {@link CoreGeoBone} ready for the next render frame + */ + private void resetBoneTransformationMarkers() { + getRegisteredBones().forEach(CoreGeoBone::resetStateChanges); + } + + /** + * Create new bone {@link BoneSnapshot} based on the bone's initial snapshot for the currently registered + * {@link CoreGeoBone GeoBones}, filtered by the bones already present in the master snapshots map + * + * @param snapshots The master bone snapshots map. + * @return The input snapshots map, for easy assignment + */ + private Map updateBoneSnapshots(Map snapshots) { + for (var bone : getRegisteredBones()) { + if (!snapshots.containsKey(bone.getName())) { + snapshots.put(bone.getName(), BoneSnapshot.copy(bone.getInitialSnapshot())); + } + } + + return snapshots; + } + + /** + * Gets a bone by name. + * + * @param boneName The bone name + * @return the bone + */ + public CoreGeoBone getBone(String boneName) { + return this.bonesByName.get(boneName); + } + + /** + * Adds the given bone to the bones list for this processor.
    + * This is normally handled automatically by AzureLib.
    + * Failure to properly register a bone will break things. + */ + public void registerGeoBone(CoreGeoBone bone) { + bone.saveInitialSnapshot(); + this.bonesByName.put(bone.getName(), bone); + bone.getChildBones().forEach(this::registerGeoBone); + } + + /** + * Clear the {@link CoreGeoBone GeoBones} currently registered to the processor, then prepares the processor for a + * new model.
    + * Should be called whenever switching models to render/animate + */ + public void setActiveModel(AzBakedModel model) { + this.bonesByName.clear(); + model.getTopLevelBones().forEach(this::registerGeoBone); + } + + /** + * Get an iterable collection of the {@link CoreGeoBone GeoBones} currently registered to the processor + */ + public Collection getRegisteredBones() { + return this.bonesByName.values(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java new file mode 100644 index 000000000..749861c6d --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java @@ -0,0 +1,193 @@ +package mod.azure.azurelib.core2.animation; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mod.azure.azurelib.core.object.DataTicket; +import mod.azure.azurelib.core.object.PlayState; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; + +import java.util.Map; +import java.util.Objects; + +/** + * Animation state handler for end-users.
    + * This is where users would set their selected animation to play, stop the controller, or any number of other + * animation-related actions. + */ +public class AzAnimationState { + + private final T animatable; + + private final float limbSwing; + + private final float limbSwingAmount; + + private final float partialTick; + + private final boolean isMoving; + + private final Map, Object> extraData = new Object2ObjectOpenHashMap<>(); + public double animationTick; + protected AzAnimationController controller; + + public AzAnimationState(T animatable, float limbSwing, float limbSwingAmount, float partialTick, boolean isMoving) { + this.animatable = animatable; + this.limbSwing = limbSwing; + this.limbSwingAmount = limbSwingAmount; + this.partialTick = partialTick; + this.isMoving = isMoving; + } + + /** + * Gets the amount of ticks that have passed in either the current transition or animation, depending on the + * controller's AnimationState. + */ + public double getAnimationTick() { + return this.animationTick; + } + + /** + * Gets the current {@link T animatable} being rendered + */ + public T getAnimatable() { + return this.animatable; + } + + public float getLimbSwing() { + return this.limbSwing; + } + + public float getLimbSwingAmount() { + return this.limbSwingAmount; + } + + /** + * Gets the fractional value of the current game tick that has passed in rendering + */ + public float getPartialTick() { + return this.partialTick; + } + + /** + * Gets whether the current {@link T animatable} is considered to be moving for animation purposes.
    + * Note that this is a best-case approximation of movement, and your needs may vary. + */ + public boolean isMoving() { + return this.isMoving; + } + + /** + * Gets the current {@link AzAnimationController} responsible for the current animation + */ + public AzAnimationController getController() { + return this.controller; + } + + /** + * Sets the {@code AnimationEvent}'s current {@link AzAnimationController} + */ + public AzAnimationState withController(AzAnimationController controller) { + this.controller = controller; + + return this; + } + + /** + * Gets the optional additional data map for the event.
    + * + * @see DataTicket + */ + public Map, ?> getExtraData() { + return this.extraData; + } + + /** + * Get a data value saved to this animation event by the ticket for that data.
    + * + * @param dataTicket The {@link DataTicket} for the data to retrieve + * @return The cached data for the given {@code DataTicket}, or null if not saved + * @see DataTicket + */ + public D getData(DataTicket dataTicket) { + return dataTicket.getData(this.extraData); + } + + /** + * Save a data value for the given {@link DataTicket} in the additional data map + * + * @param dataTicket The {@code DataTicket} for the data value + * @param data The data value + */ + public void setData(DataTicket dataTicket, D data) { + this.extraData.put(dataTicket, data); + } + + /** + * Sets the animation for the controller to start/continue playing.
    + * Basically just a shortcut for + * + *

    +     * getController().setAnimation()
    +     * 
    + * + * @param animation The animation to play + */ + public void setAnimation(AzRawAnimation animation) { + getController().setAnimation(animatable, animation); + } + + /** + * Helper method to set an animation to start/continue playing, and return {@link PlayState#CONTINUE} + */ + public PlayState setAndContinue(AzRawAnimation animation) { + getController().setAnimation(animatable, animation); + + return PlayState.CONTINUE; + } + + /** + * Checks whether the current {@link AzAnimationController}'s last animation was the one provided. This allows for + * multi-stage animation shifting where the next animation to play may depend on the previous one + * + * @param animation The animation to check + * @return Whether the controller's last animation is the one provided + */ + public boolean isCurrentAnimation(AzRawAnimation animation) { + return Objects.equals(getController().getCurrentRawAnimation(), animation); + } + + /** + * Similar to {@link AzAnimationState#isCurrentAnimation}, but additionally checks the current stage of the animation + * by name.
    + * This can be used to check if a multi-stage animation has reached a given stage (if it is running at all)
    + * Note that this will still return true even if the animation has finished, matching with the last animation stage + * in the {@link AzRawAnimation} last provided + * + * @param name The name of the animation stage to check (I.E. "move.walk") + * @return Whether the controller's current stage is the one provided + */ + public boolean isCurrentAnimationStage(String name) { + return getController().getCurrentAnimation() != null && getController().getCurrentAnimation() + .animation() + .name() + .equals(name); + } + + /** + * Helper method for {@link AzAnimationController#forceAnimationReset()}
    + * This should be used in controllers when stopping a non-looping animation, so that it is reset to the start for + * the next time it starts + */ + public void resetCurrentAnimation() { + getController().forceAnimationReset(); + } + + /** + * Helper method for {@link AzAnimationController#setAnimationSpeed} + * + * @param speed The speed modifier for the controller (2 = twice as fast, 0.5 = half as fast, etc) + */ + public void setControllerSpeed(float speed) { + getController().setAnimationSpeed(speed); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java new file mode 100644 index 000000000..4434d934a --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -0,0 +1,179 @@ +package mod.azure.azurelib.core2.animation; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.AzureLibException; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.MolangQueries; +import mod.azure.azurelib.core2.animation.cache.AzBakedAnimationCache; +import mod.azure.azurelib.core2.animation.cache.AzBoneSnapshotCache; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.primitive.AzAnimation; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.LivingEntity; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public abstract class AzAnimator { + + // Remnants from AnimatableManager. + private final AzAnimationControllerContainer animationControllerContainer; + private final AzAnimationProcessor animationProcessor; + private final AzBoneSnapshotCache boneSnapshotCache; + + // Remnants from AnimatableManager. + private double lastUpdateTime; + private boolean isFirstTick = true; + private double firstTickTime = -1; + + // Remnants from GeoModel. + private double animTime; + private double lastGameTickTime; + + protected AzAnimator() { + this.animationControllerContainer = new AzAnimationControllerContainer<>(); + this.animationProcessor = new AzAnimationProcessor<>(this); + this.boneSnapshotCache = new AzBoneSnapshotCache(); + } + + public abstract void registerControllers(AzAnimationControllerContainer animationControllerContainer); + public abstract @NotNull ResourceLocation getAnimationLocation(T animatable); + + public void animate(T animatable, AzAnimationState animationState) { + var minecraft = Minecraft.getInstance(); + var currentTick = animationState.getData(DataTickets.TICK); + + if (currentTick == null) { + // TODO: We need to figure out how to get this instanceof check out of this abstract class. + currentTick = animatable instanceof LivingEntity livingEntity + ? (double) livingEntity.tickCount + : RenderUtils.getCurrentTick(); + } + + if (firstTickTime == -1) { + firstTickTime = currentTick + minecraft.getTimer().getGameTimeDeltaTicks(); + } + + double currentFrameTime = currentTick - firstTickTime; + boolean isReRender = !isFirstTick && currentFrameTime == lastUpdateTime; + + // TODO: Figure out why this was here to begin with. +// if (isReRender && instanceId == this.lastRenderedInstance) { +// return; +// } + + if (!isReRender && (!minecraft.isPaused() || shouldPlayAnimsWhileGamePaused())) { + this.lastUpdateTime = currentFrameTime; + + this.animTime += lastUpdateTime - this.lastGameTickTime; + this.lastGameTickTime = lastUpdateTime; + } + + animationState.animationTick = this.animTime; + + preAnimationSetup(animatable, this.animTime); + + if (!animationProcessor.getRegisteredBones().isEmpty()) { + animationProcessor.tickAnimation(animatable, animationState); + } + + setCustomAnimations(animatable, animationState); + } + + /** + * Apply transformations and settings prior to acting on any animation-related functionality + */ + protected void preAnimationSetup(T animatable, double animTime) { + applyMolangQueries(animatable, animTime); + } + + protected void applyMolangQueries(T animatable, double animTime) { + var parser = MolangParser.INSTANCE; + var minecraft = Minecraft.getInstance(); + // TODO: See if there's a better way to null-check here. + var level = Objects.requireNonNull(minecraft.level); + + parser.setMemoizedValue(MolangQueries.LIFE_TIME, () -> animTime / 20d); + parser.setMemoizedValue(MolangQueries.ACTOR_COUNT, level::getEntityCount); + parser.setMemoizedValue(MolangQueries.TIME_OF_DAY, () -> level.getDayTime() / 24000f); + parser.setMemoizedValue(MolangQueries.MOON_PHASE, level::getMoonPhase); + } + + /** + * This method is called once per render frame for each {@link T animatable} being rendered.
    + * Override to set custom animations (such as head rotation, etc). + * + * @param animatable The {@code GeoAnimatable} instance currently being rendered + * @param animationState An {@link AzAnimationState} instance created to hold animation data for the + * {@code animatable} for this method call + */ + public void setCustomAnimations(T animatable, AzAnimationState animationState) {} + + /** + * Defines whether the animations for this animator should continue playing in the background when the game is + * paused.
    + * By default, animation progress will be stalled while the game is paused. + */ + public boolean shouldPlayAnimsWhileGamePaused() { + return false; + } + + /** + * Override this and return true if AzureLib should crash when attempting to animate the model, but fails to find a + * bone.
    + * By default, AzureLib will just gracefully ignore a missing bone, which might cause oddities with incorrect models + * or mismatching variables.
    + */ + public boolean crashIfBoneMissing() { + return false; + } + + /** + * Get the baked animation object used for rendering from the given resource path + */ + public AzAnimation getAnimation(T animatable, String name) { + var location = getAnimationLocation(animatable); + var bakedAnimations = AzBakedAnimationCache.getInstance().getNullable(location); + + if (bakedAnimations == null) { + throw new AzureLibException(location, "Unable to find animation."); + } + + return bakedAnimations.getAnimation(name); + } + + public AzAnimationControllerContainer getAnimationControllerContainer() { + return animationControllerContainer; + } + + public AzAnimationProcessor getAnimationProcessor() { + return animationProcessor; + } + + public double getAnimTime() { + return animTime; + } + + /** + * Defines the speed in which the {@link AzAnimationProcessor} should return {@link CoreGeoBone GeoBones} that + * currently have no animations to their default position. + */ + public double getBoneResetTime() { + return 1; + } + + public AzBoneSnapshotCache getBoneSnapshotCache() { + return boneSnapshotCache; + } + + public boolean isFirstTick() { + return this.isFirstTick; + } + + protected void finishFirstTick() { + this.isFirstTick = false; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java index 02cb802b9..aaa170058 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java @@ -2,8 +2,8 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import mod.azure.azurelib.common.internal.common.loading.FileLoader; -import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; import mod.azure.azurelib.core2.AzResourceCache; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; import org.jetbrains.annotations.Nullable; @@ -20,7 +20,7 @@ public static AzBakedAnimationCache getInstance() { return INSTANCE; } - private final Map bakedAnimations; + private final Map bakedAnimations; private AzBakedAnimationCache() { this.bakedAnimations = new Object2ObjectOpenHashMap<>(); @@ -31,12 +31,12 @@ public CompletableFuture loadAnimations(Executor backgroundExecutor, Resou backgroundExecutor, resourceManager, "animations", - resource -> FileLoader.loadAnimationsFile(resource, resourceManager), + resource -> FileLoader.loadAzAnimationsFile(resource, resourceManager), bakedAnimations::put ); } - public @Nullable BakedAnimations getNullable(ResourceLocation resourceLocation) { + public @Nullable AzBakedAnimations getNullable(ResourceLocation resourceLocation) { return bakedAnimations.get(resourceLocation); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java new file mode 100644 index 000000000..9eb553f3a --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java @@ -0,0 +1,27 @@ +package mod.azure.azurelib.core2.animation.cache; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mod.azure.azurelib.core.state.BoneSnapshot; + +import java.util.Map; + +public class AzBoneSnapshotCache { + + private final Map boneSnapshotsByName; + + public AzBoneSnapshotCache() { + this.boneSnapshotsByName = new Object2ObjectOpenHashMap<>(); + } + + public Map getBoneByName(String name) { + return boneSnapshotsByName; + } + + public void clear() { + this.boneSnapshotsByName.clear(); + } + + public Map getAll() { + return boneSnapshotsByName; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java new file mode 100644 index 000000000..5926993dd --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -0,0 +1,819 @@ +package mod.azure.azurelib.core2.animation.controller; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.animation.EasingType; +import mod.azure.azurelib.core.keyframe.AnimationPoint; +import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.keyframe.KeyframeLocation; +import mod.azure.azurelib.core.keyframe.event.data.KeyFrameData; +import mod.azure.azurelib.core.math.Constant; +import mod.azure.azurelib.core.math.IValue; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.MolangQueries; +import mod.azure.azurelib.core.object.Axis; +import mod.azure.azurelib.core.object.PlayState; +import mod.azure.azurelib.core.state.BoneSnapshot; +import mod.azure.azurelib.core2.animation.AzAnimationProcessor; +import mod.azure.azurelib.core2.animation.AzAnimationState; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; +import mod.azure.azurelib.core2.animation.controller.handler.AzAnimationStateHandler; +import mod.azure.azurelib.core2.animation.controller.handler.AzCustomKeyframeHandler; +import mod.azure.azurelib.core2.animation.controller.handler.AzParticleKeyframeHandler; +import mod.azure.azurelib.core2.animation.controller.handler.AzSoundKeyframeHandler; +import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; +import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; +import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; +import mod.azure.azurelib.core2.animation.primitive.AzAnimation; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.Set; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; + +/** + * The actual controller that handles the playing and usage of animations, including their various keyframes and + * instruction markers. Each controller can only play a single animation at a time - for example you may have one + * controller to animate walking, one to control attacks, one to control size, etc. + */ +public class AzAnimationController { + + protected static final Logger LOGGER = LoggerFactory.getLogger(AzAnimationController.class); + + protected final String name; + protected final AzAnimationStateHandler stateHandler; + protected final Map boneAnimationQueues = new Object2ObjectOpenHashMap<>(); + protected final Map boneSnapshots = new Object2ObjectOpenHashMap<>(); + protected final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); + protected final Set executedKeyFrames = new ObjectOpenHashSet<>(); + private final AzAnimator animator; + + protected Queue animationQueue = new LinkedList<>(); + protected boolean isJustStarting = false; + protected boolean needsAnimationReload = false; + protected boolean shouldResetTick = false; + protected boolean justStartedTransition = false; + protected AzSoundKeyframeHandler soundKeyframeHandler = null; + protected AzParticleKeyframeHandler particleKeyframeHandler = null; + protected AzCustomKeyframeHandler customKeyframeHandler = null; + protected AzRawAnimation triggeredAnimation = null; + + protected boolean handlingTriggeredAnimations = false; + + protected double transitionLength; + + protected AzRawAnimation currentRawAnimation; + + protected AzQueuedAnimation currentAnimation; + + protected AzAnimationControllerState animationState = AzAnimationControllerState.STOPPED; + + protected double tickOffset; + + protected ToDoubleFunction animationSpeedModifier = obj -> 1d; + + protected Function overrideEasingTypeFunction = obj -> null; + protected boolean justStopped = true; + + // FIXME: There used to be more constructors here. We should bring those back as a builder pattern. + + /** + * Instantiates a new {@code AnimationController}.
    + * + * @param name The name of the controller - should represent what animations it handles + * @param transitionTickTime The amount of time (in ticks) that the controller should take to transition + * between animations. Lerping is automatically applied where possible + * @param animationHandler The {@link AzAnimationStateHandler} animation state handler responsible for deciding + * which animations to play + */ + public AzAnimationController( + AzAnimator animator, + String name, + int transitionTickTime, + AzAnimationStateHandler animationHandler + ) { + this.animator = animator; + this.name = name; + this.transitionLength = transitionTickTime; + this.stateHandler = animationHandler; + } + + /** + * Applies the given {@link AzSoundKeyframeHandler} to this controller, for handling {@link AzSoundKeyframeEvent sound + * keyframe instructions}. + * + * @return this + */ + public AzAnimationController setSoundKeyframeHandler(AzSoundKeyframeHandler soundHandler) { + this.soundKeyframeHandler = soundHandler; + + return this; + } + + /** + * Applies the given {@link AzParticleKeyframeHandler} to this controller, for handling {@link AzParticleKeyframeEvent + * particle keyframe instructions}. + * + * @return this + */ + public AzAnimationController setParticleKeyframeHandler(AzParticleKeyframeHandler particleHandler) { + this.particleKeyframeHandler = particleHandler; + + return this; + } + + /** + * Applies the given {@link AzCustomKeyframeHandler} to this controller, for handling + * {@link AzCustomInstructionKeyframeEvent sound keyframe instructions}. + * + * @return this + */ + public AzAnimationController setCustomInstructionKeyframeHandler( + AzCustomKeyframeHandler customInstructionHandler + ) { + this.customKeyframeHandler = customInstructionHandler; + + return this; + } + + /** + * Applies the given modifier function to this controller, for handling the speed that the controller should play + * its animations at.
    + * An output value of 1 is considered neutral, with 2 playing an animation twice as fast, 0.5 playing half as fast, + * etc. + * + * @param speedModFunction The function to apply to this controller to handle animation speed + * @return this + */ + public AzAnimationController setAnimationSpeedHandler(ToDoubleFunction speedModFunction) { + this.animationSpeedModifier = speedModFunction; + + return this; + } + + public void setJustStarting(boolean justStarting) { + isJustStarting = justStarting; + } + + /** + * Sets the controller's {@link EasingType} override for animations.
    + * By default, the controller will use whatever {@code EasingType} was defined in the animation json + * + * @param easingTypeFunction The new {@code EasingType} to use + * @return this + */ + public AzAnimationController setOverrideEasingType(EasingType easingTypeFunction) { + return setOverrideEasingTypeFunction(obj -> easingTypeFunction); + } + + public Function getOverrideEasingTypeFunction() { + return overrideEasingTypeFunction; + } + + /** + * Sets the controller's {@link EasingType} override function for animations.
    + * By default, the controller will use whatever {@code EasingType} was defined in the animation json + * + * @param easingType The new {@code EasingType} to use + * @return this + */ + public AzAnimationController setOverrideEasingTypeFunction(Function easingType) { + this.overrideEasingTypeFunction = easingType; + + return this; + } + + /** + * Registers a triggerable {@link AzRawAnimation} with the controller.
    + * These can then be triggered by the various {@code triggerAnim} methods in {@code GeoAnimatable's} subclasses + * + * @param name The name of the triggerable animation + * @param animation The RawAnimation for this triggerable animation + * @return this + */ + public AzAnimationController triggerableAnim(String name, AzRawAnimation animation) { + this.triggerableAnimations.put(name, animation); + + return this; + } + + /** + * Tells the AnimationController that you want to receive the {@link AzAnimationStateHandler} while a triggered + * animation is playing.
    + *
    + * This has no effect if no triggered animation has been registered, or one isn't currently playing.
    + * If a triggered animation is playing, it can be checked in your AnimationStateHandler via + * {@link AzAnimationController#isPlayingTriggeredAnimation()} + */ + public AzAnimationController receiveTriggeredAnimations() { + this.handlingTriggeredAnimations = true; + + return this; + } + + /** + * Gets the controller's name. + * + * @return The name + */ + public String getName() { + return name; + } + + /** + * Gets the currently loaded {@link AzAnimation}. Can be null
    + * An animation returned here does not guarantee it is currently playing, just that it is the currently loaded + * animation for this controller + */ + + public AzQueuedAnimation getCurrentAnimation() { + return currentAnimation; + } + + /** + * Gets the currently loaded animation's {@link BoneAnimationQueue BoneAnimationQueues}. + */ + public Map getBoneAnimationQueues() { + return boneAnimationQueues; + } + + /** + * Gets the current animation speed modifier.
    + * This modifier defines the relative speed in which animations will be played based on the current state of the + * game. + * + * @return The computed current animation speed modifier + */ + public double getAnimationSpeed(T animatable) { + return animationSpeedModifier.applyAsDouble(animatable); + } + + /** + * Applies the given modifier value to this controller, for handlign the speed that the controller hsould play its + * animations at.
    + * A value of 1 is considered neutral, with 2 playing an animation twice as fast, 0.5 playing half as fast, etc. + * + * @param speed The speed modifier to apply to this controller to handle animation speed. + * @return this + */ + public AzAnimationController setAnimationSpeed(double speed) { + return setAnimationSpeedHandler(obj -> speed); + } + + /** + * Marks the controller as needing to reset its animation and state the next time + * {@link AzAnimationController#setAnimation(T, AzRawAnimation)} is called.
    + *
    + * Use this if you have a {@link AzRawAnimation} with multiple stages and you want it to start again from the first + * stage, or if you want to reset the currently playing animation to the start + */ + public void forceAnimationReset() { + this.needsAnimationReload = true; + } + + /** + * Tells the controller to stop all animations until told otherwise.
    + * Calling this will prevent the controller from continuing to play the currently loaded animation until either + * {@link AzAnimationController#forceAnimationReset()} is called, or + * {@link AzAnimationController#setAnimation(T, AzRawAnimation)} is called with a different animation + */ + public void stop() { + this.animationState = AzAnimationControllerState.STOPPED; + } + + /** + * Overrides the animation transition time for the controller + */ + public void setTransitionLength(int ticks) { + this.transitionLength = ticks; + } + + /** + * Checks whether the last animation that was playing on this controller has finished or not.
    + * This will return true if the controller has had an animation set previously, and it has finished playing and + * isn't going to loop or proceed to another animation.
    + * + * @return Whether the previous animation finished or not + */ + public boolean hasAnimationFinished() { + return currentRawAnimation != null && animationState == AzAnimationControllerState.STOPPED; + } + + /** + * Returns the currently cached {@link AzRawAnimation}.
    + * This animation may or may not still be playing, but it is the last one to be set in + * {@link AzAnimationController#setAnimation} + */ + public AzRawAnimation getCurrentRawAnimation() { + return currentRawAnimation; + } + + /** + * Returns whether the controller is currently playing a triggered animation registered in + * {@link AzAnimationController#triggerableAnim}
    + * Used for custom handling if {@link AzAnimationController#receiveTriggeredAnimations()} was marked + */ + public boolean isPlayingTriggeredAnimation() { + return triggeredAnimation != null && !hasAnimationFinished(); + } + + /** + * Sets the currently loaded animation to the one provided.
    + * This method may be safely called every render frame, as passing the same builder that is already loaded will do + * nothing.
    + * Pass null to this method to tell the controller to stop.
    + * If {@link AzAnimationController#forceAnimationReset()} has been called prior to this, the controller will reload + * the animation regardless of whether it matches the currently loaded one or not + */ + public void setAnimation(T animatable, AzRawAnimation rawAnimation) { + if (rawAnimation == null || rawAnimation.getAnimationStages().isEmpty()) { + stop(); + + return; + } + + if (needsAnimationReload || !rawAnimation.equals(currentRawAnimation)) { + var animations = animator.getAnimationProcessor().buildAnimationQueue(animatable, rawAnimation); + + if (animations != null) { + this.animationQueue = animations; + this.currentRawAnimation = rawAnimation; + this.shouldResetTick = true; + this.animationState = AzAnimationControllerState.TRANSITIONING; + this.justStartedTransition = true; + this.needsAnimationReload = false; + + return; + } + + stop(); + } + } + + /** + * Attempt to trigger an animation from the list of {@link AzAnimationController#triggerableAnimations triggerable + * animations} this controller contains. + * + * @param animName The name of the animation to trigger + * @return Whether the controller triggered an animation or not + */ + public boolean tryTriggerAnimation(String animName) { + var anim = triggerableAnimations.get(animName); + + if (anim == null) { + return false; + } + + this.triggeredAnimation = anim; + + if (animationState == AzAnimationControllerState.STOPPED) { + this.animationState = AzAnimationControllerState.TRANSITIONING; + this.shouldResetTick = true; + this.justStartedTransition = true; + } + + return true; + } + + /** + * Handle a given AnimationState, alongside the current triggered animation if applicable + */ + protected PlayState handleAnimationState(AzAnimationState state) { + if (triggeredAnimation != null) { + if (currentRawAnimation != triggeredAnimation) + this.currentAnimation = null; + + setAnimation(state.getAnimatable(), triggeredAnimation); + + if ( + !hasAnimationFinished() && (!handlingTriggeredAnimations || stateHandler.handle(state) == PlayState.CONTINUE) + ) + return PlayState.CONTINUE; + + this.triggeredAnimation = null; + this.needsAnimationReload = true; + } + + return stateHandler.handle(state); + } + + /** + * This method is called every frame in order to populate the animation point queues, and process animation state + * logic. + * + * @param state The animation test state + * @param bones The registered {@link CoreGeoBone bones} for this model + * @param snapshots The {@link BoneSnapshot} map + * @param seekTime The current tick + partial tick + * @param crashWhenCantFindBone Whether to hard-fail when a bone can't be found, or to continue with the remaining + * bones + */ + public void process( + AzAnimationState state, + Map bones, + Map snapshots, + final double seekTime, + boolean crashWhenCantFindBone + ) { + var animatable = state.getAnimatable(); + double adjustedTick = adjustTick(animatable, seekTime); + + if (animationState == AzAnimationControllerState.TRANSITIONING && adjustedTick >= transitionLength) { + this.shouldResetTick = true; + this.animationState = AzAnimationControllerState.RUNNING; + adjustedTick = adjustTick(animatable, seekTime); + } + + PlayState playState = handleAnimationState(state); + + if (playState == PlayState.STOP || (currentAnimation == null && animationQueue.isEmpty())) { + this.animationState = AzAnimationControllerState.STOPPED; + this.justStopped = true; + + return; + } + + createInitialQueues(bones.values()); + + if (justStartedTransition && (shouldResetTick || justStopped)) { + this.justStopped = false; + adjustedTick = adjustTick(animatable, seekTime); + + if (currentAnimation == null) { + this.animationState = AzAnimationControllerState.TRANSITIONING; + } + } else if (currentAnimation == null) { + this.shouldResetTick = true; + this.animationState = AzAnimationControllerState.TRANSITIONING; + this.justStartedTransition = true; + this.needsAnimationReload = false; + adjustedTick = adjustTick(animatable, seekTime); + } else if (animationState != AzAnimationControllerState.TRANSITIONING) { + this.animationState = AzAnimationControllerState.RUNNING; + } + + if (getAnimationState() == AzAnimationControllerState.RUNNING) { + processCurrentAnimation(animatable, adjustedTick, seekTime, crashWhenCantFindBone); + } else if (animationState == AzAnimationControllerState.TRANSITIONING) { + if (adjustedTick == 0 || isJustStarting) { + this.justStartedTransition = false; + this.currentAnimation = animationQueue.poll(); + + resetEventKeyFrames(); + + if (currentAnimation == null) { + return; + } + + saveSnapshotsForAnimation(currentAnimation, snapshots); + } + + if (currentAnimation != null) { + MolangParser.INSTANCE.setValue(MolangQueries.ANIM_TIME, () -> 0); + + for (var boneAnimation : currentAnimation.animation().boneAnimations()) { + var boneAnimationQueue = boneAnimationQueues.get(boneAnimation.boneName()); + var boneSnapshot = boneSnapshots.get(boneAnimation.boneName()); + var bone = bones.get(boneAnimation.boneName()); + + if (bone == null) { + if (crashWhenCantFindBone) + throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); + + continue; + } + + var rotationKeyFrames = boneAnimation.rotationKeyFrames(); + var positionKeyFrames = boneAnimation.positionKeyFrames(); + var scaleKeyFrames = boneAnimation.scaleKeyFrames(); + + if (!rotationKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addNextRotation( + null, + adjustedTick, + transitionLength, + boneSnapshot, + bone.getInitialSnapshot(), + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) + ); + } + + if (!positionKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addNextPosition( + null, + adjustedTick, + transitionLength, + boneSnapshot, + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) + ); + } + + if (!scaleKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addNextScale( + null, + adjustedTick, + transitionLength, + boneSnapshot, + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) + ); + } + } + } + } + } + + /** + * Handle the current animation's state modifications and translations + * + * @param adjustedTick The controller-adjusted tick for animation purposes + * @param seekTime The lerped tick (current tick + partial tick) + * @param crashWhenCantFindBone Whether the controller should throw an exception when unable to find the required + * bone, or continue with the remaining bones + */ + protected void processCurrentAnimation(T animatable, double adjustedTick, double seekTime, boolean crashWhenCantFindBone) { + if (adjustedTick >= currentAnimation.animation().length()) { + if ( + currentAnimation.loopType().shouldPlayAgain(animatable, this, this.currentAnimation.animation()) + ) { + if (animationState != AzAnimationControllerState.PAUSED) { + this.shouldResetTick = true; + + adjustedTick = adjustTick(animatable, seekTime); + resetEventKeyFrames(); + } + } else { + var nextAnimation = animationQueue.peek(); + + resetEventKeyFrames(); + + if (nextAnimation == null) { + this.animationState = AzAnimationControllerState.STOPPED; + + return; + } else { + this.animationState = AzAnimationControllerState.TRANSITIONING; + this.shouldResetTick = true; + this.currentAnimation = nextAnimation; + } + } + } + + final double finalAdjustedTick = adjustedTick; + + MolangParser.INSTANCE.setMemoizedValue(MolangQueries.ANIM_TIME, () -> finalAdjustedTick / 20d); + + for (var boneAnimation : currentAnimation.animation().boneAnimations()) { + var boneAnimationQueue = boneAnimationQueues.get(boneAnimation.boneName()); + + if (boneAnimationQueue == null) { + if (crashWhenCantFindBone) + throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); + + continue; + } + + var rotationKeyFrames = boneAnimation.rotationKeyFrames(); + var positionKeyFrames = boneAnimation.positionKeyFrames(); + var scaleKeyFrames = boneAnimation.scaleKeyFrames(); + + if (!rotationKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addRotations( + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) + ); + } + + if (!positionKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addPositions( + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + ); + } + + if (!scaleKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addScales( + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + ); + } + } + + adjustedTick += this.transitionLength; + + for (var keyframeData : currentAnimation.animation().keyFrames().sounds()) { + if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { + if (soundKeyframeHandler == null) { + LOGGER.warn( + "Sound Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + getName() + ); + break; + } + + soundKeyframeHandler.handle( + new AzSoundKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) + ); + } + } + + for (var keyframeData : currentAnimation.animation().keyFrames().particles()) { + if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { + if (particleKeyframeHandler == null) { + LOGGER.warn( + "Particle Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + getName() + ); + break; + } + + particleKeyframeHandler.handle( + new AzParticleKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) + ); + } + } + + for ( + var keyframeData : currentAnimation.animation() + .keyFrames() + .customInstructions() + ) { + if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { + if (customKeyframeHandler == null) { + LOGGER.warn( + "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + getName() + ); + break; + } + + customKeyframeHandler.handle( + new AzCustomInstructionKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) + ); + } + } + + if (this.transitionLength == 0 && this.shouldResetTick && this.animationState == AzAnimationControllerState.TRANSITIONING) { + this.currentAnimation = this.animationQueue.poll(); + } + } + + /** + * Prepare the {@link BoneAnimationQueue} map for the current render frame + * + * @param modelRendererList The bone list from the {@link AzAnimationProcessor} + */ + protected void createInitialQueues(Collection modelRendererList) { + boneAnimationQueues.clear(); + + for (var modelRenderer : modelRendererList) { + boneAnimationQueues.put(modelRenderer.getName(), new BoneAnimationQueue(modelRenderer)); + } + } + + /** + * Cache the relevant {@link BoneSnapshot BoneSnapshots} for the current {@link AzQueuedAnimation} + * for animation lerping + * + * @param animation The {@code QueuedAnimation} to filter {@code BoneSnapshots} for + * @param snapshots The master snapshot collection to pull filter from + */ + protected void saveSnapshotsForAnimation( + AzQueuedAnimation animation, + Map snapshots + ) { + if (animation.animation().boneAnimations() == null) { + return; + } + + for (var snapshot : snapshots.values()) { + for (var boneAnimation : animation.animation().boneAnimations()) { + if (boneAnimation.boneName().equals(snapshot.getBone().getName())) { + boneSnapshots.put(boneAnimation.boneName(), BoneSnapshot.copy(snapshot)); + break; + } + } + } + } + + /** + * Adjust a tick value depending on the controller's current state and speed modifier.
    + * Is used when starting a new animation, transitioning, and a few other key areas + * + * @param tick The currently used tick value + * @return 0 if {@link AzAnimationController#shouldResetTick} is set to false, or a + * {@link AzAnimationController#animationSpeedModifier} modified value otherwise + */ + protected double adjustTick(T animatable, double tick) { + if (!shouldResetTick) { + return animationSpeedModifier.applyAsDouble(animatable) * Math.max(tick - tickOffset, 0); + } + + if (getAnimationState() != AzAnimationControllerState.STOPPED) { + this.tickOffset = tick; + } + + this.shouldResetTick = false; + + return 0; + } + + /** + * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} + */ + protected AnimationPoint getAnimationPointAtTick( + List> frames, + double tick, + boolean isRotation, + Axis axis + ) { + var location = getCurrentKeyFrameLocation(frames, tick); + var currentFrame = location.keyframe(); + var startValue = currentFrame.startValue().get(); + var endValue = currentFrame.endValue().get(); + + if (isRotation) { + if (!(currentFrame.startValue() instanceof Constant)) { + startValue = Math.toRadians(startValue); + + if (axis == Axis.X || axis == Axis.Y) { + startValue *= -1; + } + } + + if (!(currentFrame.endValue() instanceof Constant)) { + endValue = Math.toRadians(endValue); + + if (axis == Axis.X || axis == Axis.Y) { + endValue *= -1; + } + } + } + + return new AnimationPoint(currentFrame, location.startTick(), currentFrame.length(), startValue, endValue); + } + + /** + * Returns the {@link Keyframe} relevant to the current tick time + * + * @param frames The list of {@code KeyFrames} to filter through + * @param ageInTicks The current tick time + * @return A new {@code KeyFrameLocation} containing the current {@code KeyFrame} and the tick time used to find it + */ + protected KeyframeLocation> getCurrentKeyFrameLocation( + List> frames, + double ageInTicks + ) { + var totalFrameTime = 0; + + for (var frame : frames) { + totalFrameTime += frame.length(); + + if (totalFrameTime > ageInTicks) { + return new KeyframeLocation<>(frame, (ageInTicks - (totalFrameTime - frame.length()))); + } + } + + return new KeyframeLocation<>(frames.get(frames.size() - 1), ageInTicks); + } + + /** + * Clear the {@link KeyFrameData} cache in preparation for the next animation + */ + protected void resetEventKeyFrames() { + executedKeyFrames.clear(); + } + + /** + * Returns the current state of this controller. + */ + public AzAnimationControllerState getAnimationState() { + return animationState; + } + + public void setAnimationState(AzAnimationControllerState animationState) { + this.animationState = animationState; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerContainer.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerContainer.java new file mode 100644 index 000000000..8c06ca6dd --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerContainer.java @@ -0,0 +1,28 @@ +package mod.azure.azurelib.core2.animation.controller; + +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; + +import java.util.Collection; +import java.util.Map; + +public class AzAnimationControllerContainer { + + private final Map> animationControllersByName; + + public AzAnimationControllerContainer() { + this.animationControllersByName = new Object2ObjectArrayMap<>(); + } + + @SafeVarargs + public final void add(AzAnimationController controller, AzAnimationController... controllers) { + animationControllersByName.put(controller.getName(), controller); + + for (var extraController : controllers) { + animationControllersByName.put(extraController.getName(), extraController); + } + } + + public Collection> getAll() { + return animationControllersByName.values(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java new file mode 100644 index 000000000..d67b7d3e8 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java @@ -0,0 +1,8 @@ +package mod.azure.azurelib.core2.animation.controller; + +public enum AzAnimationControllerState { + RUNNING, + TRANSITIONING, + PAUSED, + STOPPED; +} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java new file mode 100644 index 000000000..eee1fea77 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java @@ -0,0 +1,34 @@ +package mod.azure.azurelib.core2.animation.controller.handler; + +import mod.azure.azurelib.core.object.PlayState; +import mod.azure.azurelib.core2.animation.AzAnimationState; + +/** + * Every render frame, the {@code AzAnimationController} will call this handler for each animatable that is + * being rendered. This handler defines which animation should be currently playing, and returning a + * {@link PlayState} to tell the controller what to do next.
    + * Example Usage:
    + * + *
    {@code
    + *
    + * AzAnimationFrameHandler myIdleWalkHandler = state -> {
    + *     if (state.isMoving()) {
    + *         state.getController().setAnimation(myWalkAnimation);
    + *     } else {
    + *         state.getController().setAnimation(myIdleAnimation);
    + *     }
    + *
    + *     return PlayState.CONTINUE;
    + * };
    + * }
    + */ +@FunctionalInterface +public interface AzAnimationStateHandler { + + /** + * The handling method, called each frame. Return {@link PlayState#CONTINUE} to tell the controller to continue + * animating, or return {@link PlayState#STOP} to tell it to stop playing all animations and wait for the next + * {@code PlayState.CONTINUE} return. + */ + PlayState handle(AzAnimationState state); +} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzCustomKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzCustomKeyframeHandler.java new file mode 100644 index 000000000..12c782102 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzCustomKeyframeHandler.java @@ -0,0 +1,14 @@ +package mod.azure.azurelib.core2.animation.controller.handler; + +import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; + +/** + * A handler for pre-defined custom instruction keyframes. When the keyframe is encountered, the + * {@link AzCustomKeyframeHandler#handle(AzCustomInstructionKeyframeEvent)} method will be called. You can then take + * whatever action you want at this point. + */ +@FunctionalInterface +public interface AzCustomKeyframeHandler { + + void handle(AzCustomInstructionKeyframeEvent event); +} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzParticleKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzParticleKeyframeHandler.java new file mode 100644 index 000000000..fe80c4381 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzParticleKeyframeHandler.java @@ -0,0 +1,14 @@ +package mod.azure.azurelib.core2.animation.controller.handler; + +import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; + +/** + * A handler for when a predefined particle keyframe is hit. When the keyframe is encountered, the + * {@link AzParticleKeyframeHandler#handle(AzParticleKeyframeEvent)} method will be called. Spawn the particles/effects + * of your choice at this time. + */ +@FunctionalInterface +public interface AzParticleKeyframeHandler { + + void handle(AzParticleKeyframeEvent event); +} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzSoundKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzSoundKeyframeHandler.java new file mode 100644 index 000000000..a0ed97dd0 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzSoundKeyframeHandler.java @@ -0,0 +1,14 @@ +package mod.azure.azurelib.core2.animation.controller.handler; + +import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; + +/** + * A handler for when a predefined sound keyframe is hit. When the keyframe is encountered, the + * {@link AzSoundKeyframeHandler#handle(AzSoundKeyframeEvent)} method will be called. Play the sound(s) of your choice + * at this time. + */ +@FunctionalInterface +public interface AzSoundKeyframeHandler { + + void handle(AzSoundKeyframeEvent event); +} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java new file mode 100644 index 000000000..c850a9ad6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java @@ -0,0 +1,28 @@ +package mod.azure.azurelib.core2.animation.event; + +import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; + +/** + * The {@link AzKeyFrameEvent} specific to the {@link AzAnimationController#customKeyframeHandler}.
    + * Called when a custom instruction keyframe is encountered + */ +public class AzCustomInstructionKeyframeEvent extends AzKeyFrameEvent { + + public AzCustomInstructionKeyframeEvent( + T entity, + double animationTick, + AzAnimationController controller, + CustomInstructionKeyframeData customInstructionKeyframeData + ) { + super(entity, animationTick, controller, customInstructionKeyframeData); + } + + /** + * Get the {@link CustomInstructionKeyframeData} relevant to this event call + */ + @Override + public CustomInstructionKeyframeData getKeyframeData() { + return super.getKeyframeData(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzKeyFrameEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzKeyFrameEvent.java new file mode 100644 index 000000000..e2e24fba6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzKeyFrameEvent.java @@ -0,0 +1,60 @@ +package mod.azure.azurelib.core2.animation.event; + +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.keyframe.event.data.KeyFrameData; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; + +/** + * The base class for {@link Keyframe} events.
    + * These will be passed to one of the controllers in {@link AzAnimationController} when encountered during animation. + * + * @see AzCustomInstructionKeyframeEvent + * @see AzParticleKeyframeEvent + * @see AzSoundKeyframeEvent + */ +public abstract class AzKeyFrameEvent { + + private final T animatable; + + private final double animationTick; + + private final AzAnimationController controller; + + private final E eventKeyFrame; + + protected AzKeyFrameEvent(T animatable, double animationTick, AzAnimationController controller, E eventKeyFrame) { + this.animatable = animatable; + this.animationTick = animationTick; + this.controller = controller; + this.eventKeyFrame = eventKeyFrame; + } + + /** + * Gets the amount of ticks that have passed in either the current transition or animation, depending on the + * controller's AnimationState. + */ + public double getAnimationTick() { + return animationTick; + } + + /** + * Gets the {@link T animatable} object being rendered + */ + public T getAnimatable() { + return animatable; + } + + /** + * Gets the {@link AzAnimationController} responsible for the currently playing animation + */ + public AzAnimationController getController() { + return controller; + } + + /** + * Returns the {@link KeyFrameData} relevant to the encountered {@link Keyframe} + */ + public E getKeyframeData() { + return this.eventKeyFrame; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java new file mode 100644 index 000000000..0d0c172d7 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java @@ -0,0 +1,36 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. + * Original source: https://github.com/bernie-g/geckolib + * Copyright © 2024 Bernie-G. + * Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation.event; + +import mod.azure.azurelib.core.keyframe.event.KeyFrameEvent; +import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; + +/** + * The {@link KeyFrameEvent} specific to the {@link AzAnimationController#particleKeyframeHandler}.
    + * Called when a particle instruction keyframe is encountered + */ +public class AzParticleKeyframeEvent extends AzKeyFrameEvent { + + public AzParticleKeyframeEvent( + T animatable, + double animationTick, + AzAnimationController controller, + ParticleKeyframeData particleKeyFrameData + ) { + super(animatable, animationTick, controller, particleKeyFrameData); + } + + /** + * Get the {@link ParticleKeyframeData} relevant to this event call + */ + @Override + public ParticleKeyframeData getKeyframeData() { + return super.getKeyframeData(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java new file mode 100644 index 000000000..ffd2fb663 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java @@ -0,0 +1,36 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. + * Original source: https://github.com/bernie-g/geckolib + * Copyright © 2024 Bernie-G. + * Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation.event; + +import mod.azure.azurelib.core.keyframe.event.KeyFrameEvent; +import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; + +/** + * The {@link KeyFrameEvent} specific to the {@link AzAnimationController#soundKeyframeHandler}.
    + * Called when a sound instruction keyframe is encountered + */ +public class AzSoundKeyframeEvent extends AzKeyFrameEvent { + + /** + * This stores all the fields that are needed in the AnimationTestEvent + * + * @param entity the entity + * @param animationTick The amount of ticks that have passed in either the current transition or animation, + * depending on the controller's AnimationState. + * @param controller the controller + */ + public AzSoundKeyframeEvent( + T entity, + double animationTick, + AzAnimationController controller, + SoundKeyframeData keyFrameData + ) { + super(entity, animationTick, controller, keyFrameData); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java new file mode 100644 index 000000000..3a4d9a409 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java @@ -0,0 +1,71 @@ +package mod.azure.azurelib.core2.animation.impl; + +import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.MolangQueries; +import mod.azure.azurelib.core2.animation.AzAnimationState; +import mod.azure.azurelib.core2.animation.AzAnimator; +import net.minecraft.client.Minecraft; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; + +public abstract class AzEntityAnimator extends AzAnimator { + + public AzAnimationState createAnimationState(T animatable, float limbSwing, float limbSwingAmount, float partialTick) { + var velocity = animatable.getDeltaMovement(); + var avgVelocity = (float) (Math.abs(velocity.x) + Math.abs(velocity.z) / 2f); + var motionThreshold = getMotionAnimThreshold(animatable); + + return new AzAnimationState<>( + animatable, + limbSwing, + limbSwingAmount, + partialTick, + avgVelocity >= motionThreshold && limbSwingAmount != 0 + ); + } + + @Override + protected void applyMolangQueries(T entity, double animTime) { + super.applyMolangQueries(entity, animTime); + + var parser = MolangParser.INSTANCE; + var minecraft = Minecraft.getInstance(); + + parser.setMemoizedValue( + MolangQueries.DISTANCE_FROM_CAMERA, + () -> minecraft.gameRenderer.getMainCamera().getPosition().distanceTo(entity.position()) + ); + parser.setMemoizedValue(MolangQueries.IS_ON_GROUND, () -> RenderUtils.booleanToFloat(entity.onGround())); + parser.setMemoizedValue(MolangQueries.IS_IN_WATER, () -> RenderUtils.booleanToFloat(entity.isInWater())); + parser.setMemoizedValue(MolangQueries.IS_IN_WATER_OR_RAIN, () -> RenderUtils.booleanToFloat(entity.isInWaterOrRain())); + parser.setMemoizedValue(MolangQueries.IS_ON_FIRE, () -> RenderUtils.booleanToFloat(entity.isOnFire())); + + if (entity instanceof LivingEntity livingEntity) { + parser.setMemoizedValue(MolangQueries.HEALTH, livingEntity::getHealth); + parser.setMemoizedValue(MolangQueries.MAX_HEALTH, livingEntity::getMaxHealth); + parser.setMemoizedValue(MolangQueries.GROUND_SPEED, () -> { + var velocity = livingEntity.getDeltaMovement(); + return Mth.sqrt((float) ((velocity.x * velocity.x) + (velocity.z * velocity.z))); + }); + parser.setMemoizedValue(MolangQueries.YAW_SPEED, () -> livingEntity.getYRot() - livingEntity.yRotO); + } + } + + /** + * Determines the threshold value before the animatable should be considered moving for animation purposes.
    + * The default value and usage for this varies depending on the renderer.
    + *
      + *
    • For entities, it represents the averaged lateral velocity of the object.
    • + *
    • For {@link GeoBlockEntity Tile Entities} and {@link GeoItem Items}, it's currently unused
    • + *
    + * The lower the value, the more sensitive the {@link AzAnimationState#isMoving()} check will be.
    + * Particularly low values may have adverse effects however + */ + protected float getMotionAnimThreshold(T animatable) { + return 0.015f; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java new file mode 100644 index 000000000..6e0130af5 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java @@ -0,0 +1,32 @@ +package mod.azure.azurelib.core2.animation.primitive; + +import mod.azure.azurelib.core.keyframe.BoneAnimation; +import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; +import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; +import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; + +/** + * A compiled animation instance for use by the {@link AzAnimationController}
    + * Modifications or extensions of a compiled Animation are not supported, and therefore an instance of + * Animation is considered final and immutable. + */ +public record AzAnimation( + String name, + double length, + AzLoopType loopType, + BoneAnimation[] boneAnimations, + AzKeyframes keyFrames +) { + + public static AzAnimation generateWaitAnimation(double length) { + return new AzAnimation( + AzStage.WAIT, + length, + AzLoopType.PLAY_ONCE, + new BoneAnimation[0], + new AzKeyframes(new SoundKeyframeData[0], new ParticleKeyframeData[0], + new CustomInstructionKeyframeData[0]) + ); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimations.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimations.java new file mode 100644 index 000000000..ea490c4df --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimations.java @@ -0,0 +1,25 @@ +package mod.azure.azurelib.core2.animation.primitive; + +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +/** + * Container object that holds a deserialized map of {@link AzAnimation Animations}.
    + * Kept as a unique object so that it can be registered as a {@link com.google.gson.JsonDeserializer deserializer} for + * {@link com.google.gson.Gson Gson} + */ +public record AzBakedAnimations( + Map animations, + Map includes +) { + /** + * Gets an {@link AzAnimation} by its name, if present + */ + @Nullable + public AzAnimation getAnimation(String name) { + return animations.get(name); + } + +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzKeyframes.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzKeyframes.java new file mode 100644 index 000000000..da7883b56 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzKeyframes.java @@ -0,0 +1,11 @@ +package mod.azure.azurelib.core2.animation.primitive; + +import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; +import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; +import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; + +public record AzKeyframes( + SoundKeyframeData[] sounds, + ParticleKeyframeData[] particles, + CustomInstructionKeyframeData[] customInstructions +) {} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java new file mode 100644 index 000000000..b578db81e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java @@ -0,0 +1,95 @@ +package mod.azure.azurelib.core2.animation.primitive; + +import com.google.gson.JsonElement; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerState; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Loop type functional interface to define post-play handling for a given animation.
    + * Custom loop types are supported by extending this class and providing the extended class instance as the loop + * type for the animation + */ +@FunctionalInterface +public interface AzLoopType { + + Map LOOP_TYPES = new ConcurrentHashMap<>(4); + + AzLoopType DEFAULT = (animatable, controller, currentAnimation) -> currentAnimation.loopType() + .shouldPlayAgain(animatable, controller, currentAnimation); + + AzLoopType PLAY_ONCE = register( + "play_once", + register("false", (animatable, controller, currentAnimation) -> false) + ); + + AzLoopType HOLD_ON_LAST_FRAME = register("hold_on_last_frame", (animatable, controller, currentAnimation) -> { + controller.setAnimationState(AzAnimationControllerState.PAUSED); + + return true; + }); + + AzLoopType LOOP = register("loop", register("true", (animatable, controller, currentAnimation) -> true)); + + /** + * Retrieve a AzLoopType instance based on a {@link JsonElement}. Returns either {@link AzLoopType#PLAY_ONCE} or + * {@link AzLoopType#LOOP} based on a boolean or string element type, or any other registered loop type with a + * matching type string. + * + * @param json The loop {@link JsonElement} to attempt to parse + * @return A usable AzLoopType instance + */ + static AzLoopType fromJson(JsonElement json) { + if (json == null || !json.isJsonPrimitive()) { + return PLAY_ONCE; + } + + var primitive = json.getAsJsonPrimitive(); + + if (primitive.isBoolean()) { + return primitive.getAsBoolean() ? LOOP : PLAY_ONCE; + } + + if (primitive.isString()) { + return fromString(primitive.getAsString()); + } + + return PLAY_ONCE; + } + + static AzLoopType fromString(String name) { + return LOOP_TYPES.getOrDefault(name, PLAY_ONCE); + } + + /** + * Register a AzLoopType with AzureLib for handling loop functionality of animations..
    + * MUST be called during mod construct
    + * It is recommended you don't call this directly, and instead call it via + * {@code AzureLibUtil#addCustomLoopType} + * + * @param name The name of the loop type + * @param loopType The loop type to register + * @return The registered {@code AzLoopType} + */ + static AzLoopType register(String name, AzLoopType loopType) { + LOOP_TYPES.put(name, loopType); + + return loopType; + } + + /** + * Override in a custom instance to dynamically decide whether an animation should repeat or stop + * + * @param animatable The animating object relevant to this method call + * @param controller The {@link AzAnimationController} playing the current animation + * @param currentAnimation The current animation that just played + * @return Whether the animation should play again, or stop + */ + boolean shouldPlayAgain( + Object animatable, + AzAnimationController controller, + AzAnimation currentAnimation + ); +} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzQueuedAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzQueuedAnimation.java new file mode 100644 index 000000000..4dba6736e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzQueuedAnimation.java @@ -0,0 +1,9 @@ +package mod.azure.azurelib.core2.animation.primitive; + +/** + * {@link AzAnimation} and {@link AzLoopType} override pair. + */ +public record AzQueuedAnimation( + AzAnimation animation, + AzLoopType loopType +) {} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzRawAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzRawAnimation.java new file mode 100644 index 000000000..d50504a5b --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzRawAnimation.java @@ -0,0 +1,149 @@ +package mod.azure.azurelib.core2.animation.primitive; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; + +import java.util.List; +import java.util.Objects; + +/** + * A builder class for a raw/unbaked animation. These are constructed to pass to the {@link AzAnimationController} to + * build into full-fledged animations for usage.
    + *
    + * Animations added to this builder are added in order of insertion - the animations will play in the order that + * you define them.
    + * AzRawAnimation instances should be cached statically where possible to reduce overheads and improve efficiency.
    + *
    + * Example usage:
    + * + *
    {@code
    + * AzRawAnimation.begin().thenPlay("action.open_box").thenLoop("state.stay_open")
    + * }
    + */ +public final class AzRawAnimation { + + private final List animationList; + + // Private constructor to force usage of factory for logical operations + private AzRawAnimation() { + this.animationList = new ObjectArrayList<>(); + } + + /** + * Start a new RawAnimation instance. This is the start point for creating an animation chain. + * + * @return A new RawAnimation instance + */ + public static AzRawAnimation begin() { + return new AzRawAnimation(); + } + + /** + * Create a new RawAnimation instance based on an existing RawAnimation instance. The new instance will be a shallow + * copy of the other instance, and can then be appended to or otherwise modified + * + * @param other The existing RawAnimation instance to copy + * @return A new instance of RawAnimation + */ + public static AzRawAnimation copyOf(AzRawAnimation other) { + AzRawAnimation newInstance = AzRawAnimation.begin(); + + newInstance.animationList.addAll(other.animationList); + + return newInstance; + } + + /** + * Append an animation to the animation chain, playing the named animation and stopping or progressing to the next + * chained animation depending on the loop type set in the animation json + * + * @param animationName The name of the animation to play once + */ + public AzRawAnimation thenPlay(String animationName) { + return then(animationName, AzLoopType.DEFAULT); + } + + /** + * Append an animation to the animation chain, playing the named animation and repeating it continuously until the + * animation is stopped by external sources. + * + * @param animationName The name of the animation to play on a loop + */ + public AzRawAnimation thenLoop(String animationName) { + return then(animationName, AzLoopType.LOOP); + } + + /** + * Appends a 'wait' animation to the animation chain.
    + * This causes the animatable to do nothing for a set period of time before performing the next animation. + * + * @param ticks The number of ticks to 'wait' for + */ + public AzRawAnimation thenWait(int ticks) { + this.animationList.add(new AzStage(AzStage.WAIT, AzLoopType.PLAY_ONCE, ticks)); + + return this; + } + + /** + * Appends an animation to the animation chain, then has the animatable hold the pose at the end of the animation + * until it is stopped by external sources. + * + * @param animation The name of the animation to play and hold + */ + public AzRawAnimation thenPlayAndHold(String animation) { + return then(animation, AzLoopType.HOLD_ON_LAST_FRAME); + } + + /** + * Append an animation to the animation chain, playing the named animation playCount times, then + * stopping or progressing to the next chained animation depending on the loop type set in the animation json + * + * @param animationName The name of the animation to play X times + * @param playCount The number of times to repeat the animation before proceeding + */ + public AzRawAnimation thenPlayXTimes(String animationName, int playCount) { + for (int i = 0; i < playCount; i++) { + then(animationName, i == playCount - 1 ? AzLoopType.DEFAULT : AzLoopType.PLAY_ONCE); + } + + return this; + } + + /** + * Append an animation to the animation chain, playing the named animation and proceeding based on the + * loopType parameter provided. + * + * @param animationName The name of the animation to play. MUST match the name of the animation in the + * .animation.json file. + * @param loopType The loop type handler for the animation, overriding the default value set in the animation + * json + */ + public AzRawAnimation then(String animationName, AzLoopType loopType) { + this.animationList.add(new AzStage(animationName, loopType)); + + return this; + } + + public List getAnimationStages() { + return this.animationList; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + + if (obj == null || getClass() != obj.getClass()) + return false; + + return hashCode() == obj.hashCode(); + } + + @Override + public int hashCode() { + return Objects.hash(this.animationList); + } + + +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzStage.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzStage.java new file mode 100644 index 000000000..a36747fab --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzStage.java @@ -0,0 +1,38 @@ +package mod.azure.azurelib.core2.animation.primitive; + +import java.util.Objects; + +/** + * An animation stage for a {@link AzRawAnimation} builder.
    + * This is an entry object representing a single animation stage of the final compiled animation. + */ +public record AzStage( + String animationName, + AzLoopType loopType, + int additionalTicks +) { + + public static final String WAIT = "internal.wait"; + + public AzStage(String animationName, AzLoopType loopType) { + this(animationName, loopType, 0); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + return hashCode() == obj.hashCode(); + } + + @Override + public int hashCode() { + return Objects.hash(this.animationName, this.loopType); + } +} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 6ed6e3c9e..ffccc9343 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -2,7 +2,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import mod.azure.azurelib.core2.render.pipeline.impl.AzEntityRendererPipeline; @@ -27,7 +27,7 @@ public abstract class AzEntityRenderer extends EntityRenderer< private float scaleHeight = 1; private final AzEntityRendererPipeline azEntityRendererPipeline; private final List> renderLayers; - private final AzAnimator azAnimator; + private final AzEntityAnimator azAnimator; protected AzEntityRenderer(EntityRendererProvider.Context context) { super(context); @@ -36,7 +36,6 @@ protected AzEntityRenderer(EntityRendererProvider.Context context) { this.azAnimator = createAnimator(); } - protected abstract @Nullable AzAnimator createAnimator(); protected abstract @NotNull ResourceLocation getModelLocation(T entity); @Override @@ -46,6 +45,10 @@ public void render(@NotNull T entity, float entityYaw, float partialTick, @NotNu azEntityRendererPipeline.defaultRender(poseStack, bakedGeoModel, entity, bufferSource, null, null, entityYaw, partialTick, packedLight); } + protected @Nullable AzEntityAnimator createAnimator() { + return null; + } + /** * Sets a scale override for this renderer, telling AzureLib to pre-scale the model */ @@ -134,7 +137,7 @@ public int getBlockLightLevel(@NotNull T entity, @NotNull BlockPos pos) { return super.getBlockLightLevel(entity, pos); } - public AzAnimator getAnimator() { + public AzEntityAnimator getAnimator() { return azAnimator; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java index aead41f11..403f8bd7f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -187,19 +187,10 @@ public void actuallyRender( } if (!isReRender) { - // FIXME: - float headPitch = Mth.lerp(partialTick, animatable.xRotO, animatable.getXRot()); - var velocity = animatable.getDeltaMovement(); - float avgVelocity = (float) (Math.abs(velocity.x) + Math.abs(velocity.z) / 2f); - -// float motionThreshold = getMotionAnimThreshold(animatable); -// AnimationState animationState = new AnimationState( -// animatable, -// limbSwing, -// limbSwingAmount, -// partialTick, -// avgVelocity >= motionThreshold && limbSwingAmount != 0 -// ); + // FIXME: Figure out what to do with this data stuff. +// float headPitch = Mth.lerp(partialTick, animatable.xRotO, animatable.getXRot()); +// var velocity = animatable.getDeltaMovement(); +// float avgVelocity = (float) (Math.abs(velocity.x) + Math.abs(velocity.z) / 2f); // // long instanceId = getInstanceId(animatable); // @@ -214,14 +205,12 @@ public void actuallyRender( // -headPitch // ) // ); - - // FIXME: +// // this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); -// this.model.handleAnimations(animatable, instanceId, animationState); -// runAnimations(animatable, animationState); - var geoAnimationProvider = azEntityRenderer.getAnimator(); - geoAnimationProvider.runAnimations(animatable); + var animator = azEntityRenderer.getAnimator(); + var animationState = animator.createAnimationState(animatable, limbSwing, limbSwingAmount, partialTick); + animator.animate(animatable, animationState); } this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); @@ -421,11 +410,13 @@ protected void applyRotations( */ protected void applyRotations(T animatable, PoseStack poseStack, float ageInTicks, float rotationYaw, float partialTick, float nativeScale) { - if (isShaking(animatable)) - rotationYaw += (float)(Math.cos(animatable.tickCount * 3.25d) * Math.PI * 0.4d); + if (isShaking(animatable)) { + rotationYaw += (float) (Math.cos(animatable.tickCount * 3.25d) * Math.PI * 0.4d); + } - if (!animatable.hasPose(Pose.SLEEPING)) + if (!animatable.hasPose(Pose.SLEEPING)) { poseStack.mulPose(Axis.YP.rotationDegrees(180f - rotationYaw)); + } if (animatable instanceof LivingEntity livingEntity) { if (livingEntity.deathTime > 0) { From 1d071801d065684eb05b9d5412dd53a4f84c951b Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Tue, 3 Dec 2024 16:31:25 -0500 Subject: [PATCH 012/224] Committing progress. Signed-off-by: = --- .../common/internal/common/util/JsonUtil.java | 40 +- .../controller/AzAnimationController.java | 6 +- .../parse/AzBakedAnimationsAdapter.java | 269 + .../animation/parse/AzKeyFramesAdapter.java | 112 + .../core2/render/entity/AzEntityRenderer.java | 13 + .../impl/AzEntityRendererPipeline.java | 2 +- .../animations/entity/drone.animation.json | 8542 +++++++++++++++++ .../assets/azurelib/geo/entity/drone.geo.json | 722 ++ .../assets/azurelib/textures/entity/drone.png | Bin 0 -> 18747 bytes .../azure/azurelib/fabric/ClientListener.java | 6 +- .../azurelib/fabric/FabricAzureLibMod.java | 20 +- .../azurelib/fabric/core2/example/Drone.java | 12 + .../fabric/core2/example/DroneAnimator.java | 34 + .../fabric/core2/example/DroneRenderer.java | 34 + .../core2/example/ExampleEntityTypes.java | 28 + 15 files changed, 9810 insertions(+), 30 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzKeyFramesAdapter.java create mode 100644 common/src/main/resources/assets/azurelib/animations/entity/drone.animation.json create mode 100644 common/src/main/resources/assets/azurelib/geo/entity/drone.geo.json create mode 100644 common/src/main/resources/assets/azurelib/textures/entity/drone.png create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneRenderer.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java index 4ab7c0be2..68ea14402 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java @@ -15,6 +15,10 @@ import mod.azure.azurelib.common.internal.common.loading.json.typeadapter.KeyFramesAdapter; import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; import mod.azure.azurelib.core.animation.Animation; +import mod.azure.azurelib.core2.animation.parse.AzBakedAnimationsAdapter; +import mod.azure.azurelib.core2.animation.parse.AzKeyFramesAdapter; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; +import mod.azure.azurelib.core2.animation.primitive.AzKeyframes; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; @@ -29,22 +33,26 @@ public record JsonUtil() { public static final Gson GEO_GSON = new GsonBuilder().setLenient() - .registerTypeAdapter(Bone.class, Bone.deserializer()) - .registerTypeAdapter(Cube.class, Cube.deserializer()) - .registerTypeAdapter(FaceUV.class, FaceUV.deserializer()) - .registerTypeAdapter(LocatorClass.class, LocatorClass.deserializer()) - .registerTypeAdapter(LocatorValue.class, LocatorValue.deserializer()) - .registerTypeAdapter(MinecraftGeometry.class, MinecraftGeometry.deserializer()) - .registerTypeAdapter(Model.class, Model.deserializer()) - .registerTypeAdapter(ModelProperties.class, ModelProperties.deserializer()) - .registerTypeAdapter(PolyMesh.class, PolyMesh.deserializer()) - .registerTypeAdapter(PolysUnion.class, PolysUnion.deserializer()) - .registerTypeAdapter(TextureMesh.class, TextureMesh.deserializer()) - .registerTypeAdapter(UVFaces.class, UVFaces.deserializer()) - .registerTypeAdapter(UVUnion.class, UVUnion.deserializer()) - .registerTypeAdapter(Animation.Keyframes.class, new KeyFramesAdapter()) - .registerTypeAdapter(BakedAnimations.class, new BakedAnimationsAdapter()) - .create(); + .registerTypeAdapter(Bone.class, Bone.deserializer()) + .registerTypeAdapter(Cube.class, Cube.deserializer()) + .registerTypeAdapter(FaceUV.class, FaceUV.deserializer()) + .registerTypeAdapter(LocatorClass.class, LocatorClass.deserializer()) + .registerTypeAdapter(LocatorValue.class, LocatorValue.deserializer()) + .registerTypeAdapter(MinecraftGeometry.class, MinecraftGeometry.deserializer()) + .registerTypeAdapter(Model.class, Model.deserializer()) + .registerTypeAdapter(ModelProperties.class, ModelProperties.deserializer()) + .registerTypeAdapter(PolyMesh.class, PolyMesh.deserializer()) + .registerTypeAdapter(PolysUnion.class, PolysUnion.deserializer()) + .registerTypeAdapter(TextureMesh.class, TextureMesh.deserializer()) + .registerTypeAdapter(UVFaces.class, UVFaces.deserializer()) + .registerTypeAdapter(UVUnion.class, UVUnion.deserializer()) + // TODO: Remove + .registerTypeAdapter(Animation.Keyframes.class, new KeyFramesAdapter()) + // TODO: Remove + .registerTypeAdapter(BakedAnimations.class, new BakedAnimationsAdapter()) + .registerTypeAdapter(AzKeyframes.class, new AzKeyFramesAdapter()) + .registerTypeAdapter(AzBakedAnimations.class, new AzBakedAnimationsAdapter()) + .create(); /** * Convert a {@link JsonArray} of doubles to a {@code double[]}.
    diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 5926993dd..77dfc0a86 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -391,15 +391,17 @@ public boolean tryTriggerAnimation(String animName) { */ protected PlayState handleAnimationState(AzAnimationState state) { if (triggeredAnimation != null) { - if (currentRawAnimation != triggeredAnimation) + if (currentRawAnimation != triggeredAnimation) { this.currentAnimation = null; + } setAnimation(state.getAnimatable(), triggeredAnimation); if ( !hasAnimationFinished() && (!handlingTriggeredAnimations || stateHandler.handle(state) == PlayState.CONTINUE) - ) + ) { return PlayState.CONTINUE; + } this.triggeredAnimation = null; this.needsAnimationReload = true; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java new file mode 100644 index 000000000..05e67979d --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java @@ -0,0 +1,269 @@ +package mod.azure.azurelib.core2.animation.parse; + +import com.google.gson.*; +import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; +import mod.azure.azurelib.core.animation.EasingType; +import mod.azure.azurelib.core.keyframe.BoneAnimation; +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.keyframe.KeyframeStack; +import mod.azure.azurelib.core.math.Constant; +import mod.azure.azurelib.core.math.IValue; +import mod.azure.azurelib.core.molang.MolangException; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.expressions.MolangValue; +import mod.azure.azurelib.core2.animation.primitive.AzAnimation; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; +import mod.azure.azurelib.core2.animation.primitive.AzKeyframes; +import mod.azure.azurelib.core2.animation.primitive.AzLoopType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import org.apache.commons.lang3.math.NumberUtils; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +/** + * {@link com.google.gson.Gson} {@link JsonDeserializer} for {@link AzBakedAnimations}.
    + * Acts as the deserialization interface for {@code BakedAnimations} + */ +public class AzBakedAnimationsAdapter implements JsonDeserializer { + + private static List> getTripletObj(JsonElement element) { + if (element == null) + return List.of(); + + if (element instanceof JsonPrimitive primitive) { + JsonArray array = new JsonArray(3); + + array.add(primitive); + array.add(primitive); + array.add(primitive); + + element = array; + } + + if (element instanceof JsonArray array) + return ObjectArrayList.of(Pair.of("0", array)); + + if (element instanceof JsonObject obj) { + List> list = new ObjectArrayList<>(); + + for (Map.Entry entry : obj.entrySet()) { + if (entry.getValue() instanceof JsonObject entryObj && !entryObj.has("vector")) { + list.add(getTripletObjBedrock(entry.getKey(), entryObj)); + + continue; + } + + list.add(Pair.of(entry.getKey(), entry.getValue())); + } + + return list; + } + + throw new JsonParseException("Invalid object type provided to getTripletObj, got: " + element); + } + + private static Pair getTripletObjBedrock(String timestamp, JsonObject keyframe) { + JsonArray keyframeValues = null; + + if (keyframe.has("pre")) { + JsonElement pre = keyframe.get("pre"); + keyframeValues = pre.isJsonArray() ? pre.getAsJsonArray() : GsonHelper.getAsJsonArray(pre.getAsJsonObject(), "vector"); + } + else if (keyframe.has("post")) { + JsonElement post = keyframe.get("post"); + keyframeValues = post.isJsonArray() ? post.getAsJsonArray() : GsonHelper.getAsJsonArray(post.getAsJsonObject(), "vector"); + } + + if (keyframeValues != null) + return Pair.of(NumberUtils.isCreatable(timestamp) ? timestamp : "0", keyframeValues); + + throw new JsonParseException("Invalid keyframe data - expected array, found " + keyframe); + } + + private static double calculateAnimationLength(BoneAnimation[] boneAnimations) { + double length = 0; + + for (BoneAnimation animation : boneAnimations) { + length = Math.max(length, animation.rotationKeyFrames().getLastKeyframeTime()); + length = Math.max(length, animation.positionKeyFrames().getLastKeyframeTime()); + length = Math.max(length, animation.scaleKeyFrames().getLastKeyframeTime()); + } + + return length == 0 ? Double.MAX_VALUE : length; + } + + @Override + public AzBakedAnimations deserialize( + JsonElement json, + Type type, + JsonDeserializationContext context + ) throws JsonParseException { + JsonObject jsonObj = json.getAsJsonObject(); + + JsonObject animationJsonList = jsonObj.getAsJsonObject("animations"); + JsonArray includeListJSONObj = jsonObj.getAsJsonArray("includes"); + Map includes = null; + if (includeListJSONObj != null) { + includes = new Object2ObjectOpenHashMap<>(includeListJSONObj.size()); + for (JsonElement entry : includeListJSONObj.asList()) { + JsonObject obj = entry.getAsJsonObject(); + ResourceLocation fileId = ResourceLocation.parse(obj.get("file_id").getAsString()); + for (JsonElement animName : obj.getAsJsonArray("animations")) { + String ani = animName.getAsString(); + if (includes.containsKey(ani)) { + AzureLib.LOGGER.warn( + "Animation {} is already included! File already including: {} File trying to include from again: {}", + ani, + includes.get(ani), + fileId + ); + } else { + includes.put(ani, fileId); + } + } + } + } + + Map animations = new Object2ObjectOpenHashMap<>(animationJsonList.size()); + + for (Map.Entry entry : animationJsonList.entrySet()) { + try { + animations.put( + entry.getKey(), + bakeAnimation(entry.getKey(), entry.getValue().getAsJsonObject(), context) + ); + } catch (MolangException ex) { + AzureLib.LOGGER.error("Unable to parse animation: {}", entry.getKey()); + ex.printStackTrace(); + } + } + + return new AzBakedAnimations(animations, includes); + } + + private AzAnimation bakeAnimation( + String name, + JsonObject animationObj, + JsonDeserializationContext context + ) throws MolangException { + double length = animationObj.has("animation_length") + ? GsonHelper.getAsDouble(animationObj, "animation_length") * 20d + : -1; + AzLoopType loopType = AzLoopType.fromJson(animationObj.get("loop")); + BoneAnimation[] boneAnimations = bakeBoneAnimations( + GsonHelper.getAsJsonObject(animationObj, "bones", new JsonObject()) + ); + AzKeyframes keyframes = context.deserialize(animationObj, AzKeyframes.class); + + if (length == -1) + length = calculateAnimationLength(boneAnimations); + + return new AzAnimation(name, length, loopType, boneAnimations, keyframes); + } + + private BoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangException { + BoneAnimation[] animations = new BoneAnimation[bonesObj.size()]; + int index = 0; + + for (Map.Entry entry : bonesObj.entrySet()) { + JsonObject entryObj = entry.getValue().getAsJsonObject(); + KeyframeStack> scaleFrames = buildKeyframeStack( + getTripletObj(entryObj.get("scale")), + false + ); + KeyframeStack> positionFrames = buildKeyframeStack( + getTripletObj(entryObj.get("position")), + false + ); + KeyframeStack> rotationFrames = buildKeyframeStack( + getTripletObj(entryObj.get("rotation")), + true + ); + + animations[index] = new BoneAnimation(entry.getKey(), rotationFrames, positionFrames, scaleFrames); + index++; + } + + return animations; + } + + private KeyframeStack> buildKeyframeStack( + List> entries, + boolean isForRotation + ) throws MolangException { + if (entries.isEmpty()) + return new KeyframeStack<>(); + + List> xFrames = new ObjectArrayList<>(); + List> yFrames = new ObjectArrayList<>(); + List> zFrames = new ObjectArrayList<>(); + + IValue xPrev = null; + IValue yPrev = null; + IValue zPrev = null; + Pair prevEntry = null; + + for (Pair entry : entries) { + String key = entry.getFirst(); + JsonElement element = entry.getSecond(); + + if (key.equals("easing") || key.equals("easingArgs") || key.equals("lerp_mode")) + continue; + + double prevTime = prevEntry != null ? Double.parseDouble(prevEntry.getFirst()) : 0; + double curTime = NumberUtils.isCreatable(key) ? Double.parseDouble(entry.getFirst()) : 0; + double timeDelta = curTime - prevTime; + + JsonArray keyFrameVector = element instanceof JsonArray array + ? array + : GsonHelper.getAsJsonArray(element.getAsJsonObject(), "vector"); + MolangValue rawXValue = MolangParser.parseJson(keyFrameVector.get(0)); + MolangValue rawYValue = MolangParser.parseJson(keyFrameVector.get(1)); + MolangValue rawZValue = MolangParser.parseJson(keyFrameVector.get(2)); + IValue xValue = isForRotation && rawXValue.isConstant() + ? new Constant(Math.toRadians(-rawXValue.get())) + : rawXValue; + IValue yValue = isForRotation && rawYValue.isConstant() + ? new Constant(Math.toRadians(-rawYValue.get())) + : rawYValue; + IValue zValue = isForRotation && rawZValue.isConstant() + ? new Constant(Math.toRadians(rawZValue.get())) + : rawZValue; + + JsonObject entryObj = element instanceof JsonObject obj ? obj : null; + EasingType easingType = entryObj != null && entryObj.has("easing") + ? EasingType.fromJson(entryObj.get("easing")) + : EasingType.LINEAR; + List easingArgs = entryObj != null && entryObj.has("easingArgs") + ? JsonUtil.jsonArrayToList( + GsonHelper.getAsJsonArray(entryObj, "easingArgs"), + ele -> new Constant(ele.getAsDouble()) + ) + : new ObjectArrayList<>(); + + xFrames.add( + new Keyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) + ); + yFrames.add( + new Keyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) + ); + zFrames.add( + new Keyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) + ); + + xPrev = xValue; + yPrev = yValue; + zPrev = zValue; + prevEntry = entry; + } + + return new KeyframeStack<>(xFrames, yFrames, zFrames); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzKeyFramesAdapter.java b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzKeyFramesAdapter.java new file mode 100644 index 000000000..ddecd93d2 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzKeyFramesAdapter.java @@ -0,0 +1,112 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. + * Original source: https://github.com/bernie-g/geckolib + * Copyright © 2024 Bernie-G. + * Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation.parse; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; +import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; +import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; +import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; +import mod.azure.azurelib.core2.animation.primitive.AzKeyframes; +import net.minecraft.util.GsonHelper; + +import java.lang.reflect.Type; +import java.util.Map; + +/** + * {@link Gson} {@link JsonDeserializer} for {@link AzKeyframes}.
    + * Acts as the deserialization interface for {@code Keyframes} + */ +public class AzKeyFramesAdapter implements JsonDeserializer { + + private static SoundKeyframeData[] buildSoundFrameData(JsonObject rootObj) { + JsonObject soundsObj = GsonHelper.getAsJsonObject(rootObj, "sound_effects", new JsonObject()); + SoundKeyframeData[] sounds = new SoundKeyframeData[soundsObj.size()]; + int index = 0; + + for (Map.Entry entry : soundsObj.entrySet()) { + sounds[index] = new SoundKeyframeData( + Double.parseDouble(entry.getKey()) * 20d, + GsonHelper.getAsString(entry.getValue().getAsJsonObject(), "effect") + ); + index++; + } + + return sounds; + } + + private static ParticleKeyframeData[] buildParticleFrameData(JsonObject rootObj) { + JsonObject particlesObj = GsonHelper.getAsJsonObject(rootObj, "particle_effects", new JsonObject()); + ParticleKeyframeData[] particles = new ParticleKeyframeData[particlesObj.size()]; + int index = 0; + + for (Map.Entry entry : particlesObj.entrySet()) { + JsonObject obj = entry.getValue().getAsJsonObject(); + String effect = GsonHelper.getAsString(obj, "effect", ""); + String locator = GsonHelper.getAsString(obj, "locator", ""); + String script = GsonHelper.getAsString(obj, "pre_effect_script", ""); + + particles[index] = new ParticleKeyframeData( + Double.parseDouble(entry.getKey()) * 20d, + effect, + locator, + script + ); + index++; + } + + return particles; + } + + private static CustomInstructionKeyframeData[] buildCustomFrameData(JsonObject rootObj) { + JsonObject customInstructionsObj = GsonHelper.getAsJsonObject(rootObj, "timeline", new JsonObject()); + CustomInstructionKeyframeData[] customInstructions = new CustomInstructionKeyframeData[customInstructionsObj + .size()]; + int index = 0; + + for (Map.Entry entry : customInstructionsObj.entrySet()) { + String instructions = ""; + + if (entry.getValue() instanceof JsonArray array) { + instructions = JsonUtil.GEO_GSON.fromJson(array, ObjectArrayList.class).toString(); + } else if (entry.getValue() instanceof JsonPrimitive primitive) { + instructions = primitive.getAsString(); + } + + customInstructions[index] = new CustomInstructionKeyframeData( + Double.parseDouble(entry.getKey()) * 20d, + instructions + ); + index++; + } + + return customInstructions; + } + + @Override + public AzKeyframes deserialize( + JsonElement json, + Type type, + JsonDeserializationContext context + ) throws JsonParseException { + JsonObject obj = json.getAsJsonObject(); + SoundKeyframeData[] sounds = buildSoundFrameData(obj); + ParticleKeyframeData[] particles = buildParticleFrameData(obj); + CustomInstructionKeyframeData[] customInstructions = buildCustomFrameData(obj); + + return new AzKeyframes(sounds, particles, customInstructions); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index ffccc9343..087b5202d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -34,14 +34,27 @@ protected AzEntityRenderer(EntityRendererProvider.Context context) { this.azEntityRendererPipeline = new AzEntityRendererPipeline<>(this); this.renderLayers = new ObjectArrayList<>(); this.azAnimator = createAnimator(); + + if (azAnimator != null) { + azAnimator.registerControllers(azAnimator.getAnimationControllerContainer()); + } } protected abstract @NotNull ResourceLocation getModelLocation(T entity); + public void superRender(@NotNull T entity, float entityYaw, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource bufferSource, int packedLight) { + super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight); + } + @Override public void render(@NotNull T entity, float entityYaw, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource bufferSource, int packedLight) { var modelResourceLocation = getModelLocation(entity); var bakedGeoModel = AzBakedModelCache.getInstance().getNullable(modelResourceLocation); + + if (bakedGeoModel != null) { + azAnimator.getAnimationProcessor().setActiveModel(bakedGeoModel); + } + azEntityRendererPipeline.defaultRender(poseStack, bakedGeoModel, entity, bufferSource, null, null, entityYaw, partialTick, packedLight); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java index 403f8bd7f..d03c38bcf 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -339,7 +339,7 @@ public void renderRecursively( @Override public void renderFinal(PoseStack poseStack, T entity, AzBakedModel model, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay, int colour) { - azEntityRenderer.render(entity, 0, partialTick, poseStack, bufferSource, packedLight); + azEntityRenderer.superRender(entity, 0, partialTick, poseStack, bufferSource, packedLight); if (entity instanceof Mob mob) { var leashHolder = mob.getLeashHolder(); diff --git a/common/src/main/resources/assets/azurelib/animations/entity/drone.animation.json b/common/src/main/resources/assets/azurelib/animations/entity/drone.animation.json new file mode 100644 index 000000000..20370698a --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/entity/drone.animation.json @@ -0,0 +1,8542 @@ +{ + "format_version": "1.8.0", + "animations": { + "animation.idle": { + "loop": true, + "animation_length": 3, + "bones": { + "gTail1": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.625": { + "vector": [-23.44039, -5, 0] + }, + "1.5": { + "vector": [-25, 0, 0] + }, + "2.25": { + "vector": [-23.7887, 5.625, 0] + }, + "3.0": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail2": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail3": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail4": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail5": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail6": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail7": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail8": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.625": { + "vector": [24.58, -5, 0] + }, + "1.5": { + "vector": [27.5, 0, 0] + }, + "2.25": { + "vector": [27.5, 5, 0] + }, + "3.0": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail10": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + }, + "3.0": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail12": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.6667": { + "vector": [-22.5, 0, 0] + }, + "2.2917": { + "vector": [22.5, 0, 0] + }, + "3.0": { + "vector": [0, 0, 0] + } + } + }, + "gTailBlade": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.6667": { + "vector": [-22.5, 0, 0] + }, + "2.2917": { + "vector": [22.5, 0, 0] + }, + "3.0": { + "vector": [0, 0, 0] + } + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, -5] + }, + "3.0": { + "vector": [0, 0, 0] + } + } + }, + "gMain": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, -0.25, 0.75] + }, + "3.0": { + "vector": [0, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, -22.5, 0] + }, + "1.5": { + "vector": [-25, -22.5, 0] + }, + "3.0": { + "vector": [-22.5, -22.5, 0] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [2.5, 0, 0] + }, + "3.0": { + "vector": [0, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [20, 0, 0] + }, + "3.0": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, 22.5, 0] + }, + "1.5": { + "vector": [-25, 22.5, 0] + }, + "3.0": { + "vector": [-22.5, 22.5, 0] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [2.5, 0, 0] + }, + "3.0": { + "vector": [0, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [20, 0, 0] + }, + "3.0": { + "vector": [22.5, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [25, 0, 0] + }, + "3.0": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 5] + }, + "3.0": { + "vector": [0, 0, 0] + } + } + }, + "gHead": { + "rotation": { + "vector": [-22.5, 0, 0] + } + } + } + }, + "animation.walk": { + "loop": true, + "animation_length": 1.5, + "bones": { + "gTail1": { + "rotation": { + "0.0": { + "vector": [-22.5, 5, 0] + }, + "0.75": { + "vector": [-27.5, -5, 0] + }, + "1.5": { + "vector": [-22.5, 5, 0] + } + } + }, + "gTail2": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail3": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail4": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail5": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail6": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.125": { + "vector": [27.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail7": { + "rotation": { + "0.0": { + "vector": [22.56, 0.02, -0.55] + }, + "0.375": { + "vector": [22.5, 12.5, 0] + }, + "1.125": { + "vector": [22.62076, -12.45167, -1.10693] + }, + "1.5": { + "vector": [22.56, 0.02, -0.55] + } + } + }, + "gTail8": { + "rotation": { + "vector": [0.09875, -1.08122, -1.62112] + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [22.00137, 6.90486, -2.91722] + }, + "0.75": { + "vector": [22.67664, -7.14576, 2.26137] + }, + "1.5": { + "vector": [22.00137, 6.90486, -2.91722] + } + } + }, + "gTail10": { + "rotation": { + "0.0": { + "vector": [7.94668, 2.0727, 2.74317] + }, + "0.375": { + "vector": [15.18273, -1.37269, -0.82585] + }, + "0.75": { + "vector": [7.94668, 2.0727, 2.74317] + }, + "1.125": { + "vector": [15.21087, 0.96213, 1.42227] + }, + "1.5": { + "vector": [7.94668, 2.0727, 2.74317] + } + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.125": { + "vector": [-27.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail12": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTailBlade": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [3.98114, 0.103, -21.96874] + }, + "0.375": { + "vector": [-3.51886, 0.103, -21.96874] + }, + "0.75": { + "vector": [3.98114, 0.103, -21.96874] + }, + "1.125": { + "vector": [-3.51886, 0.103, -21.96874] + }, + "1.5": { + "vector": [3.98114, 0.103, -21.96874] + } + } + }, + "gMain": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [0, 1.5, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.125": { + "vector": [0, 1.5, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [45, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.375": { + "vector": [-21.09, 0, 0] + }, + "0.75": { + "vector": [-50, 0, 0] + }, + "1.125": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.375": { + "vector": [14.06, 0, 0] + }, + "0.75": { + "vector": [30, 0, 0] + }, + "1.125": { + "vector": [-56.25, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gLeftFoot": { + "rotation": { + "0.0": { + "vector": [1.94, 0, 0] + }, + "0.1667": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "0.9583": { + "vector": [75.01, 0, 0] + }, + "1.125": { + "vector": [75.01, 0, 0] + }, + "1.4167": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [1.94, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0.70711, -0.70711] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.125": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0.70711, -0.70711] + } + } + }, + "gLeftRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [-12.5, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.9583": { + "vector": [-58.12, 0, 0] + }, + "1.125": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftMiddleToe": { + "rotation": { + "0.375": { + "vector": [-12.5, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.9583": { + "vector": [-54.38, 0, 0] + }, + "1.125": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [45, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.5": { + "vector": [45, 0, 0] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [-50, 0, 0] + }, + "0.375": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.125": { + "vector": [-21.09, 0, 0] + }, + "1.5": { + "vector": [-50, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [30, 0, 0] + }, + "0.375": { + "vector": [-56.25, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.125": { + "vector": [14.06, 0, 0] + }, + "1.5": { + "vector": [30, 0, 0] + } + } + }, + "gRightFoot": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.2083": { + "vector": [75.01, 0, 0] + }, + "0.375": { + "vector": [75.01, 0, 0] + }, + "0.6667": { + "vector": [0, 0, 0] + }, + "0.9167": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0.70711, -0.70711] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2083": { + "vector": [-54.38, 0, 0] + }, + "0.375": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.125": { + "vector": [-12.5, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightMiddleToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2083": { + "vector": [-54.38, 0, 0] + }, + "0.375": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.125": { + "vector": [-12.5, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.375": { + "vector": [30, 0, 0] + }, + "0.5833": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.125": { + "vector": [30, 0, 0] + }, + "1.3333": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gChest": { + "rotation": { + "0.0": { + "vector": [30, 0, 0] + }, + "0.5": { + "vector": [27.5, 0, 0] + }, + "0.75": { + "vector": [30, 0, 0] + }, + "0.9167": { + "vector": [32.5, 0, 0] + }, + "1.25": { + "vector": [27.5, 0, 0] + }, + "1.5": { + "vector": [30, 0, 0] + } + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [3.98114, -0.103, 21.96874] + }, + "0.375": { + "vector": [-16.01886, -0.103, 21.96874] + }, + "0.75": { + "vector": [3.98114, -0.103, 21.96874] + }, + "1.125": { + "vector": [-16.01886, -0.103, 21.96874] + }, + "1.5": { + "vector": [3.98114, -0.103, 21.96874] + } + } + }, + "gRightFobackm": { + "rotation": { + "0.0": { + "vector": [-52.5, 0, 0] + }, + "0.375": { + "vector": [-40, 0, 0] + }, + "0.75": { + "vector": [-52.5, 0, 0] + }, + "1.125": { + "vector": [-40, 0, 0] + }, + "1.5": { + "vector": [-52.5, 0, 0] + } + } + }, + "gLeftFobackm": { + "rotation": { + "0.0": { + "vector": [-52.5, 0, 0] + }, + "0.3333": { + "vector": [-40.94, 0, 0] + }, + "0.75": { + "vector": [-52.5, 0, 0] + }, + "1.125": { + "vector": [-40.94, 0, 0] + }, + "1.5": { + "vector": [-52.5, 0, 0] + } + } + }, + "gNeck": { + "rotation": { + "0.0": { + "vector": [5.81, 0, 0] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [7.5, 0, 0] + }, + "1.125": { + "vector": [0, 0, 0] + }, + "1.3333": { + "vector": [7.5, 0, 0] + }, + "1.5": { + "vector": [5.81, 0, 0] + } + } + }, + "gHead": { + "rotation": { + "vector": [-45, 0, 0] + } + } + } + }, + "animation.run": { + "loop": true, + "animation_length": 0.8333, + "bones": { + "gTail1": { + "rotation": { + "0.0": { + "vector": [-22.5, 5, 0] + }, + "0.4167": { + "vector": [-19.97168, -4.95712, -0.65426] + }, + "0.8333": { + "vector": [-22.5, 5, 0] + } + } + }, + "gTail2": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail3": { + "rotation": { + "vector": [-0.09877, -1.61925, 1.08401] + } + }, + "gTail4": { + "rotation": { + "vector": [0.06815, 1.62083, -1.08165] + } + }, + "gTail5": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail6": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.4167": { + "vector": [22.5, 0, 0] + }, + "0.625": { + "vector": [27.5, 0, 0] + }, + "0.8333": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail7": { + "rotation": { + "0.0": { + "vector": [22.56, 0.02, -0.55] + }, + "0.2083": { + "vector": [22.5, 12.5, 0] + }, + "0.625": { + "vector": [22.62076, -12.45167, -1.10693] + }, + "0.8333": { + "vector": [22.56, 0.02, -0.55] + } + } + }, + "gTail8": { + "rotation": { + "vector": [0.09875, -1.08122, -1.62112] + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [9.57541, 5.16185, -4.95938] + }, + "0.4167": { + "vector": [10.17524, -6.48267, 5.07063] + }, + "0.8333": { + "vector": [9.57541, 5.16185, -4.95938] + } + } + }, + "gTail10": { + "rotation": { + "0.0": { + "vector": [-14.112, -1.47943, -0.07609] + }, + "0.2083": { + "vector": [-6.76142, -5.32776, -2.85234] + }, + "0.4167": { + "vector": [-13.75126, 6.29346, 5.68347] + }, + "0.625": { + "vector": [-6.49299, 4.01286, 5.68655] + }, + "0.8333": { + "vector": [-14.112, -1.47943, -0.07609] + } + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.4167": { + "vector": [-22.5, 0, 0] + }, + "0.625": { + "vector": [-27.5, 0, 0] + }, + "0.8333": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail12": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTailBlade": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [-39.87592, 15.90951, 8.46625] + }, + "0.2083": { + "vector": [-46.9554, 7.60476, 12.16527] + }, + "0.4167": { + "vector": [-39.87592, 15.90951, 8.46625] + }, + "0.625": { + "vector": [-46.64536, 12.28238, 13.95907] + }, + "0.8333": { + "vector": [-39.87592, 15.90951, 8.46625] + } + } + }, + "gMain": { + "position": { + "0.0": { + "vector": [0, 4.5, 0] + }, + "0.2083": { + "vector": [0, 3.5, 0] + }, + "0.4167": { + "vector": [0, 4.5, 0] + }, + "0.625": { + "vector": [0, 3.5, 0] + }, + "0.8333": { + "vector": [0, 4.5, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.4167": { + "vector": [67.5, 0, 0] + }, + "0.8333": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.4167": { + "vector": [-50, 0, 0] + }, + "0.625": { + "vector": [42.5, 0, 0] + }, + "0.8333": { + "vector": [-45, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [45, 0, 0] + }, + "0.4167": { + "vector": [30, 0, 0] + }, + "0.625": { + "vector": [-30, 0, 0] + }, + "0.8333": { + "vector": [45, 0, 0] + } + } + }, + "gLeftFoot": { + "rotation": { + "0.0": { + "vector": [45, 0, 0] + }, + "0.2083": { + "vector": [0, 0, 0] + }, + "0.625": { + "vector": [45, 0, 0] + }, + "0.8333": { + "vector": [45, 0, 0] + } + } + }, + "gLeftRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2083": { + "vector": [-32.49095, -0.42056, -2.46439] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.625": { + "vector": [26.56104, -0.06932, 0.30472] + }, + "0.8333": { + "vector": [0, 0, 0] + } + } + }, + "gLeftMiddleToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2083": { + "vector": [-32.49095, -0.42056, -2.46439] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.625": { + "vector": [26.56104, -0.06932, 0.30472] + }, + "0.8333": { + "vector": [0, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [67.5, 0, 0] + }, + "0.4167": { + "vector": [-22.5, 0, 0] + }, + "0.8333": { + "vector": [67.5, 0, 0] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [-50, 0, 0] + }, + "0.2083": { + "vector": [42.5, 0, 0] + }, + "0.4167": { + "vector": [-45, 0, 0] + }, + "0.8333": { + "vector": [-50, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [30, 0, 0] + }, + "0.2083": { + "vector": [-30, 0, 0] + }, + "0.4167": { + "vector": [45, 0, 0] + }, + "0.8333": { + "vector": [30, 0, 0] + } + } + }, + "gRightFoot": { + "rotation": { + "0.0": { + "vector": [19.69, 0, 0] + }, + "0.2083": { + "vector": [45, 0, 0] + }, + "0.4167": { + "vector": [45, 0, 0] + }, + "0.625": { + "vector": [0, 0, 0] + }, + "0.8333": { + "vector": [19.69, 0, 0] + } + }, + "position": { + "vector": [0, 0, 0] + } + }, + "gRightRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2083": { + "vector": [26.56104, -0.06932, 0.30472] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.625": { + "vector": [-32.49095, -0.42056, -2.46439] + }, + "0.8333": { + "vector": [0, 0, 0] + } + } + }, + "gRightMiddleToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2083": { + "vector": [26.5625, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.625": { + "vector": [-32.5, 0, 0] + }, + "0.8333": { + "vector": [0, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [25.74, 0, 0] + }, + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [27.5, 0, 0] + }, + "0.5417": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [27.5, 0, 0] + }, + "0.8333": { + "vector": [25.74, 0, 0] + } + } + }, + "gChest": { + "rotation": { + "vector": [30, 0, 0] + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [-39.87592, -15.90951, -8.46625] + }, + "0.2083": { + "vector": [-46.9554, -7.60476, -12.16527] + }, + "0.4167": { + "vector": [-39.87592, -15.90951, -8.46625] + }, + "0.625": { + "vector": [-46.9554, -7.60476, -12.16527] + }, + "0.8333": { + "vector": [-39.87592, -15.90951, -8.46625] + } + } + }, + "gRightFobackm": { + "rotation": { + "0.0": { + "vector": [-45.21643, 10.80088, 11.80009] + }, + "0.2083": { + "vector": [-35.23275, -2.94442, 9.87563] + }, + "0.4167": { + "vector": [-45.21643, 10.80088, 11.80009] + }, + "0.625": { + "vector": [-35.23275, -2.94442, 9.87563] + }, + "0.8333": { + "vector": [-45.21643, 10.80088, 11.80009] + } + } + }, + "gLeftFobackm": { + "rotation": { + "0.0": { + "vector": [-45.21643, -10.80088, -11.80009] + }, + "0.2083": { + "vector": [-35.23275, 2.94442, -9.87563] + }, + "0.4167": { + "vector": [-45.21643, -10.80088, -11.80009] + }, + "0.625": { + "vector": [-35.23275, 2.94442, -9.87563] + }, + "0.8333": { + "vector": [-45.21643, -10.80088, -11.80009] + } + } + }, + "gNeck": { + "rotation": { + "0.0": { + "vector": [3.31, 0, 0] + }, + "0.2083": { + "vector": [-1.69, 0, 0] + }, + "0.4167": { + "vector": [3.31, 0, 0] + }, + "0.625": { + "vector": [-1.69, 0, 0] + }, + "0.8333": { + "vector": [3.31, 0, 0] + } + } + }, + "gHead": { + "rotation": { + "vector": [-45, 0, 0] + } + }, + "gRightBicep": { + "rotation": { + "vector": [22.49921, 0.15864, 0.13934] + } + }, + "gLeftBicep": { + "rotation": { + "vector": [22.49921, -0.15864, -0.13934] + } + } + } + }, + "animation.sprint": { + "loop": true, + "animation_length": 0.5, + "bones": { + "gMain": { + "rotation": { + "0.0": { + "vector": [97.5, 0, 0] + }, + "0.25": { + "vector": [72.5, 0, 0] + }, + "0.5": { + "vector": [97.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [0, 3, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gChest": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gNeck": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gHead": { + "rotation": { + "vector": [-45, 0, 0] + } + }, + "gTail1": { + "rotation": { + "0.0": { + "vector": [-54.76, 0, 0] + }, + "0.1667": { + "vector": [-66.00918, 0, 0] + }, + "0.3333": { + "vector": [-43.50918, 0, 0] + }, + "0.5": { + "vector": [-54.76, 0, 0] + } + } + }, + "gTail2": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail5": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [22.8118, 0, 3.86032] + }, + "0.3333": { + "vector": [-22.81179, 0, -3.86032] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [-7.59, 0, 0] + }, + "0.1667": { + "vector": [22.5, 0, 0] + }, + "0.4167": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-7.59, 0, 0] + } + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [-7.59, 0, 0] + }, + "0.1667": { + "vector": [22.5, 0, 0] + }, + "0.4167": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-7.59, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-90, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [-67.5, 0, 0] + }, + "0.1667": { + "vector": [55, 0, 0] + }, + "0.25": { + "vector": [67.5, 0, 0] + }, + "0.5": { + "vector": [-67.5, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [45, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [45, 0, 0] + } + } + }, + "gLeftFoot": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [45, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [-28.12, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftRingToe": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + } + } + }, + "gLeftMiddleToe": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [10, 0, 0] + }, + "0.0417": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [-90, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [10, 0, 0] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [-15.47, 0, 0] + }, + "0.0833": { + "vector": [55, 0, 0] + }, + "0.1667": { + "vector": [67.5, 0, 0] + }, + "0.25": { + "vector": [49, 0, 0] + }, + "0.4167": { + "vector": [-67.5, 0, 0] + }, + "0.5": { + "vector": [-15.47, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [21.67, 0, 0] + }, + "0.1667": { + "vector": [-45, 0, 0] + }, + "0.25": { + "vector": [-44.91, 0, 0] + }, + "0.4167": { + "vector": [45, 0, 0] + }, + "0.5": { + "vector": [21.67, 0, 0] + } + } + }, + "gRightFoot": { + "rotation": { + "0.0": { + "vector": [36.04, 0, 0] + }, + "0.0417": { + "vector": [45, 0, 0] + }, + "0.1667": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-1.04, 0, 0] + }, + "0.2917": { + "vector": [-28.12, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [36.04, 0, 0] + } + } + }, + "gRightRingToe": { + "rotation": { + "0.0": { + "vector": [2.5, 0, 0] + }, + "0.0417": { + "vector": [22.5, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [2.5, 0, 0] + } + } + }, + "gRightMiddleToe": { + "rotation": { + "0.0": { + "vector": [2.5, 0, 0] + }, + "0.0417": { + "vector": [22.5, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [2.5, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [10, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [-66.09, 0, 0] + }, + "0.0833": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.4167": { + "vector": [-112.5, 0, 0] + }, + "0.5": { + "vector": [-66.09, 0, 0] + } + } + }, + "gRightBicep": { + "rotation": { + "vector": [0, 0, -22.5] + }, + "position": { + "0.0": { + "vector": [0, 0.98793, 0.15488] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0.98793, 0.15488] + } + } + }, + "gRightFobackm": { + "rotation": { + "0.0": { + "vector": [-8.44, 0, 0] + }, + "0.0833": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [-135, 0, 0] + }, + "0.4167": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-8.44, 0, 0] + } + } + }, + "gRightHand": { + "rotation": { + "0.0": { + "vector": [-74.21307, -5.94383, 108.55723] + }, + "0.0833": { + "vector": [-92.36985, -17.4059, 121.53219] + }, + "0.1667": { + "vector": [0, -90, 22.5] + }, + "0.2917": { + "vector": [74.67899, -32.65931, -61.53967] + }, + "0.4167": { + "vector": [0, -90, 22.5] + }, + "0.5": { + "vector": [-74.21307, -5.94383, 108.55723] + } + } + }, + "gRightIndex": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.0833": { + "vector": [0, 0, 22.5] + }, + "0.1667": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [0, 0, -22.5] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightRing": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.0833": { + "vector": [0, 0, 22.5] + }, + "0.1667": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [0, 0, -22.5] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [-112.5, 0, 0] + }, + "0.1667": { + "vector": [0, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [-112.5, 0, 0] + } + } + }, + "gLeftBicep": { + "rotation": { + "vector": [0, 0, 22.5] + } + }, + "gLeftFobackm": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.1667": { + "vector": [-22.5, 0, 0] + }, + "0.3333": { + "vector": [-135, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0.76714, 0.64148] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftHand": { + "rotation": { + "0.0": { + "vector": [0, 90, -22.5] + }, + "0.0833": { + "vector": [-74.21307, 5.94383, -108.55723] + }, + "0.1667": { + "vector": [-92.36985, 17.4059, -121.53219] + }, + "0.25": { + "vector": [0, 90, -22.5] + }, + "0.375": { + "vector": [74.67899, 32.65931, 61.53967] + }, + "0.5": { + "vector": [0, 90, -22.5] + } + } + }, + "gLeftIndex": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.0833": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [0, 0, 22.5] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftRing": { + "rotation": { + "0.0833": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [0, 0, 22.5] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "root": { + "position": { + "vector": [0, -8, 0] + } + } + } + }, + "animation.crawl": { + "loop": true, + "animation_length": 0.5833, + "bones": { + "gMain": { + "rotation": { + "0.0": { + "vector": [105, 0, 0] + }, + "0.125": { + "vector": [110, 0, 0] + }, + "0.2917": { + "vector": [105, 0, 0] + }, + "0.4167": { + "vector": [110, 0, 0] + }, + "0.5833": { + "vector": [105, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 2, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [0, 2, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gChest": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 22.5] + }, + "0.2917": { + "vector": [-22.5, 0, -22.5] + }, + "0.5833": { + "vector": [-22.5, 0, 22.5] + } + } + }, + "gNeck": { + "rotation": { + "0.0": { + "vector": [-20.94102, -8.42106, -20.94102] + }, + "0.125": { + "vector": [-22.94102, -1.79224, -4.45684] + }, + "0.2917": { + "vector": [-20.94102, 8.42106, 20.94102] + }, + "0.4167": { + "vector": [-22.69612, 1.86439, 4.63625] + }, + "0.5833": { + "vector": [-20.94102, -8.42106, -20.94102] + } + } + }, + "gHead": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.2917": { + "vector": [-45, 0, 0] + }, + "0.5833": { + "vector": [-45, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [-59.93173, -20.97487, 14.79608] + }, + "0.2917": { + "vector": [-37.86119, -40.78947, 20.94102] + }, + "0.4167": { + "vector": [-31.99892, -66.16033, 6.38527] + }, + "0.5833": { + "vector": [-59.93173, -20.97487, 14.79608] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [67.5, 0, 0] + }, + "0.2917": { + "vector": [-45, 0, 0] + }, + "0.5833": { + "vector": [67.5, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.1667": { + "vector": [32.08, 0, 0] + }, + "0.2917": { + "vector": [45, 0, 0] + }, + "0.5833": { + "vector": [-45, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [-37.86119, 40.78947, -20.94102] + }, + "0.125": { + "vector": [-31.99892, 66.16033, -6.38527] + }, + "0.2917": { + "vector": [-59.93173, 20.97487, -14.79608] + }, + "0.5833": { + "vector": [-37.86119, 40.78947, -20.94102] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.2917": { + "vector": [67.5, 0, 0] + }, + "0.5833": { + "vector": [-45, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [45, 0, 0] + }, + "0.2917": { + "vector": [-45, 0, 0] + }, + "0.4583": { + "vector": [32.08, 0, 0] + }, + "0.5833": { + "vector": [45, 0, 0] + } + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [19.23707, 0.01241, 134.84633] + }, + "0.125": { + "vector": [0.41212, 2.83864, 6.94076] + }, + "0.2083": { + "vector": [-6.03777, 9.98908, 14.50115] + }, + "0.2917": { + "vector": [-0.64233, 3.16479, 17.05953] + }, + "0.4167": { + "vector": [56.92125, -8.90482, 117.4302] + }, + "0.5833": { + "vector": [26.73707, 0.01241, 134.84633] + } + } + }, + "gRightFobackm": { + "rotation": { + "0.0": { + "vector": [22.5, 90, 0] + }, + "0.125": { + "vector": [-87.58639, 38.00913, 26.13474] + }, + "0.25": { + "vector": [31.70923, 84.28653, 47.47645] + }, + "0.2917": { + "vector": [22.5, 90, 0] + }, + "0.4167": { + "vector": [-73.30379, -23.6878, -104.128] + }, + "0.5833": { + "vector": [22.5, 90, 0] + } + } + }, + "gRightHand": { + "rotation": { + "0.0": { + "vector": [0, 0, 22.5] + }, + "0.125": { + "vector": [0, 0, 67.5] + }, + "0.2917": { + "vector": [0, -90, 22.5] + }, + "0.4167": { + "vector": [48.38543, -17.20661, -58.40199] + }, + "0.5833": { + "vector": [0, 0, 22.5] + } + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, -4] + }, + "0.125": { + "vector": [67.27073, -11.10192, -117.63224] + }, + "0.2917": { + "vector": [19.23707, -0.01241, -134.84633] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [-2.41314, -15.32347, -18.2924] + }, + "0.5833": { + "vector": [0, 0, -10] + } + } + }, + "gLeftFobackm": { + "rotation": { + "0.0": { + "vector": [22.5, -90, 0] + }, + "0.125": { + "vector": [-73.30379, 23.6878, 104.128] + }, + "0.2917": { + "vector": [22.5, -90, 0] + }, + "0.4167": { + "vector": [-90, -45, -22.5] + }, + "0.5833": { + "vector": [22.5, -90, 0] + } + } + }, + "gLeftHand": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0, 33.75] + }, + "0.2917": { + "vector": [0, 0, -45] + } + } + }, + "root": { + "position": { + "0.0": { + "vector": [0, -13, 0] + }, + "0.2917": { + "vector": [0, -13, 0] + }, + "0.5833": { + "vector": [0, -13, 0] + } + } + }, + "gWaist": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-22.5, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [-22.5, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [2.5, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [2.5, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gRightBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.2083": { + "vector": [42.73421, -58.60029, -47.26579] + }, + "0.2917": { + "vector": [-22.5, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gLeftBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [42.73421, 58.60029, 47.26579] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gTail1": { + "rotation": { + "0.0": { + "vector": [-43.51, 0.99, 4.59] + }, + "0.1667": { + "vector": [-43.50918, 5.5939, 25.82476] + }, + "0.4167": { + "vector": [-43.50918, -5.5939, -25.82476] + }, + "0.5833": { + "vector": [-43.51, 0.99, 4.59] + } + } + }, + "gTail2": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail5": { + "rotation": { + "0.0": { + "vector": [-22.81, -1.64, 0.69] + }, + "0.1667": { + "vector": [-22.81179, -9.23186, 3.86032] + }, + "0.4167": { + "vector": [-22.81179, 9.23186, -3.86032] + }, + "0.5833": { + "vector": [-22.81, -1.64, 0.69] + } + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [0, 45, 0] + }, + "0.2917": { + "vector": [0, -45, 0] + }, + "0.5833": { + "vector": [0, 45, 0] + } + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [0, 45, 0] + }, + "0.2917": { + "vector": [0, -45, 0] + }, + "0.5833": { + "vector": [0, 45, 0] + } + } + }, + "gLeftFoot": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [-45, 0, 0] + }, + "0.2917": { + "vector": [0, -45, 0] + }, + "0.4167": { + "vector": [67.5, 0, 0] + }, + "0.5833": { + "vector": [22.5, 0, 0] + } + } + }, + "gLeftRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-45, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gLeftMiddleToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-45, 0, 0] + }, + "0.2917": { + "vector": [-45, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gLeftIndexToe": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.2917": { + "vector": [-22.5, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [-22.5, 0, 0] + } + } + }, + "gRightFoot": { + "rotation": { + "0.0": { + "vector": [0, 45, 0] + }, + "0.125": { + "vector": [45, 0, 0] + }, + "0.2917": { + "vector": [45, 0, 0] + }, + "0.4583": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 45, 0] + } + } + }, + "gRightRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [-67.5, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gRightMiddleToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [-67.5, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gRightIndex": { + "rotation": { + "0.0": { + "vector": [0, 0, 22.5] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + } + } + }, + "gRightRing": { + "rotation": { + "0.0": { + "vector": [0, 0, 22.5] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + } + } + }, + "gLeftUpperDorsalTube": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [0, 22.5, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gRightUpperDorsalTube": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, -22.5, 0] + } + } + }, + "gBackSpike": { + "rotation": { + "vector": [-38, 0, 0] + }, + "position": { + "vector": [-0.12813, -1.58338, -0.67941] + } + } + } + }, + " animation.crawlup": { + "loop": true, + "animation_length": 0.5833, + "bones": { + "gMain": { + "rotation": { + "0.0": { + "vector": [105, 0, 0] + }, + "0.125": { + "vector": [110, 0, 0] + }, + "0.2917": { + "vector": [105, 0, 0] + }, + "0.4167": { + "vector": [110, 0, 0] + }, + "0.5833": { + "vector": [105, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 2, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [0, 2, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gChest": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 22.5] + }, + "0.2917": { + "vector": [-22.5, 0, -22.5] + }, + "0.5833": { + "vector": [-22.5, 0, 22.5] + } + } + }, + "gNeck": { + "rotation": { + "0.0": { + "vector": [-20.94102, -8.42106, -20.94102] + }, + "0.125": { + "vector": [-22.94102, -1.79224, -4.45684] + }, + "0.2917": { + "vector": [-20.94102, 8.42106, 20.94102] + }, + "0.4167": { + "vector": [-22.69612, 1.86439, 4.63625] + }, + "0.5833": { + "vector": [-20.94102, -8.42106, -20.94102] + } + } + }, + "gHead": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.2917": { + "vector": [-45, 0, 0] + }, + "0.5833": { + "vector": [-45, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [-59.93173, -20.97487, 14.79608] + }, + "0.2917": { + "vector": [-37.86119, -40.78947, 20.94102] + }, + "0.4167": { + "vector": [-31.99892, -66.16033, 6.38527] + }, + "0.5833": { + "vector": [-59.93173, -20.97487, 14.79608] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [67.5, 0, 0] + }, + "0.2917": { + "vector": [-45, 0, 0] + }, + "0.5833": { + "vector": [67.5, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.1667": { + "vector": [32.08, 0, 0] + }, + "0.2917": { + "vector": [45, 0, 0] + }, + "0.5833": { + "vector": [-45, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [-37.86119, 40.78947, -20.94102] + }, + "0.125": { + "vector": [-31.99892, 66.16033, -6.38527] + }, + "0.2917": { + "vector": [-59.93173, 20.97487, -14.79608] + }, + "0.5833": { + "vector": [-37.86119, 40.78947, -20.94102] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.2917": { + "vector": [67.5, 0, 0] + }, + "0.5833": { + "vector": [-45, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [45, 0, 0] + }, + "0.2917": { + "vector": [-45, 0, 0] + }, + "0.4583": { + "vector": [32.08, 0, 0] + }, + "0.5833": { + "vector": [45, 0, 0] + } + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [19.23707, 0.01241, 134.84633] + }, + "0.125": { + "vector": [0.41212, 2.83864, 6.94076] + }, + "0.2083": { + "vector": [-6.03777, 9.98908, 14.50115] + }, + "0.2917": { + "vector": [-0.64233, 3.16479, 17.05953] + }, + "0.4167": { + "vector": [56.92125, -8.90482, 117.4302] + }, + "0.5833": { + "vector": [26.73707, 0.01241, 134.84633] + } + } + }, + "gRightFobackm": { + "rotation": { + "0.0": { + "vector": [22.5, 90, 0] + }, + "0.125": { + "vector": [-87.58639, 38.00913, 26.13474] + }, + "0.25": { + "vector": [31.70923, 84.28653, 47.47645] + }, + "0.2917": { + "vector": [22.5, 90, 0] + }, + "0.4167": { + "vector": [-73.30379, -23.6878, -104.128] + }, + "0.5833": { + "vector": [22.5, 90, 0] + } + } + }, + "gRightHand": { + "rotation": { + "0.0": { + "vector": [0, 0, 22.5] + }, + "0.125": { + "vector": [0, 0, 67.5] + }, + "0.2917": { + "vector": [0, -90, 22.5] + }, + "0.4167": { + "vector": [48.38543, -17.20661, -58.40199] + }, + "0.5833": { + "vector": [0, 0, 22.5] + } + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, -4] + }, + "0.125": { + "vector": [67.27073, -11.10192, -117.63224] + }, + "0.2917": { + "vector": [19.23707, -0.01241, -134.84633] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [-2.41314, -15.32347, -18.2924] + }, + "0.5833": { + "vector": [0, 0, -10] + } + } + }, + "gLeftFobackm": { + "rotation": { + "0.0": { + "vector": [22.5, -90, 0] + }, + "0.125": { + "vector": [-73.30379, 23.6878, 104.128] + }, + "0.2917": { + "vector": [22.5, -90, 0] + }, + "0.4167": { + "vector": [-90, -45, -22.5] + }, + "0.5833": { + "vector": [22.5, -90, 0] + } + } + }, + "gLeftHand": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0, 33.75] + }, + "0.2917": { + "vector": [0, 0, -45] + } + } + }, + "root": { + "rotation": { + "vector": [-90, 0, 0] + }, + "position": { + "vector": [0, 3, 0] + } + }, + "gWaist": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-22.5, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [-22.5, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [2.5, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [2.5, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gRightBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.2083": { + "vector": [42.73421, -58.60029, -47.26579] + }, + "0.2917": { + "vector": [-22.5, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gLeftBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [42.73421, 58.60029, 47.26579] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gTail1": { + "rotation": { + "0.0": { + "vector": [-43.51, 0.99, 4.59] + }, + "0.1667": { + "vector": [-43.50918, 5.5939, 25.82476] + }, + "0.4167": { + "vector": [-43.50918, -5.5939, -25.82476] + }, + "0.5833": { + "vector": [-43.51, 0.99, 4.59] + } + } + }, + "gTail2": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail5": { + "rotation": { + "0.0": { + "vector": [-22.81, -1.64, 0.69] + }, + "0.1667": { + "vector": [-22.81179, -9.23186, 3.86032] + }, + "0.4167": { + "vector": [-22.81179, 9.23186, -3.86032] + }, + "0.5833": { + "vector": [-22.81, -1.64, 0.69] + } + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [0, 45, 0] + }, + "0.2917": { + "vector": [0, -45, 0] + }, + "0.5833": { + "vector": [0, 45, 0] + } + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [0, 45, 0] + }, + "0.2917": { + "vector": [0, -45, 0] + }, + "0.5833": { + "vector": [0, 45, 0] + } + } + }, + "gLeftFoot": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [-45, 0, 0] + }, + "0.2917": { + "vector": [0, -45, 0] + }, + "0.4167": { + "vector": [67.5, 0, 0] + }, + "0.5833": { + "vector": [22.5, 0, 0] + } + } + }, + "gLeftRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-45, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gLeftMiddleToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-45, 0, 0] + }, + "0.2917": { + "vector": [-45, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gLeftIndexToe": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.2917": { + "vector": [-22.5, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [-22.5, 0, 0] + } + } + }, + "gRightFoot": { + "rotation": { + "0.0": { + "vector": [0, 45, 0] + }, + "0.125": { + "vector": [45, 0, 0] + }, + "0.2917": { + "vector": [45, 0, 0] + }, + "0.4583": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 45, 0] + } + } + }, + "gRightRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [-67.5, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gRightMiddleToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [-67.5, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gRightIndex": { + "rotation": { + "0.0": { + "vector": [0, 0, 22.5] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + } + } + }, + "gRightRing": { + "rotation": { + "0.0": { + "vector": [0, 0, 22.5] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + } + } + }, + "gLeftUpperDorsalTube": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [0, 22.5, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gRightUpperDorsalTube": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, -22.5, 0] + } + } + }, + "gBackSpike": { + "rotation": { + "vector": [-38, 0, 0] + }, + "position": { + "vector": [-0.12813, -1.58338, -0.67941] + } + } + } + }, + "animation.jump": { + "animation_length": 1.8333, + "bones": { + "gTail1": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.1667": { + "vector": [0.78, 0, 0] + }, + "0.3333": { + "vector": [-22.5, 0, 0] + }, + "0.7917": { + "vector": [-35, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + }, + "1.8333": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail2": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.3333": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + }, + "1.8333": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail3": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.3333": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + }, + "1.8333": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail4": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.8333": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.8333": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail5": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.8333": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail6": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.8333": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail7": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.8333": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail8": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.8333": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.8333": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail10": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.8333": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.3333": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + }, + "1.8333": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail12": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.3333": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + }, + "1.8333": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTailBlade": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.3333": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + }, + "1.8333": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [-2.92, 1.29, -44.44] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [46.64867, -20.70481, -9.00717] + }, + "0.5": { + "vector": [-112.5, 0, 0] + }, + "0.8333": { + "vector": [-112.5, 0, 0] + }, + "1.0417": { + "vector": [1.64867, -20.70481, -9.00717] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.8333": { + "vector": [0, 0, 0] + } + } + }, + "gMain": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [0, -4.5, 0] + }, + "0.3333": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.8333": { + "vector": [0, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, -22.5, 0] + }, + "0.1667": { + "vector": [-46.41, -22.5, 0] + }, + "0.3333": { + "vector": [-22.5, -22.5, 0] + }, + "0.5": { + "vector": [0, -22.5, 0] + }, + "0.8333": { + "vector": [0, -22.5, 0] + }, + "1.25": { + "vector": [-22.5, -22.5, 0] + }, + "1.8333": { + "vector": [-22.5, -22.5, 0] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [47.81, 0, 0] + }, + "0.3333": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + }, + "0.8333": { + "vector": [-45, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.8333": { + "vector": [0, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [45, 0, 0] + }, + "0.8333": { + "vector": [45, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.8333": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, 22.5, 0] + }, + "0.1667": { + "vector": [-46.41, 22.5, 0] + }, + "0.3333": { + "vector": [-22.5, 22.5, 0] + }, + "0.5": { + "vector": [0, 22.5, 0] + }, + "0.8333": { + "vector": [0, 22.5, 0] + }, + "1.25": { + "vector": [-22.5, 22.5, 0] + }, + "1.8333": { + "vector": [-22.5, 22.5, 0] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [47.81, 0, 0] + }, + "0.3333": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + }, + "0.8333": { + "vector": [-45, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.8333": { + "vector": [0, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [45, 0, 0] + }, + "0.8333": { + "vector": [45, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.8333": { + "vector": [22.5, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.1667": { + "vector": [46.41, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.8333": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.8333": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [-2.92, -1.29, 44.44] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [46.64867, 20.70481, 9.00717] + }, + "0.5": { + "vector": [-112.5, 0, 0] + }, + "0.8333": { + "vector": [-112.5, 0, 0] + }, + "1.0417": { + "vector": [1.64867, 20.70481, 9.00717] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.8333": { + "vector": [0, 0, 0] + } + } + }, + "gHead": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.3333": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + }, + "1.8333": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftFoot": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [45, 0, 0] + }, + "0.8333": { + "vector": [45, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.8333": { + "vector": [0, 0, 0] + } + } + }, + "gRightFoot": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [45, 0, 0] + }, + "0.8333": { + "vector": [45, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.8333": { + "vector": [0, 0, 0] + } + } + }, + "gRightFobackm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [-112.5, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.8333": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [-67.7, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.8333": { + "vector": [0, 0, 0] + } + } + }, + "gLeftFobackm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [-112.5, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.8333": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [-67.7, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.8333": { + "vector": [0, 0, 0] + } + } + } + } + }, + "animation.land": { + "loop": "hold_on_last_frame", + "animation_length": 1.25, + "bones": { + "gTail1": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.3333": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail2": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail3": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail4": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail5": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail6": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail7": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.3333": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail8": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail9": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail10": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.3333": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail11": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail12": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTailBlade": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0, -45] + }, + "0.3333": { + "vector": [0, 0, -45] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gMain": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, -22.5, 0] + }, + "0.125": { + "vector": [-45, -22.5, 0] + }, + "0.3333": { + "vector": [-45, -22.5, 0] + }, + "0.75": { + "vector": [-22.5, -22.5, 0] + }, + "1.25": { + "vector": [-22.5, -22.5, 0] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [71.1, 0, 0] + }, + "0.3333": { + "vector": [71.1, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [-24.3, 0, 0] + }, + "0.3333": { + "vector": [-24.3, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, 22.5, 0] + }, + "0.125": { + "vector": [-45, 22.5, 0] + }, + "0.3333": { + "vector": [-45, 22.5, 0] + }, + "0.75": { + "vector": [-22.5, 22.5, 0] + }, + "1.25": { + "vector": [-22.5, 22.5, 0] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [71.1, 0, 0] + }, + "0.3333": { + "vector": [71.1, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [-24.3, 0, 0] + }, + "0.3333": { + "vector": [-24.3, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0, 45] + }, + "0.3333": { + "vector": [0, 0, 45] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gHead": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gRightFobackm": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "gLeftFobackm": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "gChest": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gBottomJawBase": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.3333": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "root": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, -7, 0] + }, + "0.3333": { + "vector": [0, -7, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + } + } + }, + "animation.swim": { + "loop": true, + "animation_length": 1.5, + "bones": { + "gMain": { + "rotation": { + "0.0": { + "vector": [86.5, 0, 0] + }, + "0.75": { + "vector": [93.5, 0, 0] + }, + "1.5": { + "vector": [86.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -5.5, 0] + }, + "0.375": { + "vector": [0, -5, 0] + }, + "1.125": { + "vector": [0, -6, 0] + }, + "1.5": { + "vector": [0, -5.5, 0] + } + } + }, + "gWaist": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [-3.5, 0, 0] + }, + "1.125": { + "vector": [3.5, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gTail1": { + "rotation": { + "0.0": { + "vector": [-90.5, 0, 0] + }, + "0.75": { + "vector": [-89.5, 0, 0] + }, + "1.5": { + "vector": [-90.5, 0, 0] + } + } + }, + "gTail2": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "gTail5": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [6.5, 0, 0] + }, + "1.0": { + "vector": [-7.5, 0, 0] + }, + "1.25": { + "vector": [-7.5, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [4.69, 0, 0] + }, + "0.25": { + "vector": [4.69, 0, 0] + }, + "0.75": { + "vector": [-7.5, 0, 0] + }, + "1.0": { + "vector": [-7.5, 0, 0] + }, + "1.5": { + "vector": [4.69, 0, 0] + } + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [-7.5, 0, 0] + }, + "0.5": { + "vector": [10, 0, 0] + }, + "0.75": { + "vector": [10, 0, 0] + }, + "1.25": { + "vector": [-7.5, 0, 0] + }, + "1.5": { + "vector": [-7.5, 0, 0] + } + } + }, + "gHead": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.75": { + "vector": [-52.5, 0, 0] + }, + "1.5": { + "vector": [-45, 0, 0] + } + } + }, + "gTail3": { + "rotation": { + "0.0": { + "vector": [7.22, 0, 0] + }, + "0.5": { + "vector": [-3.8, 0, 0] + }, + "0.75": { + "vector": [-3.8, 0, 0] + }, + "1.25": { + "vector": [7.22, 0, 0] + }, + "1.5": { + "vector": [7.22, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [12.5, 0, 0] + }, + "0.75": { + "vector": [-12.5, 0, 0] + }, + "1.5": { + "vector": [12.5, 0, 0] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.375": { + "vector": [-32.5, 0, 0] + }, + "0.75": { + "vector": [-45, 0, 0] + }, + "1.125": { + "vector": [-57.5, 0, 0] + }, + "1.5": { + "vector": [-45, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [67.5, 0, 0] + }, + "0.75": { + "vector": [67.5, 0, 0] + }, + "1.0": { + "vector": [67.5, 0, 0] + } + } + }, + "gLeftFoot": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [45, 0, 0] + }, + "1.125": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [-12.5, 0, 0] + }, + "0.75": { + "vector": [12.5, 0, 0] + }, + "1.5": { + "vector": [-12.5, 0, 0] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [-45, 0, 0] + }, + "0.375": { + "vector": [-57.5, 0, 0] + }, + "0.75": { + "vector": [-45, 0, 0] + }, + "1.125": { + "vector": [-32.5, 0, 0] + }, + "1.5": { + "vector": [-45, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "vector": [67.5, 0, 0] + } + }, + "gRightFoot": { + "rotation": { + "0.0": { + "vector": [45, 0, 0] + }, + "0.375": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [45, 0, 0] + } + } + }, + "gChest": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gRightShoulder": { + "rotation": { + "vector": [45, 0, 0] + } + }, + "gLeftShoulder": { + "rotation": { + "vector": [45, 0, 0] + } + }, + "gLeftFobackm": { + "rotation": { + "0.0": { + "vector": [-5, 0, 0] + }, + "0.75": { + "vector": [5, 0, 0] + }, + "1.125": { + "vector": [5, 0, 0] + }, + "1.5": { + "vector": [-5, 0, 0] + } + } + }, + "gNeck": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gBackSpike": { + "rotation": { + "vector": [-17, 0, 0] + }, + "position": { + "vector": [0, -2.1959, 0.13431] + } + } + } + }, + "animation.attackbite": { + "animation_length": 1.5, + "bones": { + "gTail1": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail2": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail3": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail4": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail5": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail6": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail7": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail8": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail9": { + "rotation": { + "vector": [22.5, 0, 0] + } + }, + "gTail10": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail11": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTail12": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gTailBlade": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-30.72806, -30.97162, 5.44503] + }, + "0.25": { + "vector": [-67.5, 0, 0] + }, + "0.9167": { + "vector": [-67.5, 0, 0] + }, + "1.0833": { + "vector": [-35.81228, -12.2752, 19.00401] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gMain": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 1.5, -8.5] + }, + "0.25": { + "vector": [0, 0, -17] + }, + "0.9167": { + "vector": [0, 0, -17] + }, + "1.0833": { + "vector": [0, 1.5, -8.5] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, -22.5, 0] + }, + "0.25": { + "vector": [58.53967, -8.01867, -12.88333] + }, + "0.9167": { + "vector": [58.53967, -8.01867, -12.88333] + }, + "1.25": { + "vector": [-22.5, -22.5, 0] + }, + "1.5": { + "vector": [-22.5, -22.5, 0] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-67.5, 0, 0] + }, + "0.625": { + "vector": [-79.81, 0, 0] + }, + "0.9167": { + "vector": [-67.5, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [45, 0, 0] + }, + "0.5833": { + "vector": [47.31, 0, 0] + }, + "0.9167": { + "vector": [45, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, 22.5, 0] + }, + "0.25": { + "vector": [-22.5, 22.5, 0] + }, + "0.9167": { + "vector": [-22.5, 22.5, 0] + }, + "1.25": { + "vector": [-22.5, 22.5, 0] + }, + "1.5": { + "vector": [-22.5, 22.5, 0] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.9167": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [45, 0, 0] + }, + "0.9167": { + "vector": [45, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-30.72806, 30.97162, -5.44503] + }, + "0.25": { + "vector": [-67.5, 0, 0] + }, + "0.9167": { + "vector": [-67.5, 0, 0] + }, + "1.0833": { + "vector": [-35.81228, 12.2752, -19.00401] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gHead": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftFoot": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0.10824, 0.98834, -0.10706] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + }, + "1.0833": { + "vector": [0.10824, 0.98834, -0.10706] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0] + }, + "0.9167": { + "vector": [-45, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftMiddleToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0] + }, + "0.9167": { + "vector": [-45, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftIndexToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.9167": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, -10] + }, + "0.9167": { + "vector": [0, 0, -10] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightFobackm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-64.69, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + }, + "1.0833": { + "vector": [-45, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 10] + }, + "0.9167": { + "vector": [0, 0, 10] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftFobackm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-64.69, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + }, + "1.0833": { + "vector": [-45, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gInnerJaw": { + "position": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [0, 0, -4] + }, + "0.5": { + "vector": [0, 0, -4] + }, + "0.625": { + "vector": [0, 0, 0] + } + } + }, + "gInnerJawEnd": { + "position": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, -4] + }, + "0.625": { + "vector": [0, 0, 0] + } + } + }, + "gTopInnerJaw": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gBottomInnerJaw": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [45, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gBottomJawBase": { + "rotation": { + "0.125": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [45, 0, 0] + }, + "0.6667": { + "vector": [45, 0, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + }, + "1.0833": { + "vector": [0, 0, 0] + } + } + }, + "gTopLip": { + "position": { + "0.125": { + "vector": [0, 0, 0] + }, + "0.2083": { + "vector": [0, 0.5, 0] + }, + "0.8333": { + "vector": [0, 0.5, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + } + } + }, + "gBottomLip": { + "position": { + "0.125": { + "vector": [0, 0, 0] + }, + "0.2083": { + "vector": [0, -0.2, 0] + }, + "0.8333": { + "vector": [0, -0.2, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + } + } + } + } + }, + "animation.attackclaw": { + "animation_length": 1.5, + "bones": { + "gTail1": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.1667": { + "vector": [-22.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail2": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.1667": { + "vector": [-22.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail3": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.1667": { + "vector": [-22.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail4": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.1667": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail5": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.1667": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail6": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.1667": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail7": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.1667": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail8": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.1667": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.1667": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail10": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.1667": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.1667": { + "vector": [-22.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail12": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.1667": { + "vector": [-22.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTailBlade": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.1667": { + "vector": [-22.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-30.72806, -30.97162, 5.44503] + }, + "0.25": { + "vector": [-1.64867, -20.70481, -58.49283] + }, + "0.5": { + "vector": [43.35133, -20.70481, -58.49283] + }, + "0.75": { + "vector": [-1.64867, -20.70481, -58.49283] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gMain": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 1.5, -8.5] + }, + "0.25": { + "vector": [0, 0, -17] + }, + "0.5": { + "vector": [0, 0, -17] + }, + "0.75": { + "vector": [0, 0, -14] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, -22.5, 0] + }, + "0.25": { + "vector": [-22.5, -22.5, 0] + }, + "0.5": { + "vector": [-22.5, -22.5, 0] + }, + "0.75": { + "vector": [-22.5, -22.5, 0] + }, + "1.1667": { + "vector": [-22.5, -22.5, 0] + }, + "1.5": { + "vector": [-22.5, -22.5, 0] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.9583": { + "vector": [22.5, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "0.9583": { + "vector": [-22.5, 0, 0] + }, + "1.1667": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, 22.5, 0] + }, + "0.25": { + "vector": [58.53967, 8.01867, 12.88333] + }, + "0.5": { + "vector": [58.54, 8.02, 12.88] + }, + "0.75": { + "vector": [58.53967, 8.01867, 12.88333] + }, + "1.1667": { + "vector": [-22.5, 22.5, 0] + }, + "1.5": { + "vector": [-22.5, 22.5, 0] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-67.5, 0, 0] + }, + "0.5": { + "vector": [-67.5, 0, 0] + }, + "0.75": { + "vector": [-67.5, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [45, 0, 0] + }, + "0.5": { + "vector": [45, 0, 0] + }, + "0.75": { + "vector": [45, 0, 0] + }, + "1.1667": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [32.5, 0, 0] + }, + "0.5": { + "vector": [32.5, 0, 0] + }, + "1.1667": { + "vector": [22.5, 0, 0] + }, + "1.5": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-75.73, 30.97, -5.45] + }, + "0.5": { + "vector": [-75.73, 30.97, -5.45] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gHead": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [-30.36119, -40.78947, 20.94102] + }, + "0.5": { + "vector": [-11.61255, 0.02318, 3.64772] + }, + "1.1667": { + "vector": [-22.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftFoot": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.0833": { + "vector": [67.5, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.0417": { + "vector": [67.5, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0.10824, 0.98834, -0.10706] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.9583": { + "vector": [0.10824, 0.98834, -0.10706] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.0833": { + "vector": [-45, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.0417": { + "vector": [-45, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftMiddleToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.0833": { + "vector": [-45, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.0417": { + "vector": [-45, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftIndexToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.0833": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 57.5] + }, + "0.5": { + "vector": [0, 0, -57.5] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightFobackm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-64.69, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.9583": { + "vector": [-45, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 10] + }, + "0.5": { + "vector": [0, 0, 10] + }, + "0.75": { + "vector": [0, 0, 10] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gLeftFobackm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-45, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gInnerJaw": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gInnerJawEnd": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gTopInnerJaw": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gBottomInnerJaw": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gBottomJawBase": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [45, 0, 0] + }, + "0.5": { + "vector": [45, 0, 0] + }, + "0.75": { + "vector": [45, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightFoot": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [-0.10824, 0.98834, -0.10706] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + }, + "0.75": { + "vector": [-45, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightMiddleToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + }, + "0.75": { + "vector": [-45, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightIndexToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gChest": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 45, 0] + }, + "0.5": { + "vector": [0, -45, 0] + }, + "1.1667": { + "vector": [0, 0, 0] + }, + "1.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightHand": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 22.5] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightThumb": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 45, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "gRightPinkyThumb": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -45, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "gRightIndex": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "gRightIndexEnd": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 45] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gRightRing": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "gRightRingEnd": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 45] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gNeck": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 5] + } + }, + "scale": { + "vector": [1, 1, 1] + } + }, + "gTopLip": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0.4, 0] + }, + "0.9167": { + "vector": [0, 0.4, 0] + }, + "1.0833": { + "vector": [0, 0, 0] + } + } + }, + "gBottomLip": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, -0.2, 0] + }, + "0.9167": { + "vector": [0, -0.2, 0] + }, + "1.0833": { + "vector": [0, 0, 0] + } + } + } + } + }, + "animation.attacktail": { + "animation_length": 1.25, + "bones": { + "gTail1": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.125": { + "vector": [-22.5, 22.5, 0] + }, + "0.25": { + "vector": [-28.8368, 42.85882, -11.52421] + }, + "0.375": { + "vector": [-28.84, 42.86, -11.52] + }, + "0.625": { + "vector": [-28.84, 42.86, -11.52] + }, + "0.875": { + "vector": [0, -45, 0] + }, + "1.125": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + }, + "1.375": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail2": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.125": { + "vector": [-22.5, 22.5, 0] + }, + "0.25": { + "vector": [-22.5, 22.5, 0] + }, + "0.5": { + "vector": [-32.83571, 49.30491, -17.06485] + }, + "0.75": { + "vector": [-32.83571, 49.30491, -17.06485] + }, + "1.0": { + "vector": [-21.22934, -12.47462, 13.80367] + }, + "1.25": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail3": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.125": { + "vector": [-22.5, 22.5, 0] + }, + "0.25": { + "vector": [-22.5, 22.5, 0] + }, + "0.75": { + "vector": [-22.5, 22.5, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail4": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [22.5, 22.5, 0] + }, + "0.25": { + "vector": [22.5, 22.5, 0] + }, + "0.5": { + "vector": [24.54658, 31.67414, 4.47838] + }, + "0.75": { + "vector": [24.54658, 31.67414, 4.47838] + }, + "1.0": { + "vector": [21.10223, 10.88682, -4.83841] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail5": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [22.5, 22.5, 0] + }, + "0.25": { + "vector": [20.71266, 1.54217, -8.42413] + }, + "0.375": { + "vector": [-22.49681, 22.49825, -16.84298] + }, + "0.625": { + "vector": [-22.49681, 22.49825, -16.84298] + }, + "0.75": { + "vector": [-22.49681, 22.49825, -16.84298] + }, + "1.0": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail6": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [22.5, 22.5, 0] + }, + "0.25": { + "vector": [22.02103, -19.44825, -16.67676] + }, + "0.375": { + "vector": [-20.71145, 1.54058, -24.93225] + }, + "0.625": { + "vector": [-20.71145, 1.54058, -24.93225] + }, + "0.75": { + "vector": [-20.71145, 1.54058, -24.93225] + }, + "1.0": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail7": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [22.5, 22.5, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.375": { + "vector": [-22.5, 0, 0] + }, + "0.625": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-24.14867, 20.70481, -9.00717] + }, + "1.0": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail8": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [22.5, 22.5, 0] + }, + "0.25": { + "vector": [24.14867, -20.70481, -9.00717] + }, + "0.375": { + "vector": [-24.15153, 20.709, -27.02581] + }, + "0.625": { + "vector": [-22.50198, 0.00456, -18.01764] + }, + "0.75": { + "vector": [-22.50198, 0.00456, -18.01764] + }, + "1.0": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [22.5, 22.5, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.375": { + "vector": [-22.5, 0, 0] + }, + "0.625": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.0": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail10": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [0, 22.5, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.125": { + "vector": [0, 22.5, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.625": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail12": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.125": { + "vector": [45, 22.5, 0] + }, + "0.25": { + "vector": [45, 22.5, 0] + }, + "0.375": { + "vector": [-45, 22.5, 0] + }, + "0.625": { + "vector": [-45, 22.5, 0] + }, + "0.75": { + "vector": [-45, 22.5, 0] + }, + "1.0": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTailBlade": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.125": { + "vector": [22.5, 22.5, 0] + }, + "0.25": { + "vector": [22.5, 22.5, 0] + }, + "0.375": { + "vector": [-22.5, 22.5, 0] + }, + "0.625": { + "vector": [-22.5, 22.5, 0] + }, + "0.75": { + "vector": [-22.5, 22.5, 0] + }, + "1.0": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-46.55898, 57.63159, -30.36119] + }, + "0.5": { + "vector": [-46.55898, 57.63159, -30.36119] + }, + "0.75": { + "vector": [-46.55898, 57.63159, -30.36119] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gMain": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 1.5, -8.5] + }, + "0.25": { + "vector": [0, 0, -17] + }, + "0.5": { + "vector": [0, 0, -17] + }, + "0.75": { + "vector": [0, 1.5, -8.5] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, -22.5, 0] + }, + "0.25": { + "vector": [58.53967, -8.01867, -12.88333] + }, + "0.5": { + "vector": [58.53967, -8.01867, -12.88333] + }, + "1.0": { + "vector": [-22.5, -22.5, 0] + }, + "1.25": { + "vector": [-22.5, -22.5, 0] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-67.5, 0, 0] + }, + "0.5": { + "vector": [-67.5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [45, 0, 0] + }, + "0.5": { + "vector": [45, 0, 0] + }, + "1.0": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, 22.5, 0] + }, + "0.25": { + "vector": [-22.5, 22.5, 0] + }, + "0.5": { + "vector": [-22.5, 22.5, 0] + }, + "1.0": { + "vector": [-22.5, 22.5, 0] + }, + "1.25": { + "vector": [-22.5, 22.5, 0] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.125": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "1.0": { + "vector": [22.5, 0, 0] + }, + "1.25": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [65.23421, -15.69986, 16.32495] + }, + "0.5": { + "vector": [65.23421, -15.69986, 16.32495] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gHead": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [-24.14867, -20.70481, 9.00717] + }, + "0.5": { + "vector": [-24.14867, -20.70481, 9.00717] + }, + "1.0": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftFoot": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0.10824, 0.98834, -0.10706] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0.10824, 0.98834, -0.10706] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gLeftRingToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gLeftMiddleToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gLeftIndexToe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gRightBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gRightFobackm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-67.5, 0, 0] + }, + "0.5": { + "vector": [-67.5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gLeftBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gLeftFobackm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-67.5, 0, 0] + }, + "0.5": { + "vector": [-67.5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gInnerJaw": { + "position": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gInnerJawEnd": { + "position": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gTopInnerJaw": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gBottomInnerJaw": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "gBottomJawBase": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [45, 0, 0] + }, + "0.5": { + "vector": [45, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "root": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 30, 0] + }, + "0.5": { + "vector": [0, 30, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "gTopLip": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0.4, 0] + }, + "0.75": { + "vector": [0, 0.4, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + } + } + }, + "gBottomLip": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, -0.2, 0] + }, + "0.75": { + "vector": [0, -0.2, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + } + } + } + } + }, + "animation.lunge": { + "loop": "hold_on_last_frame", + "animation_length": 0.75, + "bones": { + "gMain": { + "rotation": { + "0.125": { + "vector": [72.5, 0, 0] + }, + "0.5833": { + "vector": [97.5, 0, 0] + }, + "0.75": { + "vector": [97.5, 0, 0] + } + }, + "position": { + "0.125": { + "vector": [0, 0, 0] + }, + "0.2083": { + "vector": [0, 5, 0] + }, + "0.5": { + "vector": [0, 5, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + } + } + }, + "gChest": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gNeck": { + "rotation": { + "vector": [-22.5, 0, 0] + } + }, + "gHead": { + "rotation": { + "0.125": { + "vector": [-67.5, 0, 0] + }, + "0.2917": { + "vector": [-45, 0, 0] + } + } + }, + "gTail2": { + "rotation": { + "0.125": { + "vector": [-22.5, 0, 0] + }, + "0.375": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail5": { + "rotation": { + "0.125": { + "vector": [45, 0, 0] + }, + "0.375": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail9": { + "rotation": { + "0.125": { + "vector": [37.41, 0, 0] + }, + "0.375": { + "vector": [37.41, 0, 0] + }, + "0.75": { + "vector": [37.41, 0, 0] + } + } + }, + "gTail11": { + "rotation": { + "0.125": { + "vector": [-22.5, 0, 0] + }, + "0.375": { + "vector": [19.39604, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.125": { + "vector": [-94.93147, -12.27659, 43.64293] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [14.3, 0, 0] + }, + "0.7083": { + "vector": [-67.5, 0, -22.5] + } + } + }, + "gLeftShin": { + "rotation": { + "0.125": { + "vector": [67.5, 0, 0] + }, + "0.375": { + "vector": [-67.5, 0, 0] + }, + "0.7083": { + "vector": [22.5, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.125": { + "vector": [-45, 0, 0] + }, + "0.375": { + "vector": [45, 0, 0] + }, + "0.7083": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftFoot": { + "rotation": { + "0.125": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-28.12, 0, 0] + }, + "0.3333": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [45, 0, 0] + }, + "0.5417": { + "vector": [0, 0, 0] + }, + "0.7083": { + "vector": [-28.57971, -22.38597, 2.32288] + } + } + }, + "gLeftRingToe": { + "rotation": { + "0.1667": { + "vector": [0, 0, 0] + }, + "0.3333": { + "vector": [-22.5, 0, 0] + }, + "0.4583": { + "vector": [-45, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + } + } + }, + "gLeftMiddleToe": { + "rotation": { + "0.1667": { + "vector": [0, 0, 0] + }, + "0.3333": { + "vector": [-22.5, 0, 0] + }, + "0.4583": { + "vector": [-45, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.125": { + "vector": [-94.93147, 12.27659, -43.64293] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [14.3, 0, 0] + }, + "0.7083": { + "vector": [-67.5, 0, 22.5] + } + } + }, + "gRightShin": { + "rotation": { + "0.125": { + "vector": [67.5, 0, 0] + }, + "0.375": { + "vector": [-67.5, 0, 0] + }, + "0.7083": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.125": { + "vector": [-45, 0, 0] + }, + "0.375": { + "vector": [45, 0, 0] + }, + "0.7083": { + "vector": [-22.5, 0, 0] + } + } + }, + "gRightFoot": { + "rotation": { + "0.125": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-28.12, 0, 0] + }, + "0.3333": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [45, 0, 0] + }, + "0.5417": { + "vector": [0, 0, 0] + }, + "0.7083": { + "vector": [-28.57971, 22.38597, -2.32288] + } + } + }, + "gRightRingToe": { + "rotation": { + "0.1667": { + "vector": [0, 0, 0] + }, + "0.3333": { + "vector": [-22.5, 0, 0] + }, + "0.4583": { + "vector": [-45, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + } + } + }, + "gRightMiddleToe": { + "rotation": { + "0.1667": { + "vector": [0, 0, 0] + }, + "0.3333": { + "vector": [-22.5, 0, 0] + }, + "0.4583": { + "vector": [-45, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.125": { + "vector": [32.5, 0, 0] + }, + "0.1667": { + "vector": [10, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + }, + "0.625": { + "vector": [0, 0, 0] + } + } + }, + "gRightShoulder": { + "rotation": { + "0.125": { + "vector": [-67.5, 0, 0] + }, + "0.375": { + "vector": [-132.97, 0, 0] + }, + "0.4167": { + "vector": [-112.5, 0, 0] + }, + "0.5833": { + "vector": [-66.09, 0, 0] + }, + "0.7083": { + "vector": [-66.09, 0, 0] + } + } + }, + "gRightBicep": { + "rotation": { + "0.125": { + "vector": [0, 0, -22.5] + }, + "0.4167": { + "vector": [0, 0, -22.5] + }, + "0.5833": { + "vector": [0, 0, -22.5] + } + }, + "position": { + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 0.98793, 0.15488] + } + } + }, + "gRightFobackm": { + "rotation": { + "0.125": { + "vector": [-63.28, 0, 0] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [-8.44, 0, 0] + }, + "0.7083": { + "vector": [-8.44, 0, 0] + } + }, + "position": { + "0.125": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + }, + "0.7083": { + "vector": [0, 0.6, 0.5] + } + } + }, + "gRightHand": { + "rotation": { + "0.125": { + "vector": [0, -90, 22.5] + }, + "0.1667": { + "vector": [74.67899, -32.65931, -61.53967] + }, + "0.375": { + "vector": [0, -90, 22.5] + }, + "0.4583": { + "vector": [-74.21307, -5.94383, 108.55723] + } + } + }, + "gRightIndex": { + "rotation": { + "0.125": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, -22.5] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.4583": { + "vector": [0, 0, 0] + } + } + }, + "gRightRing": { + "rotation": { + "0.125": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, -22.5] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.4583": { + "vector": [0, 0, 0] + } + } + }, + "gLeftShoulder": { + "rotation": { + "0.125": { + "vector": [-67.5, 0, 0] + }, + "0.375": { + "vector": [-132.97, 0, 0] + }, + "0.4167": { + "vector": [-112.5, 0, 0] + }, + "0.5833": { + "vector": [-66.09, 0, 0] + }, + "0.7083": { + "vector": [-66.09, 0, 0] + } + } + }, + "gLeftBicep": { + "rotation": { + "0.125": { + "vector": [0, 0, 22.5] + }, + "0.4167": { + "vector": [0, 0, 22.5] + }, + "0.5833": { + "vector": [0, 0, 22.5] + } + }, + "position": { + "0.4167": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 0.98793, 0.15488] + } + } + }, + "gLeftFobackm": { + "rotation": { + "0.125": { + "vector": [-63.28, 0, 0] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [-8.44, 0, 0] + }, + "0.7083": { + "vector": [-8.44, 0, 0] + } + }, + "position": { + "0.125": { + "vector": [0, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + }, + "0.7083": { + "vector": [0, 0.6, 0.5] + } + } + }, + "gLeftHand": { + "rotation": { + "0.125": { + "vector": [0, 90, -22.5] + }, + "0.1667": { + "vector": [74.67899, 32.65931, 61.53967] + }, + "0.375": { + "vector": [0, 90, -22.5] + }, + "0.4583": { + "vector": [-74.21307, 5.94383, -108.55723] + } + } + }, + "root": { + "position": { + "vector": [0, -8, 0] + } + }, + "gTail1": { + "rotation": { + "0.125": { + "vector": [-67.5, 0, 0] + }, + "0.375": { + "vector": [-90, 0, 0] + } + } + }, + "gTail3": { + "rotation": { + "0.125": { + "vector": [45, 0, 0] + }, + "0.375": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [45, 0, 0] + } + } + }, + "gTail4": { + "rotation": { + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.375": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail6": { + "rotation": { + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.375": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [45, 0, 0] + } + } + }, + "gTail7": { + "rotation": { + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.375": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail8": { + "rotation": { + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.375": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail10": { + "rotation": { + "0.125": { + "vector": [22.5, 0, 0] + }, + "0.375": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail12": { + "rotation": { + "0.125": { + "vector": [-22.5, 0, 0] + }, + "0.375": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTailBlade": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "gBottomJawBase": { + "rotation": { + "0.125": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [45, 0, 0] + }, + "0.4167": { + "vector": [45, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + } + } + }, + "gTopLip": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [0, 0.4, 0] + }, + "0.5833": { + "vector": [0, 0.4, 0] + }, + "0.75": { + "vector": [0, 0, 0] + } + } + }, + "gBottomLip": { + "position": { + "0.0": { + "vector": [0, 0.1, 0] + }, + "0.125": { + "vector": [0, 0.1, 0] + }, + "0.2917": { + "vector": [0, -0.2, 0] + }, + "0.5833": { + "vector": [0, -0.2, 0] + }, + "0.75": { + "vector": [0, 0.1, 0] + } + } + } + } + }, + "animation.presprint": { + "loop": "hold_on_last_frame", + "animation_length": 1.125, + "bones": { + "gMain": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [72.5, 0, 0] + }, + "0.5": { + "vector": [72.5, 0, 0] + }, + "0.9583": { + "vector": [97.5, 0, 0] + }, + "1.125": { + "vector": [97.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 5, 0] + }, + "0.9583": { + "vector": [0, 0, 0] + }, + "1.125": { + "vector": [0, 0, 0] + } + } + }, + "gChest": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + } + } + }, + "gNeck": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.5833": { + "vector": [0, 0, 0] + }, + "0.8333": { + "vector": [-22.5, 0, 0] + } + } + }, + "gHead": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + } + } + }, + "gTail2": { + "rotation": { + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "1.125": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTail5": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [45, 0, 0] + }, + "0.5": { + "vector": [45, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.125": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [37.41, 0, 0] + }, + "0.5": { + "vector": [37.41, 0, 0] + }, + "0.75": { + "vector": [14.91, 0, 0] + }, + "1.125": { + "vector": [37.41, 0, 0] + } + } + }, + "gTail11": { + "rotation": { + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [19.39604, 0, 0] + }, + "1.125": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, -22.5, 0] + }, + "0.25": { + "vector": [-94.93147, -12.27659, 43.64293] + }, + "0.5": { + "vector": [-94.93147, -12.27659, 43.64293] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.875": { + "vector": [14.3, 0, 0] + }, + "1.0833": { + "vector": [-67.5, 0, -22.5] + } + } + }, + "gLeftShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [67.5, 0, 0] + }, + "0.5": { + "vector": [67.5, 0, 0] + }, + "0.75": { + "vector": [-67.5, 0, 0] + }, + "1.0833": { + "vector": [22.5, 0, 0] + } + } + }, + "gLeftAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + }, + "0.75": { + "vector": [45, 0, 0] + }, + "1.0833": { + "vector": [-22.5, 0, 0] + } + } + }, + "gLeftFoot": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.625": { + "vector": [-28.12, 0, 0] + }, + "0.7083": { + "vector": [0, 0, 0] + }, + "0.7917": { + "vector": [45, 0, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + }, + "1.0833": { + "vector": [-28.57971, -22.38597, 2.32288] + } + } + }, + "gLeftRingToe": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.5417": { + "vector": [0, 0, 0] + }, + "0.7083": { + "vector": [-22.5, 0, 0] + }, + "0.8333": { + "vector": [-45, 0, 0] + }, + "1.125": { + "vector": [0, 0, 0] + } + } + }, + "gLeftMiddleToe": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.5417": { + "vector": [0, 0, 0] + }, + "0.7083": { + "vector": [-22.5, 0, 0] + }, + "0.8333": { + "vector": [-45, 0, 0] + }, + "1.125": { + "vector": [0, 0, 0] + } + } + }, + "gRightLeg": { + "rotation": { + "0.0": { + "vector": [-22.5, 22.5, 0] + }, + "0.25": { + "vector": [-94.93147, 12.27659, -43.64293] + }, + "0.5": { + "vector": [-94.93147, 12.27659, -43.64293] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.875": { + "vector": [14.3, 0, 0] + }, + "1.0833": { + "vector": [-67.5, 0, 22.5] + } + } + }, + "gRightShin": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [67.5, 0, 0] + }, + "0.5": { + "vector": [67.5, 0, 0] + }, + "0.75": { + "vector": [-67.5, 0, 0] + }, + "1.0833": { + "vector": [22.5, 0, 0] + } + } + }, + "gRightAnkle": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + }, + "0.75": { + "vector": [45, 0, 0] + }, + "1.0833": { + "vector": [-22.5, 0, 0] + } + } + }, + "gRightFoot": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.625": { + "vector": [-28.12, 0, 0] + }, + "0.7083": { + "vector": [0, 0, 0] + }, + "0.7917": { + "vector": [45, 0, 0] + }, + "0.9167": { + "vector": [0, 0, 0] + }, + "1.0833": { + "vector": [-28.57971, 22.38597, -2.32288] + } + } + }, + "gRightRingToe": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.5417": { + "vector": [0, 0, 0] + }, + "0.7083": { + "vector": [-22.5, 0, 0] + }, + "0.8333": { + "vector": [-45, 0, 0] + }, + "1.125": { + "vector": [0, 0, 0] + } + } + }, + "gRightMiddleToe": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.5417": { + "vector": [0, 0, 0] + }, + "0.7083": { + "vector": [-22.5, 0, 0] + }, + "0.8333": { + "vector": [-45, 0, 0] + }, + "1.125": { + "vector": [0, 0, 0] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.25": { + "vector": [32.5, 0, 0] + }, + "0.5": { + "vector": [32.5, 0, 0] + }, + "0.5417": { + "vector": [10, 0, 0] + }, + "0.7917": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "gRightShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-67.5, 0, 0] + }, + "0.5": { + "vector": [-67.5, 0, 0] + }, + "0.75": { + "vector": [-132.97, 0, 0] + }, + "0.7917": { + "vector": [-112.5, 0, 0] + }, + "0.9583": { + "vector": [-66.09, 0, 0] + }, + "1.0833": { + "vector": [-66.09, 0, 0] + } + } + }, + "gRightBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, -22.5] + }, + "0.5": { + "vector": [0, 0, -22.5] + }, + "0.7917": { + "vector": [0, 0, -22.5] + }, + "0.9583": { + "vector": [0, 0, -22.5] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.7917": { + "vector": [0, 0, 0] + }, + "0.9583": { + "vector": [0, 0.98793, 0.15488] + } + } + }, + "gRightFobackm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-63.28, 0, 0] + }, + "0.5": { + "vector": [-63.28, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.9583": { + "vector": [-8.44, 0, 0] + }, + "1.0833": { + "vector": [-8.44, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.9583": { + "vector": [0, 0, 0] + }, + "1.0833": { + "vector": [0, 0.6, 0.5] + } + } + }, + "gRightHand": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -90, 22.5] + }, + "0.5": { + "vector": [0, -90, 22.5] + }, + "0.5417": { + "vector": [74.67899, -32.65931, -61.53967] + }, + "0.75": { + "vector": [0, -90, 22.5] + }, + "0.8333": { + "vector": [-74.21307, -5.94383, 108.55723] + } + } + }, + "gRightIndex": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.625": { + "vector": [0, 0, -22.5] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.8333": { + "vector": [0, 0, 0] + } + } + }, + "gRightRing": { + "rotation": { + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.625": { + "vector": [0, 0, -22.5] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.8333": { + "vector": [0, 0, 0] + } + } + }, + "gLeftShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-67.5, 0, 0] + }, + "0.5": { + "vector": [-67.5, 0, 0] + }, + "0.75": { + "vector": [-132.97, 0, 0] + }, + "0.7917": { + "vector": [-112.5, 0, 0] + }, + "0.9583": { + "vector": [-66.09, 0, 0] + }, + "1.0833": { + "vector": [-66.09, 0, 0] + } + } + }, + "gLeftBicep": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 22.5] + }, + "0.5": { + "vector": [0, 0, 22.5] + }, + "0.7917": { + "vector": [0, 0, 22.5] + }, + "0.9583": { + "vector": [0, 0, 22.5] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.7917": { + "vector": [0, 0, 0] + }, + "0.9583": { + "vector": [0, 0.98793, 0.15488] + } + } + }, + "gLeftFobackm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-63.28, 0, 0] + }, + "0.5": { + "vector": [-63.28, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.9583": { + "vector": [-8.44, 0, 0] + }, + "1.0833": { + "vector": [-8.44, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.9583": { + "vector": [0, 0, 0] + }, + "1.0833": { + "vector": [0, 0.6, 0.5] + } + } + }, + "gLeftHand": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 90, -22.5] + }, + "0.5": { + "vector": [0, 90, -22.5] + }, + "0.5417": { + "vector": [74.67899, 32.65931, 61.53967] + }, + "0.75": { + "vector": [0, 90, -22.5] + }, + "0.8333": { + "vector": [-74.21307, 5.94383, -108.55723] + } + } + }, + "root": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -8, 0] + }, + "0.5": { + "vector": [0, -8, 0] + } + } + }, + "gTail1": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [-67.5, 0, 0] + }, + "0.5": { + "vector": [-67.5, 0, 0] + }, + "0.75": { + "vector": [-90, 0, 0] + } + } + }, + "gTail3": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [45, 0, 0] + }, + "0.5": { + "vector": [45, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.125": { + "vector": [45, 0, 0] + } + } + }, + "gTail4": { + "rotation": { + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.125": { + "vector": [45, 0, 0] + } + } + }, + "gTail6": { + "rotation": { + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail7": { + "rotation": { + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.125": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail8": { + "rotation": { + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.125": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail10": { + "rotation": { + "0.25": { + "vector": [22.5, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.125": { + "vector": [22.5, 0, 0] + } + } + }, + "gTail12": { + "rotation": { + "0.25": { + "vector": [-22.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [22.5, 0, 0] + }, + "1.125": { + "vector": [-22.5, 0, 0] + } + } + }, + "gTailBlade": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + } + } + } + }, + "azurelib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/entity/drone.geo.json b/common/src/main/resources/assets/azurelib/geo/entity/drone.geo.json new file mode 100644 index 000000000..5191e93b5 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/entity/drone.geo.json @@ -0,0 +1,722 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 256, + "texture_height": 256, + "visible_bounds_width": 12, + "visible_bounds_height": 4.5, + "visible_bounds_offset": [0, 1.75, 0] + }, + "bones": [ + { + "name": "root", + "pivot": [0, 21, 0] + }, + { + "name": "gMain", + "parent": "root", + "pivot": [0, 21, 1.5] + }, + { + "name": "gLowerBody", + "parent": "gMain", + "pivot": [0, 21, 1.5], + "cubes": [ + {"origin": [-3, 20.5, -0.5], "size": [6, 6, 4], "uv": [21, 32]}, + {"origin": [0, 22, 1.9], "size": [0, 4, 4], "uv": [4, 54]} + ] + }, + { + "name": "gChest", + "parent": "gLowerBody", + "pivot": [0, 25.55, 1.5], + "rotation": [22.5, 0, 0], + "cubes": [ + {"origin": [-4, 25.5, -2], "size": [8, 6, 7], "inflate": 0.2, "uv": [18, 18]}, + {"origin": [2.37284, 30.29626, -2.48492], "size": [2, 5, 8], "inflate": -0.2, "pivot": [2.97284, 32.07095, 1.84185], "rotation": [0, 0, 20], "uv": [131, 63], "mirror": true}, + {"origin": [-4.37284, 30.29626, -2.48492], "size": [2, 5, 8], "inflate": -0.2, "pivot": [-2.97284, 32.07095, 1.84185], "rotation": [0, 0, -20], "uv": [131, 63]}, + {"origin": [0, 24.9, 3.65], "size": [0, 4, 4], "uv": [4, 54]} + ] + }, + { + "name": "gRightShoulder", + "parent": "gChest", + "pivot": [-5.55866, 29.31194, 1.75], + "rotation": [-22.5, 0, 0], + "cubes": [ + {"origin": [-7.05866, 27.81194, 0.25], "size": [3, 3, 3], "uv": [135, 8]} + ] + }, + { + "name": "gRightBicep", + "parent": "gRightShoulder", + "pivot": [-5.55866, 29.46194, 1.75], + "rotation": [0, 0, 22.5], + "cubes": [ + {"origin": [-7.05866, 22.06194, 0.25], "size": [3, 7, 3], "inflate": -0.25, "uv": [133, 15]} + ] + }, + { + "name": "gRightFobackm", + "parent": "gRightBicep", + "pivot": [-5.55866, 22.71194, 1.5], + "rotation": [-22.5, 0, 0], + "cubes": [ + {"origin": [-6.55866, 14.96194, 0.75], "size": [2, 8, 2], "uv": [146, 16]}, + {"origin": [-6.05866, 19.46194, 2.65], "size": [1, 6, 1], "inflate": -0.1, "pivot": [-3.55866, 22.46194, 1.25], "rotation": [-20, 0, 0], "uv": [148, 8]} + ] + }, + { + "name": "gRightHand", + "parent": "gRightFobackm", + "pivot": [-5.90866, 15.26194, 1.75], + "rotation": [0, 0, -22.5], + "cubes": [ + {"origin": [-6.40866, 12.26194, 0.75], "size": [1, 3, 2], "inflate": 0.1, "uv": [136, 26]} + ] + }, + { + "name": "gRightThumb", + "parent": "gRightHand", + "pivot": [-5.65866, 14.76194, 0.65], + "rotation": [0, 0, 45], + "cubes": [ + {"origin": [-6.15866, 14.26194, 0.15], "size": [3, 1, 1], "inflate": -0.1, "uv": [144, 27]} + ] + }, + { + "name": "gRightThumbEnd", + "parent": "gRightThumb", + "pivot": [-3.25866, 15.01194, 0.65], + "rotation": [0, 0, 45], + "cubes": [ + {"origin": [-3.45866, 14.26194, 0.15], "size": [3, 1, 1], "inflate": -0.15, "uv": [144, 30]}, + {"origin": [-1.45866, 14.46194, 0.15], "size": [2, 1, 1], "inflate": -0.3, "pivot": [-0.70866, 15.06194, 0.65], "rotation": [0, 0, 2.5], "uv": [145, 33]} + ] + }, + { + "name": "gRightPinkyThumb", + "parent": "gRightHand", + "pivot": [-5.65866, 14.76194, 2.85], + "rotation": [0, 0, 45], + "cubes": [ + {"origin": [-6.15866, 14.26194, 2.35], "size": [3, 1, 1], "inflate": -0.1, "uv": [145, 36]} + ] + }, + { + "name": "gRightPinkyThumbEnd", + "parent": "gRightPinkyThumb", + "pivot": [-3.25866, 15.01194, 2.85], + "rotation": [0, 0, 45], + "cubes": [ + {"origin": [-3.45866, 14.26194, 2.35], "size": [3, 1, 1], "inflate": -0.15, "uv": [145, 39]}, + {"origin": [-1.45866, 14.46194, 2.35], "size": [2, 1, 1], "inflate": -0.3, "pivot": [-0.70866, 15.06194, 2.85], "rotation": [0, 0, 2.5], "uv": [146, 42]} + ] + }, + { + "name": "gRightIndex", + "parent": "gRightHand", + "pivot": [-6.00866, 12.41194, 1.15], + "cubes": [ + {"origin": [-6.50866, 9.51194, 0.65], "size": [1, 3, 1], "inflate": -0.1, "uv": [140, 33]} + ] + }, + { + "name": "gRightIndexEnd", + "parent": "gRightIndex", + "pivot": [-6.25866, 9.61194, 1.15], + "rotation": [0, 0, -45], + "cubes": [ + {"origin": [-6.50866, 6.81194, 0.65], "size": [1, 3, 1], "inflate": -0.15, "uv": [140, 38]}, + {"origin": [-6.7915, 5.7791, 0.85], "size": [1, 2, 1], "inflate": -0.38, "pivot": [-6.2915, 6.7791, 1.35], "rotation": [-2.5, 0, -2.5], "uv": [134, 47]}, + {"origin": [-6.7915, 5.7791, 0.45], "size": [1, 2, 1], "inflate": -0.38, "pivot": [-6.2915, 6.7791, 0.95], "rotation": [2.5, 0, -2.5], "uv": [140, 43]} + ] + }, + { + "name": "gRightRing", + "parent": "gRightHand", + "pivot": [-6.00866, 12.41194, 2.35], + "cubes": [ + {"origin": [-6.50866, 9.51194, 1.85], "size": [1, 3, 1], "inflate": -0.1, "uv": [134, 33]} + ] + }, + { + "name": "gRightRingEnd", + "parent": "gRightRing", + "pivot": [-6.25866, 9.61194, 2.35], + "rotation": [0, 0, -45], + "cubes": [ + {"origin": [-6.50866, 6.81194, 1.85], "size": [1, 3, 1], "inflate": -0.15, "uv": [134, 38]}, + {"origin": [-6.7915, 5.7791, 1.65], "size": [1, 2, 1], "inflate": -0.38, "pivot": [-6.2915, 6.7791, 2.15], "rotation": [2.5, 0, -2.5], "uv": [140, 47]}, + {"origin": [-6.7915, 5.7791, 2.05], "size": [1, 2, 1], "inflate": -0.38, "pivot": [-6.2915, 6.7791, 2.55], "rotation": [-2.5, 0, -2.5], "uv": [134, 43]} + ] + }, + { + "name": "gLeftShoulder", + "parent": "gChest", + "pivot": [5.55866, 29.31194, 1.75], + "rotation": [-22.5, 0, 0], + "cubes": [ + {"origin": [4.05866, 27.81194, 0.25], "size": [3, 3, 3], "uv": [135, 8], "mirror": true} + ] + }, + { + "name": "gLeftBicep", + "parent": "gLeftShoulder", + "pivot": [5.55866, 29.46194, 1.75], + "rotation": [0, 0, -22.5], + "cubes": [ + {"origin": [4.05866, 22.06194, 0.25], "size": [3, 7, 3], "inflate": -0.25, "uv": [133, 15], "mirror": true} + ] + }, + { + "name": "gLeftFobackm", + "parent": "gLeftBicep", + "pivot": [5.55866, 22.71194, 1.5], + "rotation": [-22.5, 0, 0], + "cubes": [ + {"origin": [4.55866, 14.96194, 0.75], "size": [2, 8, 2], "uv": [146, 16], "mirror": true}, + {"origin": [5.05866, 19.46194, 2.65], "size": [1, 6, 1], "inflate": -0.1, "pivot": [3.55866, 22.46194, 1.25], "rotation": [-20, 0, 0], "uv": [148, 8], "mirror": true} + ] + }, + { + "name": "gLeftHand", + "parent": "gLeftFobackm", + "pivot": [5.90866, 15.26194, 1.75], + "rotation": [0, 0, 22.5], + "cubes": [ + {"origin": [5.40866, 12.26194, 0.75], "size": [1, 3, 2], "inflate": 0.1, "uv": [136, 26], "mirror": true} + ] + }, + { + "name": "gLeftThumb", + "parent": "gLeftHand", + "pivot": [5.65866, 14.76194, 0.65], + "rotation": [0, 0, -45], + "cubes": [ + {"origin": [3.15866, 14.26194, 0.15], "size": [3, 1, 1], "inflate": -0.1, "uv": [144, 27], "mirror": true} + ] + }, + { + "name": "gLeftThumbEnd", + "parent": "gLeftThumb", + "pivot": [3.25866, 15.01194, 0.65], + "rotation": [0, 0, -45], + "cubes": [ + {"origin": [0.45866, 14.26194, 0.15], "size": [3, 1, 1], "inflate": -0.15, "uv": [144, 30], "mirror": true}, + {"origin": [-0.29134, 14.46194, 0.15], "size": [2, 1, 1], "inflate": -0.3, "pivot": [0.70866, 15.06194, 0.65], "rotation": [0, 0, -2.5], "uv": [145, 33], "mirror": true} + ] + }, + { + "name": "gLeftPinkyThumb", + "parent": "gLeftHand", + "pivot": [5.65866, 14.76194, 2.85], + "rotation": [0, 0, -45], + "cubes": [ + {"origin": [3.15866, 14.26194, 2.35], "size": [3, 1, 1], "inflate": -0.1, "uv": [145, 36], "mirror": true} + ] + }, + { + "name": "gLeftPinkyThumbEnd", + "parent": "gLeftPinkyThumb", + "pivot": [3.25866, 15.01194, 2.85], + "rotation": [0, 0, -45], + "cubes": [ + {"origin": [0.45866, 14.26194, 2.35], "size": [3, 1, 1], "inflate": -0.15, "uv": [145, 39], "mirror": true}, + {"origin": [-0.29134, 14.46194, 2.35], "size": [2, 1, 1], "inflate": -0.3, "pivot": [0.70866, 15.06194, 2.85], "rotation": [0, 0, -2.5], "uv": [146, 42], "mirror": true} + ] + }, + { + "name": "gLeftIndex", + "parent": "gLeftHand", + "pivot": [6.00866, 12.41194, 1.15], + "cubes": [ + {"origin": [5.50866, 9.51194, 0.65], "size": [1, 3, 1], "inflate": -0.1, "uv": [140, 33], "mirror": true} + ] + }, + { + "name": "gLeftIndexEnd", + "parent": "gLeftIndex", + "pivot": [6.25866, 9.61194, 1.15], + "rotation": [0, 0, 45], + "cubes": [ + {"origin": [5.50866, 6.81194, 0.65], "size": [1, 3, 1], "inflate": -0.15, "uv": [140, 38], "mirror": true}, + {"origin": [5.7915, 5.7791, 0.85], "size": [1, 2, 1], "inflate": -0.38, "pivot": [6.2915, 6.7791, 1.35], "rotation": [-2.5, 0, 2.5], "uv": [134, 47], "mirror": true}, + {"origin": [5.7915, 5.7791, 0.45], "size": [1, 2, 1], "inflate": -0.38, "pivot": [6.2915, 6.7791, 0.95], "rotation": [2.5, 0, 2.5], "uv": [140, 43], "mirror": true} + ] + }, + { + "name": "gLeftRing", + "parent": "gLeftHand", + "pivot": [6.00866, 12.41194, 2.35], + "cubes": [ + {"origin": [5.50866, 9.51194, 1.85], "size": [1, 3, 1], "inflate": -0.1, "uv": [134, 33], "mirror": true} + ] + }, + { + "name": "gLeftRingEnd", + "parent": "gLeftRing", + "pivot": [6.25866, 9.61194, 2.35], + "rotation": [0, 0, 45], + "cubes": [ + {"origin": [5.50866, 6.81194, 1.85], "size": [1, 3, 1], "inflate": -0.15, "uv": [134, 38], "mirror": true}, + {"origin": [5.7915, 5.7791, 1.65], "size": [1, 2, 1], "inflate": -0.38, "pivot": [6.2915, 6.7791, 2.15], "rotation": [2.5, 0, 2.5], "uv": [140, 47], "mirror": true}, + {"origin": [5.7915, 5.7791, 2.05], "size": [1, 2, 1], "inflate": -0.38, "pivot": [6.2915, 6.7791, 2.55], "rotation": [-2.5, 0, 2.5], "uv": [134, 43], "mirror": true} + ] + }, + { + "name": "gDorsalTube", + "parent": "gChest", + "pivot": [0, 25.55, 1.5] + }, + { + "name": "gRightLowerDorsalTube", + "parent": "gDorsalTube", + "pivot": [-1.81753, 26.79619, 4.67466], + "rotation": [-22.5, -22.5, 0], + "cubes": [ + {"origin": [-2.81753, 25.79619, 4.37466], "size": [2, 2, 4], "inflate": 0.05, "uv": [138, 97]}, + {"origin": [-2.31753, 27.71625, 7.04382], "size": [1, 1, 4], "inflate": 0.25, "pivot": [-1.81753, 28.77689, 9.72317], "rotation": [40, 0, 0], "uv": [140, 104]}, + {"origin": [-2.31753, 28.57992, 10.92394], "size": [1, 1, 3], "inflate": 0.1, "pivot": [-1.81753, 29.28152, 10.19197], "rotation": [15, 0, 0], "uv": [142, 110]} + ] + }, + { + "name": "gLeftLowerDorsalTube", + "parent": "gDorsalTube", + "pivot": [1.81753, 26.79619, 4.67466], + "rotation": [-22.5, 22.5, 0], + "cubes": [ + {"origin": [0.81753, 25.79619, 4.37466], "size": [2, 2, 4], "inflate": 0.05, "uv": [138, 97], "mirror": true}, + {"origin": [1.31753, 27.71625, 7.04382], "size": [1, 1, 4], "inflate": 0.25, "pivot": [1.81753, 28.77689, 9.72317], "rotation": [40, 0, 0], "uv": [140, 104], "mirror": true}, + {"origin": [1.31753, 28.57992, 10.92394], "size": [1, 1, 3], "inflate": 0.1, "pivot": [1.81753, 29.28152, 10.19197], "rotation": [15, 0, 0], "uv": [142, 110], "mirror": true} + ] + }, + { + "name": "gRightUpperDorsalTube", + "parent": "gDorsalTube", + "pivot": [-2.21753, 30.29619, 4.92466], + "rotation": [0, -22.5, 0], + "cubes": [ + {"origin": [-3.21753, 29.29619, 4.62466], "size": [2, 2, 5], "inflate": 0.05, "uv": [136, 77]}, + {"origin": [-2.71753, 31.11625, 8.39382], "size": [1, 1, 5], "inflate": 0.25, "pivot": [-2.21753, 32.17689, 11.07317], "rotation": [40, 0, 0], "uv": [138, 85]}, + {"origin": [-2.71753, 32.67992, 13.17394], "size": [1, 1, 3], "inflate": 0.1, "pivot": [-2.21753, 33.38152, 12.44197], "rotation": [15, 0, 0], "uv": [142, 92]} + ] + }, + { + "name": "gLeftUpperDorsalTube", + "parent": "gDorsalTube", + "pivot": [2.21753, 30.29619, 4.92466], + "rotation": [0, 22.5, 0], + "cubes": [ + {"origin": [1.21753, 29.29619, 4.62466], "size": [2, 2, 5], "inflate": 0.05, "uv": [136, 77], "mirror": true}, + {"origin": [1.71753, 31.11625, 8.39382], "size": [1, 1, 5], "inflate": 0.25, "pivot": [2.21753, 32.17689, 11.07317], "rotation": [40, 0, 0], "uv": [138, 85], "mirror": true}, + {"origin": [1.71753, 32.67992, 13.17394], "size": [1, 1, 3], "inflate": 0.1, "pivot": [2.21753, 33.38152, 12.44197], "rotation": [15, 0, 0], "uv": [142, 92], "mirror": true} + ] + }, + { + "name": "gBackSpike", + "parent": "gChest", + "pivot": [0, 28.7, 5.35], + "cubes": [ + {"origin": [0, 28.4, 3.75], "size": [0, 3, 7], "uv": [155, 63]} + ] + }, + { + "name": "gNeck", + "parent": "gChest", + "pivot": [0, 31.4, 2.1], + "cubes": [ + {"origin": [-2, 29.95, -0.4], "size": [4, 9, 4], "inflate": -0.2, "uv": [68, 91]}, + {"origin": [0, 31.55, 3.6], "size": [0, 4, 2], "uv": [4, 50]} + ] + }, + { + "name": "gHead", + "parent": "gNeck", + "pivot": [0.5, 36.50555, 1.92864], + "cubes": [ + {"origin": [-2, 35.04258, -2.52021], "size": [4, 3, 3], "inflate": -0.4, "pivot": [-0.5, 37.24258, 0.72979], "rotation": [10.5, 0, 0], "uv": [93, 141]} + ] + }, + { + "name": "gDome", + "parent": "gHead", + "pivot": [0.5, 39.55222, 1.40092], + "rotation": [5, 0, 0], + "cubes": [ + {"origin": [-2, 37.96795, -6.49239], "size": [4, 2, 2], "inflate": 0.07, "pivot": [0, 38.89427, -5.02956], "rotation": [70, 0, 0], "uv": [94, 136]}, + {"origin": [-2, 38.06248, -5.15095], "size": [4, 2, 1], "inflate": 0.08, "pivot": [0, 38.85737, -5.07234], "rotation": [32.5, 0, 0], "uv": [95, 132]}, + {"origin": [-2, 37.36926, -4.80827], "size": [4, 3, 5], "inflate": 0.11, "pivot": [0, 38.16407, 2.02622], "rotation": [0, 0, 0], "uv": [91, 123]}, + {"origin": [-2, 37.08099, 0.06079], "size": [4, 3, 4], "inflate": 0.1, "pivot": [0, 38.16407, 2.02622], "rotation": [-9, 0, 0], "uv": [92, 115]}, + {"origin": [-2, 36.44621, 3.84749], "size": [4, 4, 6], "inflate": 0.09, "pivot": [0, 38.16407, 2.02622], "rotation": [-19.5, 0, 0], "uv": [90, 104]} + ] + }, + { + "name": "gFace", + "parent": "gHead", + "pivot": [0.5, 36.89665, -4.43625], + "cubes": [ + {"origin": [-2, 36.49665, -6.43625], "size": [4, 1, 15], "inflate": -0.07, "pivot": [0.5, 36.89665, -4.43625], "rotation": [-2.5, 0, 0], "uv": [57, 108]}, + {"origin": [-2.5, 34.71095, -7.18908], "size": [5, 3, 5], "inflate": -1.05, "uv": [48, 33]} + ] + }, + { + "name": "gTopLip", + "parent": "gFace", + "pivot": [0.5, 36.87919, -2.33572], + "cubes": [ + {"origin": [-1.5, 36.12919, -6.23572], "size": [3, 1, 4], "inflate": -0.04, "uv": [69, 132]} + ] + }, + { + "name": "gInnerJawAngle", + "parent": "gFace", + "pivot": [0.5, 36.13758, -0.31327], + "rotation": [6.5, 0, 0] + }, + { + "name": "gInnerJaw", + "parent": "gInnerJawAngle", + "pivot": [0, 35.88758, 1.18673], + "cubes": [ + {"origin": [-1, 34.88758, -1.31327], "size": [2, 2, 5], "inflate": -0.25, "uv": [93, 148]} + ] + }, + { + "name": "gInnerJawEnd", + "parent": "gInnerJaw", + "pivot": [0, 35.88758, 0.78673], + "cubes": [ + {"origin": [-1, 34.88758, -1.71327], "size": [2, 2, 5], "inflate": -0.35, "uv": [93, 156]} + ] + }, + { + "name": "gTopInnerJaw", + "parent": "gInnerJawEnd", + "pivot": [0, 35.98758, -1.41327], + "cubes": [ + {"origin": [-1, 35.78758, -3.31327], "size": [2, 1, 2], "inflate": -0.15, "uv": [96, 166]} + ] + }, + { + "name": "gBottomInnerJaw", + "parent": "gInnerJawEnd", + "pivot": [0, 35.88758, -1.41327], + "cubes": [ + {"origin": [-1, 34.98758, -3.31327], "size": [2, 1, 2], "inflate": -0.15, "uv": [96, 163]} + ] + }, + { + "name": "gBottomJawBase", + "parent": "gFace", + "pivot": [1, 37.0029, -2.26994], + "cubes": [ + {"origin": [-2, 34.66663, -3.01651], "size": [4, 4, 2], "inflate": -0.1, "pivot": [0, 36.26663, -2.96651], "rotation": [-12.5, 0, 0], "uv": [70, 138]}, + {"origin": [1.53787, 36.01678, -4.88797], "size": [0, 2, 4], "pivot": [1.53787, 37.01678, -2.88797], "rotation": [74.98635, 2.41476, -0.64743], "uv": [67, 141], "mirror": true}, + {"origin": [-1.53787, 36.01678, -4.88797], "size": [0, 2, 4], "pivot": [-1.53787, 37.01678, -2.88797], "rotation": [74.98635, -2.41476, 0.64743], "uv": [77, 141]} + ] + }, + { + "name": "gBottomJaw", + "parent": "gBottomJawBase", + "pivot": [0.5, 35.06663, -2.96651], + "cubes": [ + {"origin": [-1.5, 34.66663, -6.06651], "size": [3, 1, 4], "inflate": 0.2, "uv": [69, 160]}, + {"origin": [-2.5, 34.76663, -7.21651], "size": [5, 3, 5], "inflate": -1.1, "uv": [48, 56]} + ] + }, + { + "name": "gBottomLip", + "parent": "gBottomJaw", + "pivot": [1, 35.69663, -3.36651], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-1.5, 35.22919, -6.25572], "size": [3, 1, 4], "inflate": -0.06, "uv": [69, 154]} + ] + }, + { + "name": "gWaist", + "parent": "gMain", + "pivot": [0, 19, 1.5], + "cubes": [ + {"origin": [-3, 17.5, -0.5], "size": [6, 4, 4], "inflate": 0.2, "uv": [19, 44]} + ] + }, + { + "name": "gTail1", + "parent": "gWaist", + "pivot": [0, 19.5, 2], + "cubes": [ + {"origin": [-1.5, 18, 1.75], "size": [3, 3, 7], "pivot": [0, 19.5, 29.025], "rotation": [0, 0, 45], "uv": [21, 52]}, + {"origin": [0, 20.7, 3.75], "size": [0, 3, 5], "uv": [4, 60]} + ] + }, + { + "name": "gTail2", + "parent": "gTail1", + "pivot": [0, 19.5, 8.35], + "cubes": [ + {"origin": [-1.5, 18, 7.85], "size": [3, 3, 5], "inflate": -0.1, "pivot": [0, 19.5, 33.125], "rotation": [0, 0, 45], "uv": [23, 64]}, + {"origin": [0, 20.2, 8.85], "size": [0, 3, 4], "uv": [4, 69]} + ] + }, + { + "name": "gTail3", + "parent": "gTail2", + "pivot": [0, 19.5, 12.35], + "cubes": [ + {"origin": [-1.5, 18, 11.85], "size": [3, 3, 5], "inflate": -0.2, "pivot": [0, 19.5, 37.125], "rotation": [0, 0, 45], "uv": [23, 64]}, + {"origin": [0, 20.2, 12.6], "size": [0, 3, 4], "uv": [4, 69]} + ] + }, + { + "name": "gTail4", + "parent": "gTail3", + "pivot": [0, 19.5, 16.3], + "cubes": [ + {"origin": [-1.5, 18, 15.65], "size": [3, 3, 6], "inflate": -0.3, "pivot": [0, 19.5, 40.925], "rotation": [0, 0, 45], "uv": [22, 74]}, + {"origin": [0, 20.2, 16.4], "size": [0, 3, 5], "uv": [4, 76]} + ] + }, + { + "name": "gTail5", + "parent": "gTail4", + "pivot": [0, 19.5, 21.25], + "cubes": [ + {"origin": [-1, 18.5, 20.95], "size": [2, 2, 6], "inflate": 0.1, "pivot": [0, 19.5, 46.225], "rotation": [0, 0, 45], "uv": [23, 85]}, + {"origin": [0, 20.05, 21.6], "size": [0, 3, 5], "uv": [4, 76]} + ] + }, + { + "name": "gTail6", + "parent": "gTail5", + "pivot": [0, 19.5, 26.6], + "cubes": [ + {"origin": [-1, 18.5, 26.2], "size": [2, 2, 6], "pivot": [0, 19.5, 51.475], "rotation": [0, 0, 45], "uv": [23, 85]}, + {"origin": [0, 19.85, 27], "size": [0, 3, 5], "uv": [4, 76]} + ] + }, + { + "name": "gTail7", + "parent": "gTail6", + "pivot": [0, 19.5, 31.85], + "cubes": [ + {"origin": [-1, 18.5, 31.45], "size": [2, 2, 6], "inflate": -0.1, "pivot": [0, 19.5, 56.725], "rotation": [0, 0, 45], "uv": [23, 85]}, + {"origin": [0, 19.65, 32.05], "size": [0, 3, 5], "uv": [4, 76]} + ] + }, + { + "name": "gTail8", + "parent": "gTail7", + "pivot": [0, 19.5, 36.85], + "cubes": [ + {"origin": [-1, 18.5, 36.45], "size": [2, 2, 7], "inflate": -0.2, "pivot": [0, 19.5, 61.725], "rotation": [0, 0, 45], "uv": [22, 95]}, + {"origin": [0, 19.65, 37.1], "size": [0, 3, 6], "uv": [4, 83]} + ] + }, + { + "name": "gTail9", + "parent": "gTail8", + "pivot": [0, 19.5, 42.85], + "cubes": [ + {"origin": [-1, 18.5, 42.45], "size": [2, 2, 8], "inflate": -0.3, "pivot": [0, 19.5, 67.725], "rotation": [0, 0, 45], "uv": [21, 106]}, + {"origin": [0, 20.15, 44.2], "size": [0, 3, 6], "uv": [5, 91]} + ] + }, + { + "name": "gTail10", + "parent": "gTail9", + "pivot": [0, 19.5, 49.85], + "cubes": [ + {"origin": [-0.5, 19, 49.55], "size": [1, 1, 8], "inflate": 0.1, "pivot": [0, 19.5, 74.825], "rotation": [0, 0, 45], "uv": [22, 118]}, + {"origin": [0, 19.05, 50.1], "size": [0, 4, 7], "uv": [4, 90]} + ] + }, + { + "name": "gTail11", + "parent": "gTail10", + "pivot": [0, 19.5, 57.4], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-0.5, 19, 57.15], "size": [1, 1, 8], "pivot": [0, 19.5, 82.425], "rotation": [0, 0, 45], "uv": [22, 118]}, + {"origin": [0, 19.85, 58.1], "size": [0, 3, 7], "uv": [4, 97]} + ] + }, + { + "name": "gTail12", + "parent": "gTail11", + "pivot": [0, 19.5, 64.95], + "cubes": [ + {"origin": [-0.5, 19, 64.65], "size": [1, 1, 8], "inflate": -0.1, "pivot": [0, 19.5, 89.925], "rotation": [0, 0, 45], "uv": [22, 118]}, + {"origin": [0, 19.75, 65.4], "size": [0, 3, 7], "uv": [4, 97]} + ] + }, + { + "name": "gTailBlade", + "parent": "gTail12", + "pivot": [0, 19.5, 72.4], + "cubes": [ + {"origin": [0, 18, 72.45], "size": [0, 3, 10], "uv": [21, 122]} + ] + }, + { + "name": "gLeftLeg", + "parent": "gWaist", + "pivot": [2.7, 19.5, 1], + "rotation": [-22.5, 0, 0], + "cubes": [ + {"origin": [0.7, 10, -0.5], "size": [4, 11, 4], "inflate": -0.2, "uv": [85, 4], "mirror": true} + ] + }, + { + "name": "gLeftShin", + "parent": "gLeftLeg", + "pivot": [2.7, 10.7, 2], + "rotation": [90, 0, 0], + "cubes": [ + {"origin": [1.2, 1.7, 0], "size": [3, 10, 3], "inflate": -0.1, "uv": [87, 20], "mirror": true}, + {"origin": [2.2, 1.08536, 1.61109], "size": [1, 1, 4], "inflate": 0.1, "pivot": [2.7, 1.55, 3.5], "rotation": [-22.5, 0, 0], "uv": [88, 45], "mirror": true} + ] + }, + { + "name": "gLeftAnkle", + "parent": "gLeftShin", + "pivot": [2.7, 3.1, 1.5], + "rotation": [-90, 0, 0], + "cubes": [ + {"origin": [1.2, -4.9, 0], "size": [3, 8, 3], "inflate": -0.3, "uv": [87, 34], "mirror": true} + ] + }, + { + "name": "gLeftFoot", + "parent": "gLeftAnkle", + "pivot": [2.7, -3.95, 2.5], + "rotation": [22.5, 0, 0], + "cubes": [ + {"origin": [1.2, -4.87685, -1.78104], "size": [3, 2, 5], "inflate": -0.2, "uv": [85, 50], "mirror": true} + ] + }, + { + "name": "gLeftRingToe", + "parent": "gLeftFoot", + "pivot": [3.39636, -3.47772, -1.6259], + "rotation": [17.5, 0, 0], + "cubes": [ + {"origin": [2.89636, -4.04964, -4.40546], "size": [1, 1, 3], "inflate": -0.05, "pivot": [3.39636, -3.47772, -3.7259], "rotation": [0, 0, 0], "uv": [84, 67], "mirror": true}, + {"origin": [2.89636, -3.82056, -5.33071], "size": [1, 1, 2], "inflate": -0.2, "pivot": [2.89636, -3.35848, -3.93991], "rotation": [5, 0, 0], "uv": [85, 72], "mirror": true} + ] + }, + { + "name": "gLeftMiddleToe", + "parent": "gLeftFoot", + "pivot": [1.99636, -3.42772, -1.6259], + "rotation": [17.5, 0, 0], + "cubes": [ + {"origin": [1.49636, -3.99964, -4.40546], "size": [1, 1, 3], "inflate": -0.05, "pivot": [1.99636, -3.42772, -3.7259], "rotation": [0, 0, 0], "uv": [94, 67], "mirror": true}, + {"origin": [1.49636, -3.77056, -5.33071], "size": [1, 1, 2], "inflate": -0.2, "pivot": [2.49636, -3.30848, -3.93991], "rotation": [5, 0, 0], "uv": [95, 72], "mirror": true} + ] + }, + { + "name": "gLeftIndexToe", + "parent": "gLeftFoot", + "pivot": [1.5804, -3.52772, 1.40349], + "rotation": [17.5, 22.5, 0], + "cubes": [ + {"origin": [1.0804, -4.09964, -1.37607], "size": [1, 1, 3], "inflate": -0.05, "pivot": [1.5804, -3.52772, -0.69651], "rotation": [0, 0, 0], "uv": [94, 58], "mirror": true}, + {"origin": [1.0804, -3.8558, -2.26695], "size": [1, 1, 2], "inflate": -0.2, "pivot": [1.5804, -3.3558, -1.26695], "rotation": [2.5, 0, 0], "uv": [95, 63], "mirror": true} + ] + }, + { + "name": "gRightPinkyToe", + "parent": "gLeftFoot", + "pivot": [3.8196, -3.52772, 1.40349], + "rotation": [17.5, -22.5, 0], + "cubes": [ + {"origin": [3.3196, -4.09964, -1.37607], "size": [1, 1, 3], "inflate": -0.05, "pivot": [3.8196, -3.52772, -0.69651], "rotation": [0, 0, 0], "uv": [84, 58], "mirror": true}, + {"origin": [3.3196, -3.8558, -2.26695], "size": [1, 1, 2], "inflate": -0.2, "pivot": [3.8196, -3.3558, -1.26695], "rotation": [2.5, 0, 0], "uv": [85, 63], "mirror": true} + ] + }, + { + "name": "gRightLeg", + "parent": "gWaist", + "pivot": [-2.7, 19.5, 1], + "rotation": [-22.5, 0, 0], + "cubes": [ + {"origin": [-4.7, 10, -0.5], "size": [4, 11, 4], "inflate": -0.2, "uv": [85, 4]} + ] + }, + { + "name": "gRightShin", + "parent": "gRightLeg", + "pivot": [-2.7, 10.7, 2], + "rotation": [90, 0, 0], + "cubes": [ + {"origin": [-4.2, 1.7, 0], "size": [3, 10, 3], "inflate": -0.1, "uv": [87, 20]}, + {"origin": [-3.2, 1.08536, 1.61109], "size": [1, 1, 4], "inflate": 0.1, "pivot": [-2.7, 1.55, 3.5], "rotation": [-22.5, 0, 0], "uv": [88, 45]} + ] + }, + { + "name": "gRightAnkle", + "parent": "gRightShin", + "pivot": [-2.7, 3.1, 1.5], + "rotation": [-90, 0, 0], + "cubes": [ + {"origin": [-4.2, -4.9, 0], "size": [3, 8, 3], "inflate": -0.3, "uv": [87, 34]} + ] + }, + { + "name": "gRightFoot", + "parent": "gRightAnkle", + "pivot": [-2.7, -3.95, 2.5], + "rotation": [22.5, 0, 0], + "cubes": [ + {"origin": [-4.2, -4.87685, -1.78104], "size": [3, 2, 5], "inflate": -0.2, "uv": [85, 50]} + ] + }, + { + "name": "gRightRingToe", + "parent": "gRightFoot", + "pivot": [-3.39636, -3.47772, -1.6259], + "rotation": [17.5, 0, 0], + "cubes": [ + {"origin": [-3.89636, -4.04964, -4.40546], "size": [1, 1, 3], "inflate": -0.05, "pivot": [-3.39636, -3.47772, -3.7259], "rotation": [0, 0, 0], "uv": [84, 67]}, + {"origin": [-3.89636, -3.82056, -5.33071], "size": [1, 1, 2], "inflate": -0.2, "pivot": [-2.89636, -3.35848, -3.93991], "rotation": [5, 0, 0], "uv": [85, 72]} + ] + }, + { + "name": "gRightMiddleToe", + "parent": "gRightFoot", + "pivot": [-1.99636, -3.42772, -1.6259], + "rotation": [17.5, 0, 0], + "cubes": [ + {"origin": [-2.49636, -3.99964, -4.40546], "size": [1, 1, 3], "inflate": -0.05, "pivot": [-1.99636, -3.42772, -3.7259], "rotation": [0, 0, 0], "uv": [94, 67]}, + {"origin": [-2.49636, -3.77056, -5.33071], "size": [1, 1, 2], "inflate": -0.2, "pivot": [-2.49636, -3.30848, -3.93991], "rotation": [5, 0, 0], "uv": [95, 72]} + ] + }, + { + "name": "gRightIndexToe", + "parent": "gRightFoot", + "pivot": [-1.5804, -3.52772, 1.40349], + "rotation": [17.5, -22.5, 0], + "cubes": [ + {"origin": [-2.0804, -4.09964, -1.37607], "size": [1, 1, 3], "inflate": -0.05, "pivot": [-1.5804, -3.52772, -0.69651], "rotation": [0, 0, 0], "uv": [94, 58]}, + {"origin": [-2.0804, -3.8558, -2.26695], "size": [1, 1, 2], "inflate": -0.2, "pivot": [-1.5804, -3.3558, -1.26695], "rotation": [2.5, 0, 0], "uv": [95, 63]} + ] + }, + { + "name": "gLeftPinkyToe", + "parent": "gRightFoot", + "pivot": [-3.8196, -3.52772, 1.40349], + "rotation": [17.5, 22.5, 0], + "cubes": [ + {"origin": [-4.3196, -4.09964, -1.37607], "size": [1, 1, 3], "inflate": -0.05, "pivot": [-3.8196, -3.52772, -0.69651], "rotation": [0, 0, 0], "uv": [84, 58]}, + {"origin": [-4.3196, -3.8558, -2.26695], "size": [1, 1, 2], "inflate": -0.2, "pivot": [-3.8196, -3.3558, -1.26695], "rotation": [2.5, 0, 0], "uv": [85, 63]} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/textures/entity/drone.png b/common/src/main/resources/assets/azurelib/textures/entity/drone.png new file mode 100644 index 0000000000000000000000000000000000000000..cdfe267d909739e7d482c20b571b7181dd9c9beb GIT binary patch literal 18747 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 packet.handle()); ClientPlayNetworking.registerGlobalReceiver(AnimDataSyncPacket.TYPE, (packet, context) -> packet.handle()); ClientPlayNetworking.registerGlobalReceiver(SendConfigDataPacket.TYPE, (packet, context) -> packet.handle()); + + EntityRendererRegistry.register(ExampleEntityTypes.DRONE, DroneRenderer::new); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 1b5c8c2f5..df1eeb91f 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -2,24 +2,22 @@ import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.AzureLibMod; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; import mod.azure.azurelib.common.internal.common.config.AzureLibConfig; import mod.azure.azurelib.common.internal.common.config.format.ConfigFormats; import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import mod.azure.azurelib.common.internal.common.network.packet.*; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.common.internal.common.network.packet.AnimDataSyncPacket; +import mod.azure.azurelib.common.internal.common.network.packet.AnimTriggerPacket; +import mod.azure.azurelib.common.internal.common.network.packet.BlockEntityAnimDataSyncPacket; +import mod.azure.azurelib.common.internal.common.network.packet.BlockEntityAnimTriggerPacket; +import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimDataSyncPacket; +import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimTriggerPacket; +import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; +import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; import mod.azure.azurelib.fabric.platform.FabricAzureLibNetwork; import mod.azure.azurelib.sblforked.SBLConstants; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.material.PushReaction; public final class FabricAzureLibMod implements ModInitializer { @@ -39,5 +37,7 @@ public void onInitialize() { PayloadTypeRegistry.playS2C().register(AnimTriggerPacket.TYPE, AnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(AnimDataSyncPacket.TYPE, AnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(SendConfigDataPacket.TYPE, SendConfigDataPacket.CODEC); + + ExampleEntityTypes.initialize(); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java new file mode 100644 index 000000000..a4483badc --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java @@ -0,0 +1,12 @@ +package mod.azure.azurelib.fabric.core2.example; + +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.level.Level; + +public class Drone extends Monster { + + public Drone(EntityType entityType, Level level) { + super(entityType, level); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java new file mode 100644 index 000000000..22e36b4d1 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java @@ -0,0 +1,34 @@ +package mod.azure.azurelib.fabric.core2.example; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core.object.PlayState; +import mod.azure.azurelib.core2.animation.AzAnimationState; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +public class DroneAnimator extends AzEntityAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource("animations/entity/drone.animation.json"); + + private static final String IDLE_ANIMATION_NAME = "animation.idle"; + private static final AzRawAnimation IDLE_ANIMATION = AzRawAnimation.begin().thenLoop(IDLE_ANIMATION_NAME); + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + new AzAnimationController<>(this, "base_controller", 0, this::handle) + ); + } + public PlayState handle(AzAnimationState event) { + return event.setAndContinue(IDLE_ANIMATION); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(Drone drone) { + return ANIMATIONS; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneRenderer.java new file mode 100644 index 000000000..e421d5b96 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneRenderer.java @@ -0,0 +1,34 @@ +package mod.azure.azurelib.fabric.core2.example; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class DroneRenderer extends AzEntityRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/entity/drone.geo.json"); + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/drone.png"); + + public DroneRenderer(EntityRendererProvider.Context context) { + super(context); + } + + @Override + protected @Nullable AzEntityAnimator createAnimator() { + return new DroneAnimator(); + } + + @Override + protected @NotNull ResourceLocation getModelLocation(Drone drone) { + return MODEL; + } + + @Override + public @NotNull ResourceLocation getTextureLocation(@NotNull Drone drone) { + return TEXTURE; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java new file mode 100644 index 000000000..7275502ca --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java @@ -0,0 +1,28 @@ +package mod.azure.azurelib.fabric.core2.example; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobCategory; + +public class ExampleEntityTypes { + + public static final EntityType DRONE = register( + "drone", + EntityType.Builder.of(Drone::new, MobCategory.MONSTER).sized(0.8f, 1.98f) + ); + + private static EntityType register(String name, EntityType.Builder builder) { + var entityType = builder.build(name); + var resourceLocation = AzureLib.modResource(name); + Registry.register(BuiltInRegistries.ENTITY_TYPE, resourceLocation, entityType); + return entityType; + } + + public static void initialize() { + FabricDefaultAttributeRegistry.register(DRONE, Drone.createMonsterAttributes()); + } +} From c6d7dd6b480580a5c630727c420ffd4e9a98f29f Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Wed, 11 Dec 2024 12:59:07 -0500 Subject: [PATCH 013/224] Fixed animations not using partial ticks for entities for... some reason. Signed-off-by: = --- .../azure/azurelib/core2/animation/AzAnimator.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index 4434d934a..f8fe04da7 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -2,7 +2,6 @@ import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.AzureLibException; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.MolangQueries; @@ -12,7 +11,6 @@ import mod.azure.azurelib.core2.animation.primitive.AzAnimation; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.LivingEntity; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -44,14 +42,8 @@ protected AzAnimator() { public void animate(T animatable, AzAnimationState animationState) { var minecraft = Minecraft.getInstance(); - var currentTick = animationState.getData(DataTickets.TICK); - - if (currentTick == null) { - // TODO: We need to figure out how to get this instanceof check out of this abstract class. - currentTick = animatable instanceof LivingEntity livingEntity - ? (double) livingEntity.tickCount - : RenderUtils.getCurrentTick(); - } + // TODO: If encountering rendering smoothness issues, break glass (this used to be a DataTickets.TICK fetch). + var currentTick = RenderUtils.getCurrentTick(); if (firstTickTime == -1) { firstTickTime = currentTick + minecraft.getTimer().getGameTimeDeltaTicks(); From 6c039d0b6db5bdb5aee0f5992c5a9b4bd1329a10 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Wed, 11 Dec 2024 13:02:40 -0500 Subject: [PATCH 014/224] Fixed entities not having their own animator. Signed-off-by: = --- .../EntityMixin_AzEntityAnimatorCache.java | 26 ++++++++++++++ .../core2/animation/AzAnimatorAccessor.java | 6 ++++ .../core2/render/entity/AzEntityRenderer.java | 36 ++++++++++++++----- .../impl/AzEntityRendererPipeline.java | 7 ++-- .../resources/azurelib.fabric.mixins.json | 1 + .../main/resources/azurelib.neo.mixins.json | 1 + 6 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java new file mode 100644 index 000000000..d2d6f564a --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java @@ -0,0 +1,26 @@ +package mod.azure.azurelib.common.internal.mixins; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(Entity.class) +public abstract class EntityMixin_AzEntityAnimatorCache implements AzAnimatorAccessor { + + @Unique + @Nullable + private AzAnimator animator; + + @Override + public void setAnimator(@Nullable AzAnimator animator) { + this.animator = animator; + } + + @Override + public @Nullable AzAnimator getAnimator() { + return animator; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java new file mode 100644 index 000000000..088009147 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java @@ -0,0 +1,6 @@ +package mod.azure.azurelib.core2.animation; + +public interface AzAnimatorAccessor { + AzAnimator getAnimator(); + void setAnimator(AzAnimator animator); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 087b5202d..16f5d62f9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -2,6 +2,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; @@ -27,17 +28,14 @@ public abstract class AzEntityRenderer extends EntityRenderer< private float scaleHeight = 1; private final AzEntityRendererPipeline azEntityRendererPipeline; private final List> renderLayers; - private final AzEntityAnimator azAnimator; + + @Nullable + private AzEntityAnimator reusedAzEntityAnimator; protected AzEntityRenderer(EntityRendererProvider.Context context) { super(context); this.azEntityRendererPipeline = new AzEntityRendererPipeline<>(this); this.renderLayers = new ObjectArrayList<>(); - this.azAnimator = createAnimator(); - - if (azAnimator != null) { - azAnimator.registerControllers(azAnimator.getAnimationControllerContainer()); - } } protected abstract @NotNull ResourceLocation getModelLocation(T entity); @@ -48,13 +46,33 @@ public void superRender(@NotNull T entity, float entityYaw, float partialTick, @ @Override public void render(@NotNull T entity, float entityYaw, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource bufferSource, int packedLight) { + // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for the entity. + @SuppressWarnings("unchecked") + var entityAnimatorCache = (AzAnimatorAccessor) entity; + AzEntityAnimator cachedEntityAnimator = (AzEntityAnimator) entityAnimatorCache.getAnimator(); + + if (cachedEntityAnimator == null) { + // If the cached animator is null, create a new one. We use a separate reference here just for some + cachedEntityAnimator = createAnimator(); + + if (cachedEntityAnimator != null) { + // If the new animator we created is not null, then register its controllers. + cachedEntityAnimator.registerControllers(cachedEntityAnimator.getAnimationControllerContainer()); + // Also cache the animator so that the next time we fetch the animator, it's ready for us. + entityAnimatorCache.setAnimator(cachedEntityAnimator); + } + } + var modelResourceLocation = getModelLocation(entity); var bakedGeoModel = AzBakedModelCache.getInstance().getNullable(modelResourceLocation); - if (bakedGeoModel != null) { - azAnimator.getAnimationProcessor().setActiveModel(bakedGeoModel); + if (cachedEntityAnimator != null && bakedGeoModel != null) { + cachedEntityAnimator.getAnimationProcessor().setActiveModel(bakedGeoModel); } + // Point the renderer's current animator reference to the cached entity animator before rendering. + reusedAzEntityAnimator = cachedEntityAnimator; + // Execute the render pipeline. azEntityRendererPipeline.defaultRender(poseStack, bakedGeoModel, entity, bufferSource, null, null, entityYaw, partialTick, packedLight); } @@ -151,7 +169,7 @@ public int getBlockLightLevel(@NotNull T entity, @NotNull BlockPos pos) { } public AzEntityAnimator getAnimator() { - return azAnimator; + return reusedAzEntityAnimator; } public float getScaleHeight() { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java index d03c38bcf..d3cf1b89e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -209,8 +209,11 @@ public void actuallyRender( // this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); var animator = azEntityRenderer.getAnimator(); - var animationState = animator.createAnimationState(animatable, limbSwing, limbSwingAmount, partialTick); - animator.animate(animatable, animationState); + + if (animator != null) { + var animationState = animator.createAnimationState(animatable, limbSwing, limbSwingAmount, partialTick); + animator.animate(animatable, animationState); + } } this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); diff --git a/fabric/src/main/resources/azurelib.fabric.mixins.json b/fabric/src/main/resources/azurelib.fabric.mixins.json index 0d6449856..0d7b0271d 100644 --- a/fabric/src/main/resources/azurelib.fabric.mixins.json +++ b/fabric/src/main/resources/azurelib.fabric.mixins.json @@ -9,6 +9,7 @@ "PlayerListMixin" ], "client": [ + "EntityMixin_AzEntityAnimatorCache", "ItemRendererAccessor", "MinecraftMixin", "MixinHumanoidArmorLayer", diff --git a/neo/src/main/resources/azurelib.neo.mixins.json b/neo/src/main/resources/azurelib.neo.mixins.json index f01cb3d8a..325c5ea4d 100644 --- a/neo/src/main/resources/azurelib.neo.mixins.json +++ b/neo/src/main/resources/azurelib.neo.mixins.json @@ -9,6 +9,7 @@ "PlayerListMixin" ], "client": [ + "EntityMixin_AzEntityAnimatorCache", "ItemRendererAccessor", "MinecraftMixin", "MixinItemRenderer", From bee0a05a3f8690540947727d5ef695f4ce18d05b Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Wed, 11 Dec 2024 13:47:36 -0500 Subject: [PATCH 015/224] Bit of cleanup. Signed-off-by: = --- .../core2/render/entity/AzEntityRenderer.java | 44 ++++++++++++------- .../render/pipeline/AzRendererPipeline.java | 41 ++++++++--------- 2 files changed, 48 insertions(+), 37 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 16f5d62f9..06f725b3d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import mod.azure.azurelib.core2.render.pipeline.impl.AzEntityRendererPipeline; @@ -46,10 +47,34 @@ public void superRender(@NotNull T entity, float entityYaw, float partialTick, @ @Override public void render(@NotNull T entity, float entityYaw, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource bufferSource, int packedLight) { + var cachedEntityAnimator = provideAnimator(entity); + var azBakedModel = provideBakedModel(entity, cachedEntityAnimator); + // Point the renderer's current animator reference to the cached entity animator before rendering. + reusedAzEntityAnimator = cachedEntityAnimator; + // Execute the render pipeline. + azEntityRendererPipeline.render(poseStack, azBakedModel, entity, bufferSource, null, null, entityYaw, partialTick, packedLight); + } + + protected @Nullable AzEntityAnimator createAnimator() { + return null; + } + + protected @Nullable AzBakedModel provideBakedModel(@NotNull T entity, AzEntityAnimator cachedEntityAnimator) { + var modelResourceLocation = getModelLocation(entity); + var bakedGeoModel = AzBakedModelCache.getInstance().getNullable(modelResourceLocation); + + if (cachedEntityAnimator != null && bakedGeoModel != null) { + cachedEntityAnimator.getAnimationProcessor().setActiveModel(bakedGeoModel); + } + + return bakedGeoModel; + } + + protected @Nullable AzEntityAnimator provideAnimator(T entity) { // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for the entity. @SuppressWarnings("unchecked") var entityAnimatorCache = (AzAnimatorAccessor) entity; - AzEntityAnimator cachedEntityAnimator = (AzEntityAnimator) entityAnimatorCache.getAnimator(); + var cachedEntityAnimator = (AzEntityAnimator) entityAnimatorCache.getAnimator(); if (cachedEntityAnimator == null) { // If the cached animator is null, create a new one. We use a separate reference here just for some @@ -62,22 +87,7 @@ public void render(@NotNull T entity, float entityYaw, float partialTick, @NotNu entityAnimatorCache.setAnimator(cachedEntityAnimator); } } - - var modelResourceLocation = getModelLocation(entity); - var bakedGeoModel = AzBakedModelCache.getInstance().getNullable(modelResourceLocation); - - if (cachedEntityAnimator != null && bakedGeoModel != null) { - cachedEntityAnimator.getAnimationProcessor().setActiveModel(bakedGeoModel); - } - - // Point the renderer's current animator reference to the cached entity animator before rendering. - reusedAzEntityAnimator = cachedEntityAnimator; - // Execute the render pipeline. - azEntityRendererPipeline.defaultRender(poseStack, bakedGeoModel, entity, bufferSource, null, null, entityYaw, partialTick, packedLight); - } - - protected @Nullable AzEntityAnimator createAnimator() { - return null; + return cachedEntityAnimator; } /** diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index 52a8aef27..c214f7d6c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -63,8 +63,8 @@ public abstract RenderType getDefaultRenderType(T animatable, ResourceLocation t * Initial access point for rendering. It all begins here.
    * All AzureLib renderers should immediately defer their respective default {@code render} calls to this, for consistent handling */ - public void defaultRender(PoseStack poseStack, AzBakedModel model, T animatable, MultiBufferSource bufferSource, @Nullable RenderType renderType, @Nullable VertexConsumer buffer, - float yaw, float partialTick, int packedLight) { + public void render(PoseStack poseStack, AzBakedModel model, T animatable, MultiBufferSource bufferSource, @Nullable RenderType renderType, @Nullable VertexConsumer buffer, + float yaw, float partialTick, int packedLight) { poseStack.pushPose(); var renderColor = getRenderColor(animatable, partialTick, packedLight).argbInt(); @@ -99,7 +99,7 @@ public void defaultRender(PoseStack poseStack, AzBakedModel model, T animatable, * Re-renders the provided {@link AzBakedModel}.
    * Usually you'd use this for rendering alternate {@link RenderType} layers or for sub-model rendering whilst inside a {@link AzRenderLayer} or similar */ - public void reRender(AzBakedModel model, PoseStack poseStack, MultiBufferSource bufferSource, T animatable, + protected void reRender(AzBakedModel model, PoseStack poseStack, MultiBufferSource bufferSource, T animatable, RenderType renderType, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay, int colour) { poseStack.pushPose(); @@ -112,7 +112,7 @@ public void reRender(AzBakedModel model, PoseStack poseStack, MultiBufferSource /** * The actual render method that sub-type renderers should override to handle their specific rendering tasks.
    */ - public void actuallyRender(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, + protected void actuallyRender(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) { updateAnimatedTextureFrame(animatable); @@ -126,7 +126,7 @@ public void actuallyRender(PoseStack poseStack, T animatable, AzBakedModel model /** * Renders the provided {@link AzBone} and its associated child bones */ - public void renderRecursively(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, + protected void renderRecursively(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) { poseStack.pushPose(); @@ -144,7 +144,7 @@ public void renderRecursively(PoseStack poseStack, T animatable, AzBone bone, Re /** * Renders the {@link GeoCube GeoCubes} associated with a given {@link AzBone} */ - public void renderCubesOfBone(PoseStack poseStack, AzBone bone, VertexConsumer buffer, int packedLight, + protected void renderCubesOfBone(PoseStack poseStack, AzBone bone, VertexConsumer buffer, int packedLight, int packedOverlay, int colour) { if (bone.isHidden()) return; @@ -160,7 +160,7 @@ public void renderCubesOfBone(PoseStack poseStack, AzBone bone, VertexConsumer b * Render the child bones of a given {@link AzBone}.
    * Note that this does not render the bone itself. That should be done through {@link AzRendererPipeline#renderCubesOfBone} separately */ - public void renderChildBones(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, + protected void renderChildBones(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) { if (bone.isHidingChildren()) return; @@ -174,7 +174,7 @@ public void renderChildBones(PoseStack poseStack, T animatable, AzBone bone, Ren * Renders an individual {@link GeoCube}.
    * This tends to be called recursively from something like {@link AzRendererPipeline#renderCubesOfBone} */ - public void renderCube(PoseStack poseStack, GeoCube cube, VertexConsumer buffer, int packedLight, + protected void renderCube(PoseStack poseStack, GeoCube cube, VertexConsumer buffer, int packedLight, int packedOverlay, int colour) { RenderUtils.translateToPivotPoint(poseStack, cube); RenderUtils.rotateMatrixAroundCube(poseStack, cube); @@ -197,7 +197,7 @@ public void renderCube(PoseStack poseStack, GeoCube cube, VertexConsumer buffer, /** * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for rendering */ - public void createVerticesOfQuad(GeoQuad quad, Matrix4f poseState, Vector3f normal, VertexConsumer buffer, + protected void createVerticesOfQuad(GeoQuad quad, Matrix4f poseState, Vector3f normal, VertexConsumer buffer, int packedLight, int packedOverlay, int colour) { for (var vertex : quad.vertices()) { var position = vertex.position(); @@ -211,7 +211,7 @@ public void createVerticesOfQuad(GeoQuad quad, Matrix4f poseState, Vector3f norm /** * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#preRender pre-render} actions. */ - public void preApplyRenderLayers(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, MultiBufferSource bufferSource, + protected void preApplyRenderLayers(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { for (var renderLayer : getRenderLayers()) { renderLayer.preRender(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); @@ -221,7 +221,7 @@ public void preApplyRenderLayers(PoseStack poseStack, T animatable, AzBakedModel /** * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#renderForBone per-bone} render actions. */ - public void applyRenderLayersForBone(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, + protected void applyRenderLayersForBone(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { for (var renderLayer : getRenderLayers()) { renderLayer.renderForBone(poseStack, animatable, bone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); @@ -231,7 +231,7 @@ public void applyRenderLayersForBone(PoseStack poseStack, T animatable, AzBone b /** * Render the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer */ - public void applyRenderLayers(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, MultiBufferSource bufferSource, + protected void applyRenderLayers(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { for (var renderLayer : getRenderLayers()) { renderLayer.render(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); @@ -243,19 +243,19 @@ public void applyRenderLayers(PoseStack poseStack, T animatable, AzBakedModel mo * work such as scaling and translating.
    * {@link PoseStack} translations made here are kept until the end of the render process */ - public void preRender(PoseStack poseStack, T animatable, AzBakedModel model, @Nullable MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, + protected void preRender(PoseStack poseStack, T animatable, AzBakedModel model, @Nullable MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {} /** * Called after rendering the model to buffer. Post-render modifications should be performed here.
    * {@link PoseStack} transformations will be unused and lost once this method ends */ - public void postRender(PoseStack poseStack, T animatable, AzBakedModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {} + protected void postRender(PoseStack poseStack, T animatable, AzBakedModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {} /** * Call after all other rendering work has taken place, including reverting the {@link PoseStack}'s state. This method is not called in {@link AzRendererPipeline#reRender re-render} */ - public void renderFinal(PoseStack poseStack, T animatable, AzBakedModel model, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, + protected void renderFinal(PoseStack poseStack, T animatable, AzBakedModel model, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay, int colour) {} /** @@ -263,22 +263,23 @@ public void renderFinal(PoseStack poseStack, T animatable, AzBakedModel model, M *

    * Use this method to clean up any leftover persistent objects stored during rendering or any other post-render maintenance tasks as required */ - public void doPostRenderCleanup() {} + protected void doPostRenderCleanup() {} /** * Scales the {@link PoseStack} in preparation for rendering the model, excluding when re-rendering the model as part of a {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer} or external render call.
    * Override and call super with modified scale values as needed to further modify the scale of the model (E.G. child entities) */ - public void scaleModelForRender(float widthScale, float heightScale, PoseStack poseStack, T animatable, AzBakedModel model, boolean isReRender, float partialTick, int packedLight, int packedOverlay) { - if (!isReRender && (widthScale != 1 || heightScale != 1)) + protected void scaleModelForRender(float widthScale, float heightScale, PoseStack poseStack, T animatable, AzBakedModel model, boolean isReRender, float partialTick, int packedLight, int packedOverlay) { + if (!isReRender && (widthScale != 1 || heightScale != 1)) { poseStack.scale(widthScale, heightScale, widthScale); + } } /** * Gets a tint-applying color to render the given animatable with.
    * Returns {@link Color#WHITE} by default */ - public Color getRenderColor(T animatable, float partialTick, int packedLight) { + protected Color getRenderColor(T animatable, float partialTick, int packedLight) { return Color.WHITE; } @@ -288,7 +289,7 @@ public Color getRenderColor(T animatable, float partialTick, int packedLight) { * but can be used for other things like the {@link net.minecraft.world.entity.monster.Creeper} * white tint when exploding. */ - public int getPackedOverlay(T animatable, float u, float partialTick) { + protected int getPackedOverlay(T animatable, float u, float partialTick) { return OverlayTexture.NO_OVERLAY; } From b3f2d42139188cb9b3befb38dd11134e3eb89759 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Wed, 11 Dec 2024 13:47:55 -0500 Subject: [PATCH 016/224] Implemented AzAnimationDispatcher.java. Signed-off-by: = --- .../animation/AzAnimationDispatcher.java | 43 +++++++++++++++++++ .../core2/animation/AzAnimatorAccessor.java | 4 +- .../AzAnimationControllerContainer.java | 5 +++ .../azurelib/fabric/core2/example/Drone.java | 12 ++++++ .../fabric/core2/example/DroneAnimator.java | 4 +- 5 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java new file mode 100644 index 000000000..c026e5c6e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java @@ -0,0 +1,43 @@ +package mod.azure.azurelib.core2.animation; + +import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimTriggerPacket; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; + +public class AzAnimationDispatcher { + + private final T entity; + + public AzAnimationDispatcher(T entity) { + this.entity = entity; + } + + public void dispatch(@Nullable String controllerName, String animationName) { + if (entity.level().isClientSide()) { + @SuppressWarnings("unchecked") + var entityAnimatorCache = (AzAnimatorAccessor) entity; + var cachedEntityAnimator = (AzEntityAnimator) entityAnimatorCache.getAnimator(); + + if (cachedEntityAnimator == null) { + return; + } + + var controller = cachedEntityAnimator.getAnimationControllerContainer().getOrNull(controllerName); + + if (controller != null) { + controller.tryTriggerAnimation(animationName); + } + } else { + var entityId = entity.getId(); + var entityAnimTriggerPacket = new EntityAnimTriggerPacket( + entityId, + false, + controllerName, + animationName + ); + Services.NETWORK.sendToTrackingEntityAndSelf(entityAnimTriggerPacket, entity); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java index 088009147..7f0225580 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java @@ -1,6 +1,8 @@ package mod.azure.azurelib.core2.animation; +import org.jetbrains.annotations.Nullable; + public interface AzAnimatorAccessor { - AzAnimator getAnimator(); + @Nullable AzAnimator getAnimator(); void setAnimator(AzAnimator animator); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerContainer.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerContainer.java index 8c06ca6dd..e6a53425a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerContainer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerContainer.java @@ -1,6 +1,7 @@ package mod.azure.azurelib.core2.animation.controller; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Map; @@ -22,6 +23,10 @@ public final void add(AzAnimationController controller, AzAnimationController } } + public @Nullable AzAnimationController getOrNull(String controllerName) { + return animationControllersByName.get(controllerName); + } + public Collection> getAll() { return animationControllersByName.values(); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java index a4483badc..a4eb87e18 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java @@ -1,12 +1,24 @@ package mod.azure.azurelib.fabric.core2.example; +import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.level.Level; public class Drone extends Monster { + private final AzAnimationDispatcher animationDispatcher; + public Drone(EntityType entityType, Level level) { super(entityType, level); + this.animationDispatcher = new AzAnimationDispatcher<>(this); + } + + public void tick() { + super.tick(); + + if (this.level().isClientSide) { + animationDispatcher.dispatch("base_controller", "animation.idle"); + } } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java index 22e36b4d1..5f67ed1e5 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java @@ -21,10 +21,12 @@ public class DroneAnimator extends AzEntityAnimator { public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( new AzAnimationController<>(this, "base_controller", 0, this::handle) + .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) ); } + public PlayState handle(AzAnimationState event) { - return event.setAndContinue(IDLE_ANIMATION); + return PlayState.CONTINUE; } @Override From c0bd1ed4309b9a96d3003f54e3df0f4e661f92d5 Mon Sep 17 00:00:00 2001 From: AzureDoom Date: Wed, 11 Dec 2024 14:05:39 -0500 Subject: [PATCH 017/224] Adds spotless to multiloader-common.gradle --- .../src/main/groovy/multiloader-common.gradle | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/buildSrc/src/main/groovy/multiloader-common.gradle b/buildSrc/src/main/groovy/multiloader-common.gradle index 3e94563dd..85f092448 100644 --- a/buildSrc/src/main/groovy/multiloader-common.gradle +++ b/buildSrc/src/main/groovy/multiloader-common.gradle @@ -1,4 +1,5 @@ plugins { + id 'com.diffplug.spotless' id 'java-library' id 'maven-publish' id 'idea' @@ -143,4 +144,18 @@ idea { downloadSources = true downloadJavadoc = true } -} \ No newline at end of file +} + +spotless { + java { + eclipse().configFile("$rootDir/eclipse-formatter.xml") + endWithNewline() + importOrder("", "java", group.toString(), "\\#") + indentWithSpaces(4) + removeUnusedImports() + trimTrailingWhitespace() + } +} +tasks.build { + dependsOn("spotlessApply") +} From 6097d72d06d1d581896a1a590d44a89f2d7c270d Mon Sep 17 00:00:00 2001 From: AzureDoom Date: Wed, 11 Dec 2024 14:05:40 -0500 Subject: [PATCH 018/224] Update Common build.gradle to use spotless --- common/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/build.gradle b/common/build.gradle index 5a448f365..028722d21 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,6 +1,7 @@ plugins { id 'multiloader-common' id 'net.neoforged.moddev' + id 'com.diffplug.spotless' version "7.0.0.BETA3" } neoForge { @@ -42,4 +43,4 @@ configurations { artifacts { commonJava sourceSets.main.java.sourceDirectories.singleFile commonResources sourceSets.main.resources.sourceDirectories.singleFile -} \ No newline at end of file +} From 96dc3dee2d355a56888845ce441802397a566d8b Mon Sep 17 00:00:00 2001 From: AzureDoom Date: Wed, 11 Dec 2024 14:05:42 -0500 Subject: [PATCH 019/224] Update Fabric build.gradle to use spotless --- fabric/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fabric/build.gradle b/fabric/build.gradle index 83f2882b7..389cadf8f 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -2,6 +2,7 @@ plugins { id 'multiloader-loader' id 'fabric-loom' version "${fabric_loom_version}" id 'me.modmuss50.mod-publish-plugin' + id 'com.diffplug.spotless' version "7.0.0.BETA3" } dependencies { @@ -65,4 +66,4 @@ if (file('key.properties').exists()) { minecraftVersions.add(project.minecraft_version) } } -} \ No newline at end of file +} From 8c2f167c48ca99041c291b898705b448c27b9993 Mon Sep 17 00:00:00 2001 From: AzureDoom Date: Wed, 11 Dec 2024 14:05:44 -0500 Subject: [PATCH 020/224] Update NeoForge build.gradle to use spotless --- neo/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/neo/build.gradle b/neo/build.gradle index 6077cc786..d1a139d67 100644 --- a/neo/build.gradle +++ b/neo/build.gradle @@ -2,6 +2,7 @@ id 'multiloader-loader' id 'net.neoforged.moddev' id 'me.modmuss50.mod-publish-plugin' + id 'com.diffplug.spotless' version "7.0.0.BETA3" } neoForge { @@ -62,4 +63,4 @@ if (file('key.properties').exists()) { minecraftVersions.add(project.minecraft_version) } } -} \ No newline at end of file +} From 050b3739d954d018f68f8d6cc1e51a49d2541f19 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:29:31 -0500 Subject: [PATCH 021/224] spotless formatting --- .../common/api/client/helper/ClientUtils.java | 5 +- .../client/model/DefaultedBlockGeoModel.java | 9 +- .../client/model/DefaultedEntityGeoModel.java | 11 +- .../api/client/model/DefaultedGeoModel.java | 30 +- .../client/model/DefaultedItemGeoModel.java | 9 +- .../common/api/client/model/GeoModel.java | 57 +- .../renderer/DyeableGeoArmorRenderer.java | 70 +- .../renderer/DynamicGeoEntityRenderer.java | 241 ++-- .../api/client/renderer/GeoArmorRenderer.java | 260 ++-- .../api/client/renderer/GeoBlockRenderer.java | 229 ++-- .../client/renderer/GeoEntityRenderer.java | 514 ++++---- .../api/client/renderer/GeoItemRenderer.java | 316 ++--- .../client/renderer/GeoObjectRenderer.java | 216 ++-- .../renderer/GeoReplacedEntityRenderer.java | 494 +++---- .../dynamic/DynamicGeoArmorRenderer.java | 246 ++-- .../dynamic/DynamicGeoBlockRenderer.java | 255 ++-- .../dynamic/DynamicGeoItemRenderer.java | 245 ++-- .../dynamic/DynamicGeoObjectRenderer.java | 243 ++-- .../DynamicGeoReplacedEntityRenderer.java | 252 ++-- .../renderer/layer/AutoGlowingGeoLayer.java | 47 +- .../renderer/layer/BlockAndItemGeoLayer.java | 155 ++- .../renderer/layer/BoneFilterGeoLayer.java | 34 +- .../layer/FastBoneFilterGeoLayer.java | 46 +- .../client/renderer/layer/GeoRenderLayer.java | 70 +- .../layer/GeoRenderLayersContainer.java | 11 +- .../renderer/layer/ItemArmorGeoLayer.java | 213 ++-- .../common/ai/pathing/AzureNavigation.java | 82 +- .../api/common/animatable/GeoBlockEntity.java | 37 +- .../api/common/animatable/GeoEntity.java | 27 +- .../common/api/common/animatable/GeoItem.java | 77 +- .../common/animatable/GeoReplacedEntity.java | 40 +- .../common/api/common/config/Config.java | 13 +- .../api/common/config/TestingConfig.java | 27 +- .../common/entities/AzureVibrationUser.java | 24 +- .../common/api/common/helper/CommonUtils.java | 48 +- .../api/common/interfaces/AzureTicker.java | 43 +- .../CommonArmorMaterialRegistryInterface.java | 25 +- .../CommonBlockEntityRegistryInterface.java | 29 +- .../CommonBlockRegistryInterface.java | 13 +- .../CommonCreativeTabRegistryInterface.java | 29 +- .../CommonEntityRegistryInterface.java | 37 +- .../CommonFluidRegistryInterface.java | 11 +- .../registry/CommonItemRegistryInterface.java | 23 +- .../CommonMenuTypesRegistryInterface.java | 16 +- .../CommonParticleRegistryInterface.java | 25 +- .../CommonSoundRegistryInterface.java | 19 +- .../CommonStatusEffectRegistryInterface.java | 27 +- .../CommonStructureRegistryInterface.java | 19 +- .../common/api/common/tags/AzureTags.java | 3 +- .../internal/client/AzureLibClient.java | 23 +- .../internal/client/RenderProvider.java | 40 +- .../internal/client/config/ClientErrors.java | 13 +- .../client/config/DisplayAdapter.java | 241 ++-- .../client/config/DisplayAdapterManager.java | 22 +- .../client/config/IValidationHandler.java | 6 +- .../internal/client/config/WidgetAdder.java | 6 +- .../config/screen/AbstractConfigScreen.java | 205 ++- .../config/screen/ArrayConfigScreen.java | 102 +- .../config/screen/ConfigGroupScreen.java | 81 +- .../client/config/screen/ConfigScreen.java | 80 +- .../client/config/screen/DialogScreen.java | 74 +- .../client/config/widget/BooleanWidget.java | 35 +- .../client/config/widget/ColorWidget.java | 195 ++- .../config/widget/ConfigEntryWidget.java | 50 +- .../client/config/widget/ContainerWidget.java | 26 +- .../client/config/widget/EnumWidget.java | 28 +- .../client/model/data/EntityModelData.java | 17 +- .../internal/client/renderer/GeoRenderer.java | 532 ++++++-- .../internal/client/util/RenderUtils.java | 45 +- .../common/internal/common/AzureLib.java | 19 +- .../common/internal/common/AzureLibMod.java | 8 +- .../common/ai/pathing/AzurePathFinder.java | 12 +- .../animatable/SingletonGeoAnimatable.java | 43 +- .../common/blocks/TickingLightBlock.java | 24 +- .../common/blocks/TickingLightEntity.java | 12 +- .../common/cache/AnimatableIdCache.java | 18 +- .../internal/common/cache/AzureLibCache.java | 147 ++- .../common/cache/object/BakedGeoModel.java | 12 +- .../internal/common/cache/object/GeoBone.java | 57 +- .../internal/common/cache/object/GeoCube.java | 21 +- .../internal/common/cache/object/GeoQuad.java | 65 +- .../common/cache/object/GeoVertex.java | 12 +- .../cache/texture/AnimatableTexture.java | 172 +-- .../cache/texture/AutoGlowingTexture.java | 89 +- .../cache/texture/GeoAbstractTexture.java | 25 +- .../cache/texture/GeoGlowingTextureMeta.java | 119 +- .../internal/common/config/ConfigHolder.java | 138 +- .../common/config/ConfigHolderRegistry.java | 20 +- .../internal/common/config/ConfigUtils.java | 41 +- .../internal/common/config/Configurable.java | 20 +- .../common/config/adapter/TypeAdapter.java | 19 +- .../common/config/adapter/TypeAdapters.java | 22 +- .../common/config/adapter/TypeMatcher.java | 11 +- .../config/exception/ConfigReadException.java | 6 +- .../ConfigValueMissingException.java | 9 +- .../common/config/format/ConfigFormats.java | 6 +- .../common/config/format/GsonFormat.java | 27 +- .../common/config/format/IConfigFormat.java | 16 +- .../config/format/IConfigFormatHandler.java | 6 +- .../config/format/PropertiesFormat.java | 37 +- .../common/config/format/YamlFormat.java | 18 +- .../internal/common/config/io/ConfigIO.java | 42 +- .../common/config/io/FileWatchManager.java | 25 +- .../config/validate/NotificationSeverity.java | 13 +- .../config/validate/ValidationResult.java | 14 +- .../common/config/value/ArrayValue.java | 6 +- .../config/value/BooleanArrayValue.java | 31 +- .../common/config/value/BooleanValue.java | 23 +- .../common/config/value/CharValue.java | 23 +- .../common/config/value/ConfigValue.java | 22 +- .../common/config/value/DecimalValue.java | 17 +- .../common/config/value/DoubleArrayValue.java | 35 +- .../common/config/value/DoubleValue.java | 23 +- .../common/config/value/EnumArrayValue.java | 25 +- .../common/config/value/EnumValue.java | 19 +- .../common/config/value/FloatArrayValue.java | 35 +- .../common/config/value/FloatValue.java | 23 +- .../config/value/IDescriptionProvider.java | 6 +- .../common/config/value/IntArrayValue.java | 35 +- .../common/config/value/IntValue.java | 23 +- .../common/config/value/IntegerValue.java | 17 +- .../common/config/value/LongArrayValue.java | 35 +- .../common/config/value/LongValue.java | 23 +- .../common/config/value/ObjectValue.java | 26 +- .../common/config/value/StringArrayValue.java | 47 +- .../common/config/value/StringValue.java | 45 +- .../common/config/value/ValueData.java | 9 +- .../internal/common/constant/DataTickets.java | 57 +- .../common/constant/DefaultAnimations.java | 60 +- .../internal/common/loading/FileLoader.java | 22 +- .../common/loading/json/FormatVersion.java | 6 +- .../common/loading/json/raw/Bone.java | 10 +- .../common/loading/json/raw/Cube.java | 23 +- .../common/loading/json/raw/FaceUV.java | 15 +- .../common/loading/json/raw/LocatorClass.java | 15 +- .../common/loading/json/raw/LocatorValue.java | 13 +- .../loading/json/raw/MinecraftGeometry.java | 31 +- .../common/loading/json/raw/Model.java | 21 +- .../loading/json/raw/ModelProperties.java | 79 +- .../common/loading/json/raw/PolyMesh.java | 19 +- .../common/loading/json/raw/PolysUnion.java | 13 +- .../common/loading/json/raw/TextureMesh.java | 19 +- .../common/loading/json/raw/UVFaces.java | 18 +- .../common/loading/json/raw/UVUnion.java | 17 +- .../typeadapter/BakedAnimationsAdapter.java | 110 +- .../json/typeadapter/KeyFramesAdapter.java | 39 +- .../loading/object/BakedAnimations.java | 13 +- .../loading/object/BakedModelFactory.java | 239 ++-- .../common/loading/object/BoneStructure.java | 13 +- .../common/loading/object/GeometryTree.java | 17 +- .../common/network/AbstractPacket.java | 6 +- .../network/SerializableDataTicket.java | 24 +- .../network/packet/AnimDataSyncPacket.java | 55 +- .../network/packet/AnimTriggerPacket.java | 41 +- .../packet/BlockEntityAnimDataSyncPacket.java | 54 +- .../packet/BlockEntityAnimTriggerPacket.java | 42 +- .../packet/EntityAnimDataSyncPacket.java | 64 +- .../packet/EntityAnimTriggerPacket.java | 58 +- .../network/packet/SendConfigDataPacket.java | 90 +- .../registry/AzureBlocksEntityRegistry.java | 22 +- .../common/registry/AzureBlocksRegistry.java | 26 +- .../internal/common/util/AzureLibUtil.java | 33 +- .../common/internal/common/util/JsonUtil.java | 33 +- .../EntityMixin_AzEntityAnimatorCache.java | 5 +- .../internal/mixins/ItemRendererAccessor.java | 6 +- .../internal/mixins/MinecraftMixin.java | 28 +- .../mixins/MixinHumanoidArmorLayer.java | 68 +- .../internal/mixins/MixinItemRenderer.java | 37 +- .../internal/mixins/PlayerListMixin.java | 19 +- .../internal/mixins/TextureManagerMixin.java | 13 +- .../azurelib/common/platform/Services.java | 9 +- .../platform/services/AccessWidener.java | 3 +- .../common/platform/services/AzureEvents.java | 124 +- .../platform/services/AzureLibNetwork.java | 15 +- .../platform/services/CommonRegistry.java | 31 +- .../platform/services/IPlatformHelper.java | 9 +- .../core/animatable/GeoAnimatable.java | 9 +- .../instance/AnimatableInstanceCache.java | 22 +- .../InstancedAnimatableInstanceCache.java | 6 +- .../SingletonAnimatableInstanceCache.java | 7 +- .../animatable/model/CoreBakedGeoModel.java | 6 +- .../core/animatable/model/CoreGeoBone.java | 10 +- .../core/animatable/model/CoreGeoModel.java | 16 +- .../core/animation/AnimatableManager.java | 15 +- .../azurelib/core/animation/Animation.java | 59 +- .../core/animation/AnimationController.java | 173 +-- .../core/animation/AnimationProcessor.java | 115 +- .../core/animation/AnimationState.java | 21 +- .../ContextAwareAnimatableManager.java | 13 +- .../azurelib/core/animation/EasingType.java | 23 +- .../azurelib/core/animation/RawAnimation.java | 15 +- .../core/keyframe/AnimationPoint.java | 22 +- .../core/keyframe/AnimationPointQueue.java | 10 +- .../azurelib/core/keyframe/BoneAnimation.java | 17 +- .../core/keyframe/BoneAnimationQueue.java | 270 ++-- .../azurelib/core/keyframe/Keyframe.java | 21 +- .../core/keyframe/KeyframeLocation.java | 13 +- .../azurelib/core/keyframe/KeyframeStack.java | 12 +- .../event/CustomInstructionKeyframeEvent.java | 14 +- .../core/keyframe/event/KeyFrameEvent.java | 7 +- .../keyframe/event/ParticleKeyframeEvent.java | 14 +- .../keyframe/event/SoundKeyframeEvent.java | 14 +- .../data/CustomInstructionKeyframeData.java | 10 +- .../keyframe/event/data/KeyFrameData.java | 10 +- .../event/data/ParticleKeyframeData.java | 10 +- .../event/data/SoundKeyframeData.java | 10 +- .../azure/azurelib/core/math/Constant.java | 6 +- .../mod/azure/azurelib/core/math/Group.java | 6 +- .../mod/azure/azurelib/core/math/IValue.java | 6 +- .../azure/azurelib/core/math/MathBuilder.java | 43 +- .../mod/azure/azurelib/core/math/Negate.java | 6 +- .../azure/azurelib/core/math/Operation.java | 25 +- .../azure/azurelib/core/math/Operator.java | 6 +- .../mod/azure/azurelib/core/math/Ternary.java | 6 +- .../azure/azurelib/core/math/Variable.java | 6 +- .../core/math/functions/Function.java | 14 +- .../core/math/functions/classic/ACos.java | 6 +- .../core/math/functions/classic/ASin.java | 6 +- .../core/math/functions/classic/ATan.java | 6 +- .../core/math/functions/classic/ATan2.java | 6 +- .../core/math/functions/classic/Abs.java | 6 +- .../core/math/functions/classic/Cos.java | 6 +- .../core/math/functions/classic/Exp.java | 6 +- .../core/math/functions/classic/Ln.java | 6 +- .../core/math/functions/classic/Mod.java | 6 +- .../core/math/functions/classic/Pi.java | 6 +- .../core/math/functions/classic/Pow.java | 6 +- .../core/math/functions/classic/Sin.java | 6 +- .../core/math/functions/classic/Sqrt.java | 6 +- .../core/math/functions/limit/Clamp.java | 6 +- .../core/math/functions/limit/Max.java | 6 +- .../core/math/functions/limit/Min.java | 6 +- .../core/math/functions/rounding/Ceil.java | 6 +- .../core/math/functions/rounding/Floor.java | 6 +- .../core/math/functions/rounding/Round.java | 6 +- .../core/math/functions/rounding/Trunc.java | 6 +- .../core/math/functions/utility/DieRoll.java | 6 +- .../functions/utility/DieRollInteger.java | 6 +- .../math/functions/utility/HermiteBlend.java | 6 +- .../core/math/functions/utility/Lerp.java | 6 +- .../math/functions/utility/LerpRotate.java | 6 +- .../core/math/functions/utility/Random.java | 6 +- .../math/functions/utility/RandomInteger.java | 6 +- .../azurelib/core/molang/LazyVariable.java | 10 +- .../azurelib/core/molang/MolangException.java | 6 +- .../azurelib/core/molang/MolangParser.java | 27 +- .../azurelib/core/molang/MolangQueries.java | 6 +- .../expressions/MolangCompoundValue.java | 9 +- .../core/molang/expressions/MolangValue.java | 6 +- .../expressions/MolangVariableHolder.java | 6 +- .../core/molang/functions/CosDegrees.java | 6 +- .../core/molang/functions/SinDegrees.java | 6 +- .../mod/azure/azurelib/core/object/Axis.java | 6 +- .../mod/azure/azurelib/core/object/Color.java | 24 +- .../azurelib/core/object/DataTicket.java | 6 +- .../azure/azurelib/core/object/PlayState.java | 6 +- .../azurelib/core/state/BoneSnapshot.java | 6 +- .../azurelib/core/utils/Interpolation.java | 16 +- .../azurelib/core/utils/Interpolations.java | 6 +- .../azure/azurelib/core/utils/JsonUtils.java | 6 +- .../azure/azurelib/core/utils/MathHelper.java | 6 +- .../azure/azurelib/core/utils/MathUtils.java | 6 +- .../mod/azure/azurelib/core/utils/Timer.java | 8 +- .../azure/azurelib/core2/AzResourceCache.java | 6 +- .../animation/AzAnimationDispatcher.java | 5 +- .../core2/animation/AzAnimationProcessor.java | 42 +- .../core2/animation/AzAnimationState.java | 19 +- .../azurelib/core2/animation/AzAnimator.java | 23 +- .../core2/animation/AzAnimatorAccessor.java | 5 +- .../cache/AzBakedAnimationCache.java | 7 +- .../animation/cache/AzBoneSnapshotCache.java | 3 +- .../controller/AzAnimationController.java | 170 +-- .../AzAnimationControllerState.java | 2 +- .../handler/AzAnimationStateHandler.java | 8 +- .../handler/AzCustomKeyframeHandler.java | 2 +- .../handler/AzParticleKeyframeHandler.java | 2 +- .../handler/AzSoundKeyframeHandler.java | 2 +- .../AzCustomInstructionKeyframeEvent.java | 8 +- .../animation/event/AzKeyFrameEvent.java | 7 +- .../event/AzParticleKeyframeEvent.java | 6 +- .../animation/event/AzSoundKeyframeEvent.java | 14 +- .../animation/impl/AzEntityAnimator.java | 25 +- .../parse/AzBakedAnimationsAdapter.java | 98 +- .../animation/parse/AzKeyFramesAdapter.java | 39 +- .../animation/primitive/AzAnimation.java | 7 +- .../primitive/AzBakedAnimations.java | 1 + .../animation/primitive/AzKeyframes.java | 2 +- .../core2/animation/primitive/AzLoopType.java | 20 +- .../primitive/AzQueuedAnimation.java | 2 +- .../animation/primitive/AzRawAnimation.java | 4 +- .../core2/animation/primitive/AzStage.java | 2 +- .../azure/azurelib/core2/model/AzBone.java | 35 +- .../core2/model/cache/AzBakedModelCache.java | 13 +- .../model/factory/AzBakedModelFactory.java | 50 +- .../impl/AzBuiltinBakedModelFactory.java | 5 +- .../model/factory/primitive/VertexSet.java | 11 +- .../registry/AzBakedModelFactoryRegistry.java | 6 +- .../core2/render/entity/AzEntityRenderer.java | 55 +- .../core2/render/entity/RenderLeashUtil.java | 8 +- .../core2/render/layer/AzRenderLayer.java | 58 +- .../render/pipeline/AzRendererPipeline.java | 509 ++++++-- .../impl/AzEntityRendererPipeline.java | 143 ++- .../mod/azure/azurelib/sblforked/APIOnly.java | 11 +- .../azurelib/sblforked/SBLConstants.java | 12 +- .../azure/azurelib/sblforked/SBLLoader.java | 32 +- .../sblforked/api/SmartBrainOwner.java | 240 ++-- .../api/core/BrainActivityGroup.java | 165 +-- .../sblforked/api/core/SmartBrain.java | 893 +++++++------ .../api/core/SmartBrainProvider.java | 245 ++-- .../behaviour/AllApplicableBehaviours.java | 224 ++-- .../api/core/behaviour/DelayedBehaviour.java | 137 +- .../api/core/behaviour/ExtendedBehaviour.java | 600 +++++---- .../behaviour/FirstApplicableBehaviour.java | 47 +- .../api/core/behaviour/GroupBehaviour.java | 186 +-- .../api/core/behaviour/HeldBehaviour.java | 85 +- .../core/behaviour/OneRandomBehaviour.java | 59 +- .../core/behaviour/SequentialBehaviour.java | 92 +- .../custom/attack/AnimatableMeleeAttack.java | 137 +- .../custom/attack/AnimatableRangedAttack.java | 174 +-- .../behaviour/custom/attack/BowAttack.java | 63 +- .../custom/attack/ConditionlessAttack.java | 183 +-- .../attack/ConditionlessHeldAttack.java | 93 +- .../custom/look/LookAtAttackTarget.java | 64 +- .../behaviour/custom/look/LookAtTarget.java | 60 +- .../core/behaviour/custom/misc/AvoidSun.java | 56 +- .../custom/misc/BlockWithShield.java | 131 +- .../behaviour/custom/misc/BreakBlock.java | 251 ++-- .../custom/misc/BreedWithPartner.java | 243 ++-- .../custom/misc/CustomBehaviour.java | 65 +- .../custom/misc/CustomDelayedBehaviour.java | 30 +- .../custom/misc/CustomHeldBehaviour.java | 67 +- .../core/behaviour/custom/misc/HoldItem.java | 144 ++- .../api/core/behaviour/custom/misc/Idle.java | 30 +- .../custom/misc/InvalidateMemory.java | 84 +- .../api/core/behaviour/custom/misc/Panic.java | 344 ++--- .../custom/misc/ReactToUnreachableTarget.java | 140 +- .../behaviour/custom/move/AvoidEntity.java | 231 ++-- .../core/behaviour/custom/move/EscapeSun.java | 140 +- .../behaviour/custom/move/FleeTarget.java | 165 +-- .../custom/move/FloatToSurfaceOfFluid.java | 91 +- .../behaviour/custom/move/FollowEntity.java | 394 +++--- .../behaviour/custom/move/FollowOwner.java | 33 +- .../behaviour/custom/move/FollowParent.java | 89 +- .../custom/move/FollowTemptation.java | 263 ++-- .../custom/move/MoveToWalkTarget.java | 218 ++-- .../StayWithinDistanceOfAttackTarget.java | 276 ++-- .../behaviour/custom/move/StrafeTarget.java | 202 +-- .../custom/move/WalkOrRunToWalkTarget.java | 38 +- .../custom/path/SeekRandomNearbyPosition.java | 264 ++-- .../custom/path/SetRandomFlyingTarget.java | 34 +- .../custom/path/SetRandomHoverTarget.java | 227 ++-- .../custom/path/SetRandomSwimTarget.java | 48 +- .../custom/path/SetRandomWalkTarget.java | 256 ++-- .../path/SetWalkTargetToAttackTarget.java | 145 ++- .../custom/path/SetWalkTargetToBlock.java | 169 +-- .../custom/target/InvalidateAttackTarget.java | 160 +-- .../target/SetAdditionalAttackTargets.java | 245 ++-- .../custom/target/SetAttackTarget.java | 146 ++- .../custom/target/SetPlayerLookTarget.java | 86 +- .../custom/target/SetRandomLookTarget.java | 94 +- .../custom/target/SetRetaliateTarget.java | 201 +-- .../custom/target/TargetOrRetaliate.java | 282 ++-- .../core/navigation/ExtendedNavigator.java | 103 +- .../SmoothAmphibiousPathNavigation.java | 15 +- .../SmoothFlyingPathNavigation.java | 13 +- .../navigation/SmoothGroundNavigation.java | 37 +- .../SmoothWallClimberNavigation.java | 15 +- .../SmoothWaterBoundPathNavigation.java | 17 +- .../api/core/schedule/SmartBrainSchedule.java | 358 +++--- .../core/sensor/EntityFilteringSensor.java | 82 +- .../api/core/sensor/ExtendedSensor.java | 162 +-- .../api/core/sensor/PredicateSensor.java | 72 +- .../custom/GenericAttackTargetSensor.java | 59 +- .../custom/IncomingProjectilesSensor.java | 88 +- .../sensor/custom/NearbyBlocksSensor.java | 142 ++- .../core/sensor/custom/NearbyItemsSensor.java | 100 +- .../custom/UnreachableTargetSensor.java | 106 +- .../sensor/vanilla/AxolotlSpecificSensor.java | 87 +- .../sensor/vanilla/FrogSpecificSensor.java | 80 +- .../sensor/vanilla/HoglinSpecificSensor.java | 103 +- .../api/core/sensor/vanilla/HurtBySensor.java | 81 +- .../core/sensor/vanilla/InWaterSensor.java | 67 +- .../sensor/vanilla/ItemTemptingSensor.java | 215 ++-- .../sensor/vanilla/NearbyAdultSensor.java | 62 +- .../core/sensor/vanilla/NearbyBabySensor.java | 62 +- .../sensor/vanilla/NearbyGolemSensor.java | 101 +- .../sensor/vanilla/NearbyHostileSensor.java | 164 +-- .../vanilla/NearbyLivingEntitySensor.java | 155 +-- .../sensor/vanilla/NearbyPlayersSensor.java | 176 +-- .../sensor/vanilla/NearestHomeSensor.java | 157 +-- .../sensor/vanilla/NearestItemSensor.java | 103 +- .../vanilla/PiglinBruteSpecificSensor.java | 84 +- .../sensor/vanilla/PiglinSpecificSensor.java | 199 +-- .../sensor/vanilla/SecondaryPoiSensor.java | 154 +-- .../sensor/vanilla/WardenSpecificSensor.java | 85 +- .../object/BrainBehaviourConsumer.java | 30 +- .../object/BrainBehaviourPredicate.java | 35 +- .../object/ExtendedTargetingConditions.java | 57 +- .../FixedNearestVisibleLivingEntities.java | 20 +- .../sblforked/object/FreePositionTracker.java | 40 +- .../sblforked/object/SBLShufflingList.java | 205 +-- .../sblforked/object/SquareRadius.java | 42 +- .../sblforked/object/TriPredicate.java | 34 +- .../sblforked/registry/SBLMemoryTypes.java | 45 +- .../sblforked/registry/SBLSensors.java | 164 ++- .../azurelib/sblforked/util/BrainUtils.java | 1136 +++++++++-------- .../sblforked/util/EntityRetrievalUtil.java | 605 +++++---- .../azurelib/sblforked/util/RandomUtil.java | 561 ++++---- .../azurelib/sblforked/util/SensoryUtils.java | 47 +- .../azure/azurelib/fabric/ClientListener.java | 50 +- .../azurelib/fabric/FabricAzureLibMod.java | 7 +- .../azurelib/fabric/core2/example/Drone.java | 3 +- .../fabric/core2/example/DroneAnimator.java | 6 +- .../fabric/core2/example/DroneRenderer.java | 8 +- .../core2/example/ExampleEntityTypes.java | 3 +- .../azurelib/fabric/event/GeoRenderEvent.java | 515 ++++++-- .../integration/ModMenuIntegration.java | 9 +- .../fabric/platform/AzureLibEventsFabric.java | 186 ++- .../platform/FabricAzureLibInitializer.java | 55 +- .../platform/FabricAzureLibNetwork.java | 28 +- .../fabric/platform/FabricCommonRegistry.java | 80 +- .../fabric/platform/FabricPlatformHelper.java | 22 +- .../fabric/platform/FabricSBLForked.java | 29 +- .../azurelib/neoforge/ClientModListener.java | 52 +- .../neoforge/NeoForgeAzureLibMod.java | 54 +- .../MultiFluidNavigationElement.java | 16 +- .../MultiFluidSmoothGroundNavigation.java | 34 +- .../MultiFluidWalkNodeEvaluator.java | 55 +- .../neoforge/event/GeoRenderEvent.java | 258 +++- .../neoforge/mixins/ClientHooksMixin.java | 25 +- .../mixins/MixinHumanoidArmorLayer.java | 75 +- .../platform/AzureLibEventsNeoForge.java | 162 ++- .../platform/NeoForgeAzureLibInitializer.java | 5 +- .../platform/NeoForgeAzureLibNetwork.java | 27 +- .../platform/NeoForgeCommonRegistry.java | 130 +- .../platform/NeoForgePlatformHelper.java | 13 +- .../neoforge/platform/NeoForgeSBLForked.java | 38 +- 437 files changed, 17713 insertions(+), 13963 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/helper/ClientUtils.java b/common/src/main/java/mod/azure/azurelib/common/api/client/helper/ClientUtils.java index 543d98313..95e80520b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/helper/ClientUtils.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/helper/ClientUtils.java @@ -2,7 +2,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; import net.minecraft.util.Mth; @@ -10,6 +9,8 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; + /** * Helper class for segregating client-side code */ @@ -19,10 +20,12 @@ public record ClientUtils() { * Common reload KeyMapping for my various mods */ public static KeyMapping RELOAD; + /** * Common scope KeyMapping for my various mods */ public static KeyMapping SCOPE; + /** * Common scope KeyMapping for my various mods */ diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java index 7f20fd9fe..6b1270d29 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java @@ -1,15 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.model; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * {@link DefaultedGeoModel} specific to {@link net.minecraft.world.level.block.Block Blocks}. Using this class * pre-sorts provided asset paths into the "block" subdirectory diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java index 7e37ccf4b..0f22e6506 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java @@ -1,19 +1,18 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.model; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; + import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; import mod.azure.azurelib.common.internal.common.constant.DataTickets; import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animation.AnimationState; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; /** * {@link DefaultedGeoModel} specific to {@link net.minecraft.world.entity.Entity Entities}. Using this class pre-sorts diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java index 8c63be7b4..b8acf56c4 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java @@ -1,15 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.model; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Defaulted model class for AzureLib models.
    * This class allows for minimal boilerplate when implementing basic models, and saves on new classes.
    @@ -81,14 +80,15 @@ public DefaultedGeoModel withAltTexture(ResourceLocation altPath) { * @param basePath The base path of your resource. E.G. * *

    {@code ResourceLocation.fromNamespaceAndPath(MyMod.MOD_ID, "animal/goat")}
    + * * @return The formatted model resource path based on recommended defaults. E.G. * - *
    {@code "mymod:geo/entity/animal/goat.geo.json"}
    + *
    {@code "mymod:geo/entity/animal/goat.geo.json"}
    */ public ResourceLocation buildFormattedModelPath(ResourceLocation basePath) { return ResourceLocation.fromNamespaceAndPath( - basePath.getNamespace(), - "geo/" + subtype() + "/" + basePath.getPath() + ".geo.json" + basePath.getNamespace(), + "geo/" + subtype() + "/" + basePath.getPath() + ".geo.json" ); } @@ -99,14 +99,15 @@ public ResourceLocation buildFormattedModelPath(ResourceLocation basePath) { * @param basePath The base path of your resource. E.G. * *
    {@code ResourceLocation.fromNamespaceAndPath(MyMod.MOD_ID, "animal/goat")}
    + * * @return The formatted animation resource path based on recommended defaults. E.G. * - *
    {@code "mymod:animations/entity/animal/goat.animation.json"}
    + *
    {@code "mymod:animations/entity/animal/goat.animation.json"}
    */ public ResourceLocation buildFormattedAnimationPath(ResourceLocation basePath) { return ResourceLocation.fromNamespaceAndPath( - basePath.getNamespace(), - "animations/" + subtype() + "/" + basePath.getPath() + ".animation.json" + basePath.getNamespace(), + "animations/" + subtype() + "/" + basePath.getPath() + ".animation.json" ); } @@ -117,14 +118,15 @@ public ResourceLocation buildFormattedAnimationPath(ResourceLocation basePath) { * @param basePath The base path of your resource. E.G. * *
    {@code ResourceLocation.fromNamespaceAndPath(MyMod.MOD_ID, "animal/goat")}
    + * * @return The formatted texture resource path based on recommended defaults. E.G. * - *
    {@code "mymod:textures/entity/animal/goat.png"}
    + *
    {@code "mymod:textures/entity/animal/goat.png"}
    */ public ResourceLocation buildFormattedTexturePath(ResourceLocation basePath) { return ResourceLocation.fromNamespaceAndPath( - basePath.getNamespace(), - "textures/" + subtype() + "/" + basePath.getPath() + ".png" + basePath.getNamespace(), + "textures/" + subtype() + "/" + basePath.getPath() + ".png" ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java index c98555197..c7993b5a6 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java @@ -1,15 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.model; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * {@link DefaultedGeoModel} specific to {@link net.minecraft.world.item.Item Items}. Using this class pre-sorts * provided asset paths into the "item" subdirectory diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java index eb8cb7c9c..e4b060b55 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java @@ -1,12 +1,21 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.model; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.Vec3; + +import java.util.Optional; +import java.util.function.BiConsumer; + import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.AzureLibException; @@ -24,16 +33,6 @@ import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.MolangQueries; import mod.azure.azurelib.core.object.DataTicket; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.phys.Vec3; - -import java.util.Optional; -import java.util.function.BiConsumer; /** * Base class for all code-based model objects.
    @@ -144,8 +143,7 @@ public AnimationProcessor getAnimationProcessor() { * @param instanceId The unique instance id of the animatable being animated * @param dataConsumer The DataTicket + data consumer to be added to the AnimationEvent */ - public void addAdditionalStateData(T animatable, long instanceId, BiConsumer, T> dataConsumer) { - } + public void addAdditionalStateData(T animatable, long instanceId, BiConsumer, T> dataConsumer) {} @Override public void handleAnimations(T animatable, long instanceId, AnimationState animationState) { @@ -155,15 +153,15 @@ public void handleAnimations(T animatable, long instanceId, AnimationState an if (currentTick == null) currentTick = animatable instanceof LivingEntity livingEntity - ? (double) livingEntity.tickCount - : RenderUtils.getCurrentTick(); + ? (double) livingEntity.tickCount + : RenderUtils.getCurrentTick(); if (animatableManager.getFirstTickTime() == -1) animatableManager.startedAt(currentTick + mc.getTimer().getGameTimeDeltaTicks()); double currentFrameTime = currentTick - animatableManager.getFirstTickTime(); boolean isReRender = !animatableManager.isFirstTick() && currentFrameTime == animatableManager - .getLastUpdateTime(); + .getLastUpdateTime(); if (isReRender && instanceId == this.lastRenderedInstance) return; @@ -187,12 +185,12 @@ public void handleAnimations(T animatable, long instanceId, AnimationState an if (!processor.getRegisteredBones().isEmpty()) processor.tickAnimation( - animatable, - this, - animatableManager, - this.animTime, - animationState, - crashIfBoneMissing() + animatable, + this, + animatableManager, + this.animTime, + animationState, + crashIfBoneMissing() ); setCustomAnimations(animatable, instanceId, animationState); @@ -210,12 +208,15 @@ public void applyMolangQueries(T animatable, double animTime) { if (animatable instanceof Entity entity) { parser.setMemoizedValue( - MolangQueries.DISTANCE_FROM_CAMERA, - () -> mc.gameRenderer.getMainCamera().getPosition().distanceTo(entity.position()) + MolangQueries.DISTANCE_FROM_CAMERA, + () -> mc.gameRenderer.getMainCamera().getPosition().distanceTo(entity.position()) ); parser.setMemoizedValue(MolangQueries.IS_ON_GROUND, () -> RenderUtils.booleanToFloat(entity.onGround())); parser.setMemoizedValue(MolangQueries.IS_IN_WATER, () -> RenderUtils.booleanToFloat(entity.isInWater())); - parser.setMemoizedValue(MolangQueries.IS_IN_WATER_OR_RAIN, () -> RenderUtils.booleanToFloat(entity.isInWaterOrRain())); + parser.setMemoizedValue( + MolangQueries.IS_IN_WATER_OR_RAIN, + () -> RenderUtils.booleanToFloat(entity.isInWaterOrRain()) + ); parser.setMemoizedValue(MolangQueries.IS_ON_FIRE, () -> RenderUtils.booleanToFloat(entity.isOnFire())); if (entity instanceof LivingEntity livingEntity) { diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DyeableGeoArmorRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DyeableGeoArmorRenderer.java index 5b3b6554a..57d05b5b5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DyeableGeoArmorRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DyeableGeoArmorRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -10,11 +8,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.objects.ObjectArraySet; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.core.object.Color; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.util.FastColor; import net.minecraft.world.item.Item; @@ -24,12 +17,19 @@ import java.util.Collection; import java.util.Set; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.core.object.Color; + /** * A dyeable armour renderer for AzureLib armor models. */ public abstract class DyeableGeoArmorRenderer extends GeoArmorRenderer { protected final Set dyeableBones = new ObjectArraySet<>(); + protected BakedGeoModel lastModel = null; protected DyeableGeoArmorRenderer(GeoModel model) { @@ -38,28 +38,28 @@ protected DyeableGeoArmorRenderer(GeoModel model) { @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - @Nullable MultiBufferSource bufferSource, - @Nullable VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + @Nullable MultiBufferSource bufferSource, + @Nullable VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { super.preRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); if (!isReRender) @@ -68,12 +68,12 @@ public void preRender( @Override public void renderCubesOfBone( - PoseStack poseStack, - GeoBone bone, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.dyeableBones.contains(bone)) { final Color color = getColorForBone(bone); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DynamicGeoEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DynamicGeoEntityRenderer.java index 4372ce219..1d08ec5f0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DynamicGeoEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DynamicGeoEntityRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -11,10 +9,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRendererProvider; @@ -27,6 +21,11 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Extended special-entity renderer for more advanced or dynamic models.
    * Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider @@ -35,7 +34,7 @@ public abstract class DynamicGeoEntityRenderer extends GeoEntityRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; @@ -67,11 +66,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -82,14 +81,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -99,17 +98,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -123,10 +122,10 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.animatable.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.animatable.position().toVector3f()) ); } @@ -134,14 +133,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -151,49 +150,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -205,30 +204,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -239,23 +238,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -266,13 +265,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -280,23 +279,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java index 3274835d7..42fd8e223 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java @@ -1,28 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; -import mod.azure.azurelib.core.object.Color; import net.minecraft.client.Minecraft; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.ModelLayers; @@ -43,6 +27,21 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; +import mod.azure.azurelib.core.object.Color; + /** * Base {@link GeoRenderer} for rendering in-world armor specifically.
    * All custom armor added to be rendered in-world by AzureLib should use an instance of this class. @@ -55,13 +54,21 @@ public class GeoArmorRenderer extends HumanoidModel im protected final GeoRenderLayersContainer renderLayers = new GeoRenderLayersContainer<>(this); protected final GeoModel model; + public BakedGeoModel lastModel = null; + protected T animatable; + protected HumanoidModel baseModel; + protected float scaleWidth = 1; + protected float scaleHeight = 1; + protected Matrix4f entityRenderTranslations = new Matrix4f(); + protected Matrix4f modelRenderTranslations = new Matrix4f(); + protected GeoBone head = null; protected GeoBone body = null; @@ -143,10 +150,10 @@ public long getInstanceId(T animatable) { */ @Override public RenderType getRenderType( - T animatable, - ResourceLocation texture, - @org.jetbrains.annotations.Nullable MultiBufferSource bufferSource, - float partialTick + T animatable, + ResourceLocation texture, + @org.jetbrains.annotations.Nullable MultiBufferSource bufferSource, + float partialTick ) { return RenderType.armorCutoutNoCull(texture); } @@ -280,16 +287,16 @@ public GeoBone getLeftBootBone() { */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - @Nullable MultiBufferSource bufferSource, - @Nullable VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + @Nullable MultiBufferSource bufferSource, + @Nullable VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.entityRenderTranslations = new Matrix4f(poseStack.last().pose()); @@ -298,15 +305,15 @@ public void preRender( applyBaseTransformations(this.baseModel); scaleModelForBaby(poseStack, animatable, partialTick, isReRender); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); if (!(this.currentEntity instanceof GeoAnimatable)) @@ -320,34 +327,37 @@ public void preRender( */ @Override public Color getRenderColor(T animatable, float partialTick, int packedLight) { - return this.currentStack.is(ItemTags.DYEABLE) ? Color.ofOpaque( - DyedItemColor.getOrDefault(this.currentStack, -6265536)) : Color.WHITE; + return this.currentStack.is(ItemTags.DYEABLE) + ? Color.ofOpaque( + DyedItemColor.getOrDefault(this.currentStack, -6265536) + ) + : Color.WHITE; } @Override public void renderToBuffer( - @NotNull PoseStack poseStack, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int var5 + @NotNull PoseStack poseStack, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int var5 ) { Minecraft mc = Minecraft.getInstance(); MultiBufferSource bufferSource = Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); if ( - Minecraft.getInstance().levelRenderer.shouldShowEntityOutlines() && mc.shouldEntityAppearGlowing( - this.currentEntity - ) + Minecraft.getInstance().levelRenderer.shouldShowEntityOutlines() && mc.shouldEntityAppearGlowing( + this.currentEntity + ) ) bufferSource = Minecraft.getInstance().levelRenderer.renderBuffers.outlineBufferSource(); float partialTick = mc.getTimer().getGameTimeDeltaTicks(); RenderType renderType = getRenderType( - this.animatable, - getTextureLocation(this.animatable), - bufferSource, - partialTick + this.animatable, + getTextureLocation(this.animatable), + bufferSource, + partialTick ); buffer = ItemRenderer.getArmorFoilBuffer(bufferSource, renderType, this.currentStack.hasFoil()); @@ -361,17 +371,17 @@ public void renderToBuffer( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); poseStack.translate(0, 24 / 16f, 0); @@ -392,17 +402,17 @@ public void actuallyRender( this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); } @@ -412,17 +422,17 @@ public void actuallyRender( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); @@ -431,22 +441,22 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix(RenderUtils.translateMatrix(localMatrix, GeoArmorRendererConstants.ZERO)); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) ); } GeoRenderer.super.renderRecursively( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -480,10 +490,10 @@ protected void grabRelevantBones(BakedGeoModel bakedModel) { * @param baseModel The default (vanilla) model that would have been rendered if this model hadn't replaced it */ public void prepForRender( - @Nullable Entity entity, - ItemStack stack, - @Nullable EquipmentSlot slot, - @Nullable HumanoidModel baseModel + @Nullable Entity entity, + ItemStack stack, + @Nullable EquipmentSlot slot, + @Nullable HumanoidModel baseModel ) { if (entity == null || slot == null || baseModel == null) return; @@ -680,8 +690,8 @@ protected void setBoneVisible(@Nullable GeoBone bone, boolean visible) { public void updateAnimatedTextureFrame(T animatable) { if (this.currentEntity != null) AnimatableTexture.setAndUpdate( - getTextureLocation(animatable), - this.currentEntity.getId() + this.currentEntity.tickCount + getTextureLocation(animatable), + this.currentEntity.getId() + this.currentEntity.tickCount ); } @@ -700,13 +710,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireArmorPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireArmorPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -714,12 +731,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireArmorPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireArmorPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java index b5944ab64..a3381503a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -11,18 +9,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; @@ -38,6 +24,19 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; + /** * Base {@link GeoRenderer} class for rendering {@link BlockEntity Blocks} specifically.
    * All blocks added to be rendered by AzureLib should use an instance of this class. @@ -128,40 +127,40 @@ public GeoBlockRenderer withScale(float scaleWidth, float scaleHeight) { */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.blockRenderTranslations = new Matrix4f(poseStack.last().pose()); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); } @Override public void render( - T animatable, - float partialTick, - PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight, - int packedOverlay + T animatable, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight, + int packedOverlay ) { this.animatable = animatable; @@ -175,17 +174,17 @@ public void render( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (!isReRender) { AnimationState animationState = new AnimationState(animatable, 0, 0, partialTick, false); @@ -203,17 +202,17 @@ public void actuallyRender( RenderSystem.setShaderTexture(0, getTextureLocation(animatable)); GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -222,17 +221,17 @@ public void actuallyRender( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); @@ -240,32 +239,32 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix( - new Matrix4f(localMatrix), - new Vector3f( - this.animatable.getBlockPos().getX(), - this.animatable.getBlockPos().getY(), - this.animatable.getBlockPos().getZ() - ) + RenderUtils.translateMatrix( + new Matrix4f(localMatrix), + new Vector3f( + this.animatable.getBlockPos().getX(), + this.animatable.getBlockPos().getY(), + this.animatable.getBlockPos().getZ() ) + ) ); } GeoRenderer.super.renderRecursively( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -312,9 +311,9 @@ protected Direction getFacing(T block) { @Override public void updateAnimatedTextureFrame(T animatable) { AnimatableTexture.setAndUpdate( - getTextureLocation(animatable), - animatable.getBlockPos().getX() + animatable.getBlockPos().getY() + animatable.getBlockPos().getZ() - + (int) animatable.getTick(animatable) + getTextureLocation(animatable), + animatable.getBlockPos().getX() + animatable.getBlockPos().getY() + animatable.getBlockPos().getZ() + + (int) animatable.getTick(animatable) ); } @@ -333,13 +332,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireBlockPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireBlockPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -347,12 +353,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireBlockPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireBlockPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java index 98cd65b9c..37af7a506 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -12,18 +10,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; @@ -47,6 +33,19 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; + /** * Base {@link GeoRenderer} class for rendering {@link Entity Entities} specifically.
    * All entities added to be rendered by AzureLib should use an instance of this class.
    @@ -80,21 +79,21 @@ public GeoEntityRenderer(EntityRendererProvider.Context renderManager, GeoModel< * duplicated here for flexible usage */ private static void renderLeashPiece( - VertexConsumer buffer, - Matrix4f positionMatrix, - float xDif, - float yDif, - float zDif, - int entityBlockLight, - int holderBlockLight, - int entitySkyLight, - int holderSkyLight, - float width, - float yOffset, - float xOffset, - float zOffset, - int segment, - boolean isLeashKnot + VertexConsumer buffer, + Matrix4f positionMatrix, + float xDif, + float yDif, + float zDif, + int entityBlockLight, + int holderBlockLight, + int entitySkyLight, + int holderSkyLight, + float width, + float yOffset, + float xOffset, + float zOffset, + int segment, + boolean isLeashKnot ) { float piecePosPercent = segment / 24f; int lerpBlockLight = (int) Mth.lerp(piecePosPercent, entityBlockLight, holderBlockLight); @@ -106,20 +105,20 @@ private static void renderLeashPiece( float blue = 0.3f * knotColourMod; float x = xDif * piecePosPercent; float y = yDif > 0.0f - ? yDif * piecePosPercent * piecePosPercent - : yDif - yDif * (1.0f - piecePosPercent) * (1.0f - piecePosPercent); + ? yDif * piecePosPercent * piecePosPercent + : yDif - yDif * (1.0f - piecePosPercent) * (1.0f - piecePosPercent); float z = zDif * piecePosPercent; buffer.addVertex(positionMatrix, x - xOffset, y + yOffset, z + zOffset) - .setColor(red, green, blue, 1) - .setLight( - packedLight - ); + .setColor(red, green, blue, 1) + .setLight( + packedLight + ); buffer.addVertex(positionMatrix, x + xOffset, y + width - yOffset, z - zOffset) - .setColor(red, green, blue, 1) - .setLight( - packedLight - ); + .setColor(red, green, blue, 1) + .setLight( + packedLight + ); } /** @@ -197,40 +196,40 @@ public GeoEntityRenderer withScale(float scaleWidth, float scaleHeight) { */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.entityRenderTranslations = new Matrix4f(poseStack.last().pose()); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); } @Override public void render( - T entity, - float entityYaw, - float partialTick, - PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight + T entity, + float entityYaw, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight ) { this.animatable = entity; @@ -244,17 +243,17 @@ public void render( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); @@ -262,19 +261,19 @@ public void actuallyRender( boolean shouldSit = animatable.isPassenger() && (animatable.getVehicle() != null); float lerpBodyRot = livingEntity == null - ? 0 - : Mth.rotLerp( + ? 0 + : Mth.rotLerp( partialTick, livingEntity.yBodyRotO, livingEntity.yBodyRot - ); + ); float lerpHeadRot = livingEntity == null - ? 0 - : Mth.rotLerp( + ? 0 + : Mth.rotLerp( partialTick, livingEntity.yHeadRotO, livingEntity.yHeadRot - ); + ); float netHeadYaw = lerpHeadRot - lerpBodyRot; if (shouldSit && animatable.getVehicle() instanceof LivingEntity livingentity) { @@ -296,9 +295,9 @@ public void actuallyRender( float eyePosOffset = livingEntity.getEyeHeight(Pose.STANDING) - 0.1F; poseStack.translate( - -bedDirection.getStepX() * eyePosOffset, - 0, - -bedDirection.getStepZ() * eyePosOffset + -bedDirection.getStepX() * eyePosOffset, + 0, + -bedDirection.getStepZ() * eyePosOffset ); } } @@ -313,9 +312,9 @@ public void actuallyRender( if (!shouldSit && animatable.isAlive() && livingEntity != null) { limbSwingAmount = Mth.lerp( - partialTick, - livingEntity.walkAnimation.speedOld, - livingEntity.walkAnimation.speed() + partialTick, + livingEntity.walkAnimation.speedOld, + livingEntity.walkAnimation.speed() ); limbSwing = livingEntity.walkAnimation.position() - livingEntity.walkAnimation.speed() * (1 - partialTick); @@ -332,24 +331,24 @@ public void actuallyRender( Vec3 velocity = animatable.getDeltaMovement(); float avgVelocity = (float) (Math.abs(velocity.x) + Math.abs(velocity.z) / 2f); AnimationState animationState = new AnimationState( - animatable, - limbSwing, - limbSwingAmount, - partialTick, - avgVelocity >= motionThreshold && limbSwingAmount != 0 + animatable, + limbSwing, + limbSwingAmount, + partialTick, + avgVelocity >= motionThreshold && limbSwingAmount != 0 ); long instanceId = getInstanceId(animatable); animationState.setData(DataTickets.TICK, animatable.getTick(animatable)); animationState.setData(DataTickets.ENTITY, animatable); animationState.setData( - DataTickets.ENTITY_MODEL_DATA, - new EntityModelData( - shouldSit, - livingEntity != null && livingEntity.isBaby(), - -netHeadYaw, - -headPitch - ) + DataTickets.ENTITY_MODEL_DATA, + new EntityModelData( + shouldSit, + livingEntity != null && livingEntity.isBaby(), + -netHeadYaw, + -headPitch + ) ); this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); this.model.handleAnimations(animatable, instanceId, animationState); @@ -359,17 +358,17 @@ public void actuallyRender( if (!animatable.isInvisibleTo(Minecraft.getInstance().player)) GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -380,27 +379,27 @@ public void actuallyRender( */ @Override public void applyRenderLayers( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { if (!animatable.isSpectator()) GeoRenderer.super.applyRenderLayers( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay ); } @@ -410,15 +409,15 @@ public void applyRenderLayers( */ @Override public void renderFinal( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { super.render(animatable, 0, partialTick, poseStack, bufferSource, packedLight); @@ -435,17 +434,17 @@ public void renderFinal( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -459,10 +458,10 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.animatable.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.animatable.position().toVector3f()) ); } @@ -475,54 +474,62 @@ public void renderRecursively( if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); } /** - * Applies rotation transformations to the renderer prior to render time to account for various entity states, default scale of 1 + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * default scale of 1 */ protected void applyRotations( - T animatable, - PoseStack poseStack, - float ageInTicks, - float rotationYaw, - float partialTick + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick ) { applyRotations(animatable, poseStack, ageInTicks, rotationYaw, partialTick, 1); } /** - * Applies rotation transformations to the renderer prior to render time to account for various entity states, scalable + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * scalable */ - protected void applyRotations(T animatable, PoseStack poseStack, float ageInTicks, float rotationYaw, - float partialTick, float nativeScale) { + protected void applyRotations( + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick, + float nativeScale + ) { if (isShaking(animatable)) - rotationYaw += (float)(Math.cos(animatable.tickCount * 3.25d) * Math.PI * 0.4d); + rotationYaw += (float) (Math.cos(animatable.tickCount * 3.25d) * Math.PI * 0.4d); if (!animatable.hasPose(Pose.SLEEPING)) poseStack.mulPose(Axis.YP.rotationDegrees(180f - rotationYaw)); @@ -531,20 +538,23 @@ protected void applyRotations(T animatable, PoseStack poseStack, float ageInTick if (livingEntity.deathTime > 0) { float deathRotation = (livingEntity.deathTime + partialTick - 1f) / 20f * 1.6f; - poseStack.mulPose(Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable))); - } - else if (livingEntity.isAutoSpinAttack()) { + poseStack.mulPose( + Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable)) + ); + } else if (livingEntity.isAutoSpinAttack()) { poseStack.mulPose(Axis.XP.rotationDegrees(-90f - livingEntity.getXRot())); poseStack.mulPose(Axis.YP.rotationDegrees((livingEntity.tickCount + partialTick) * -75f)); - } - else if (animatable.hasPose(Pose.SLEEPING)) { + } else if (animatable.hasPose(Pose.SLEEPING)) { Direction bedOrientation = livingEntity.getBedOrientation(); - poseStack.mulPose(Axis.YP.rotationDegrees(bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw)); + poseStack.mulPose( + Axis.YP.rotationDegrees( + bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw + ) + ); poseStack.mulPose(Axis.ZP.rotationDegrees(getDeathMaxRotation(animatable))); poseStack.mulPose(Axis.YP.rotationDegrees(270f)); - } - else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { + } else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { poseStack.translate(0, (animatable.getBbHeight() + 0.1f) / nativeScale, 0); poseStack.mulPose(Axis.ZP.rotationDegrees(180f)); } @@ -576,8 +586,8 @@ public boolean shouldShowName(T animatable) { return false; if ( - animatable instanceof Mob && (!animatable.shouldShowName() && (!animatable.hasCustomName() - || animatable != this.entityRenderDispatcher.crosshairPickEntity)) + animatable instanceof Mob && (!animatable.shouldShowName() && (!animatable.hasCustomName() + || animatable != this.entityRenderDispatcher.crosshairPickEntity)) ) return false; @@ -587,7 +597,7 @@ public boolean shouldShowName(T animatable) { if (entityTeam == null) return Minecraft.renderNames() && animatable != minecraft.getCameraEntity() && visibleToClient - && !animatable.isVehicle(); + && !animatable.isVehicle(); var playerTeam = minecraft.player.getTeam(); @@ -595,12 +605,12 @@ public boolean shouldShowName(T animatable) { case ALWAYS -> visibleToClient; case NEVER -> false; case HIDE_FOR_OTHER_TEAMS -> playerTeam == null - ? visibleToClient - : entityTeam.isAlliedTo( + ? visibleToClient + : entityTeam.isAlliedTo( playerTeam - ) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); + ) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); case HIDE_FOR_OWN_TEAM -> - playerTeam == null ? visibleToClient : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; + playerTeam == null ? visibleToClient : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; }; } @@ -623,11 +633,11 @@ public int getPackedOverlay(T animatable, float u, float partialTick) { * duplicated here for flexible usage */ public void renderLeash( - M mob, - float partialTick, - PoseStack poseStack, - MultiBufferSource bufferSource, - E leashHolder + M mob, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + E leashHolder ) { double lerpBodyAngle = (Mth.lerp(partialTick, mob.yBodyRotO, mob.yBodyRot) * Mth.DEG_TO_RAD) + Mth.HALF_PI; Vec3 leashOffset = mob.getLeashOffset(); @@ -648,11 +658,11 @@ public void renderLeash( BlockPos holderEyePos = BlockPos.containing(leashHolder.getEyePosition(partialTick)); int entityBlockLight = getBlockLightLevel((T) mob, entityEyePos); int holderBlockLight = leashHolder.isOnFire() - ? 15 - : leashHolder.level() + ? 15 + : leashHolder.level() .getBrightness( - LightLayer.BLOCK, - holderEyePos + LightLayer.BLOCK, + holderEyePos ); int entitySkyLight = mob.level().getBrightness(LightLayer.SKY, entityEyePos); int holderSkyLight = mob.level().getBrightness(LightLayer.SKY, holderEyePos); @@ -664,41 +674,41 @@ public void renderLeash( for (int segment = 0; segment <= 24; ++segment) { GeoEntityRenderer.renderLeashPiece( - vertexConsumer, - posMatrix, - xDif, - yDif, - zDif, - entityBlockLight, - holderBlockLight, - entitySkyLight, - holderSkyLight, - 0.025f, - 0.025f, - xOffset, - zOffset, - segment, - false + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.025f, + xOffset, + zOffset, + segment, + false ); } for (int segment = 24; segment >= 0; --segment) { GeoEntityRenderer.renderLeashPiece( - vertexConsumer, - posMatrix, - xDif, - yDif, - zDif, - entityBlockLight, - holderBlockLight, - entitySkyLight, - holderSkyLight, - 0.025f, - 0.0f, - xOffset, - zOffset, - segment, - true + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.0f, + xOffset, + zOffset, + segment, + true ); } @@ -719,8 +729,8 @@ public boolean isShaking(T entity) { @Override public void updateAnimatedTextureFrame(T animatable) { AnimatableTexture.setAndUpdate( - getTextureLocation(animatable), - animatable.getId() + (int) animatable.getTick(animatable) + getTextureLocation(animatable), + animatable.getId() + (int) animatable.getTick(animatable) ); } @@ -739,13 +749,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -753,12 +770,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java index 804a4d79b..c12a23051 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -11,19 +9,6 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; import net.minecraft.client.Minecraft; import net.minecraft.client.model.geom.EntityModelSet; import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; @@ -41,6 +26,20 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; + /** * Base {@link GeoRenderer} class for rendering {@link Item Items} specifically.
    * All items added to be rendered by AzureLib should use an instance of this class. @@ -69,9 +68,9 @@ public class GeoItemRenderer extends BlockEntity public GeoItemRenderer(GeoModel model) { this( - Minecraft.getInstance().getBlockEntityRenderDispatcher(), - Minecraft.getInstance().getEntityModels(), - model + Minecraft.getInstance().getBlockEntityRenderDispatcher(), + Minecraft.getInstance().getEntityModels(), + model ); } @@ -174,43 +173,43 @@ public GeoItemRenderer withScale(float scaleWidth, float scaleHeight) { */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.itemRenderTranslations = new Matrix4f(poseStack.last().pose()); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); if (!isReRender) - poseStack.translate(0.5f, this.useNewOffset() ? 0.0f :0.51f, 0.5f); + poseStack.translate(0.5f, this.useNewOffset() ? 0.0f : 0.51f, 0.5f); } @Override public void renderByItem( - ItemStack stack, - ItemDisplayContext transformType, - PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight, - int packedOverlay + ItemStack stack, + ItemDisplayContext transformType, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight, + int packedOverlay ) { this.animatable = (T) stack.getItem(); this.currentItemStack = stack; @@ -220,27 +219,27 @@ public void renderByItem( renderInGui(transformType, poseStack, bufferSource, packedLight, packedOverlay); } else { RenderType renderType = getRenderType( - this.animatable, - getTextureLocation(this.animatable), - bufferSource, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() + this.animatable, + getTextureLocation(this.animatable), + bufferSource, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() ); VertexConsumer buffer = ItemRenderer.getFoilBufferDirect( - bufferSource, - renderType, - false, - this.currentItemStack != null && this.currentItemStack.hasFoil() + bufferSource, + renderType, + false, + this.currentItemStack != null && this.currentItemStack.hasFoil() ); defaultRender( - poseStack, - this.animatable, - bufferSource, - renderType, - buffer, - 0, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), - packedLight + poseStack, + this.animatable, + bufferSource, + renderType, + buffer, + 0, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), + packedLight ); } } @@ -251,45 +250,44 @@ public void renderByItem( * Just includes some additional required transformations and settings. */ protected void renderInGui( - ItemDisplayContext transformType, - PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight, - int packedOverlay + ItemDisplayContext transformType, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight, + int packedOverlay ) { if (this.useEntityGuiLighting) { Lighting.setupForEntityInInventory(); - } - else { + } else { Lighting.setupForFlatItems(); } MultiBufferSource.BufferSource defaultBufferSource = - bufferSource instanceof MultiBufferSource.BufferSource bufferSource2 - ? bufferSource2 - : Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); + bufferSource instanceof MultiBufferSource.BufferSource bufferSource2 + ? bufferSource2 + : Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); RenderType renderType = getRenderType( - this.animatable, - getTextureLocation(this.animatable), - defaultBufferSource, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() + this.animatable, + getTextureLocation(this.animatable), + defaultBufferSource, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() ); VertexConsumer buffer = ItemRenderer.getFoilBufferDirect( - bufferSource, - renderType, - true, - this.currentItemStack != null && this.currentItemStack.hasFoil() + bufferSource, + renderType, + true, + this.currentItemStack != null && this.currentItemStack.hasFoil() ); poseStack.pushPose(); defaultRender( - poseStack, - this.animatable, - defaultBufferSource, - renderType, - buffer, - 0, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), - packedLight + poseStack, + this.animatable, + defaultBufferSource, + renderType, + buffer, + 0, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), + packedLight ); defaultBufferSource.endBatch(); RenderSystem.enableDepthTest(); @@ -304,17 +302,17 @@ protected void renderInGui( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (!isReRender) { AnimationState animationState = new AnimationState<>(animatable, 0, 0, partialTick, false); @@ -324,8 +322,8 @@ public void actuallyRender( animationState.setData(DataTickets.ITEM_RENDER_PERSPECTIVE, this.renderPerspective); animationState.setData(DataTickets.ITEMSTACK, this.currentItemStack); animatable.getAnimatableInstanceCache() - .getManagerForId(instanceId) - .setData(DataTickets.ITEM_RENDER_PERSPECTIVE, this.renderPerspective); + .getManagerForId(instanceId) + .setData(DataTickets.ITEM_RENDER_PERSPECTIVE, this.renderPerspective); this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); this.model.handleAnimations(animatable, instanceId, animationState); } @@ -333,17 +331,17 @@ public void actuallyRender( this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -352,17 +350,17 @@ public void actuallyRender( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); @@ -370,22 +368,22 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); } GeoRenderer.super.renderRecursively( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -403,17 +401,17 @@ public Vec3 getRenderOffset(Item entity, float f) { @Override public void updateAnimatedTextureFrame(T animatable) { AnimatableTexture.setAndUpdate( - getTextureLocation(animatable), - Item.getId(animatable) + (int) animatable.getTick(animatable) + getTextureLocation(animatable), + Item.getId(animatable) + (int) animatable.getTick(animatable) ); } /** * Determines whether to apply the y offset for a model due to the change in BlockBench 4.11. * - * @return {@code false} by default, meaning the Y-offset will be {@code 0.51f}. Override this - * method or change the return value to {@code true} to use the new Y-offset of {@code 0.0f} - * for anything created in 4.11+ of Blockbench. + * @return {@code false} by default, meaning the Y-offset will be {@code 0.51f}. Override this method or change the + * return value to {@code true} to use the new Y-offset of {@code 0.0f} for anything created in 4.11+ of + * Blockbench. */ public boolean useNewOffset() { return false; @@ -434,13 +432,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireItemPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireItemPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -448,12 +453,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireItemPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireItemPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java index d752a3ec1..f380d52df 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java @@ -1,14 +1,23 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4f; + +import java.util.List; + import mod.azure.azurelib.common.api.client.model.GeoModel; import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; @@ -20,16 +29,6 @@ import mod.azure.azurelib.common.platform.Services; import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimationState; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.entity.EntityRenderer; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; -import org.joml.Matrix4f; - -import java.util.List; /** * Base {@link GeoRenderer} class for rendering anything that isn't already handled by the other builtin GeoRenderer @@ -130,12 +129,12 @@ public GeoObjectRenderer withScale(float scaleWidth, float scaleHeight) { * @param packedLight The light level at the given render position for rendering */ public void render( - PoseStack poseStack, - T animatable, - @Nullable MultiBufferSource bufferSource, - @Nullable RenderType renderType, - @Nullable VertexConsumer buffer, - int packedLight + PoseStack poseStack, + T animatable, + @Nullable MultiBufferSource bufferSource, + @Nullable RenderType renderType, + @Nullable VertexConsumer buffer, + int packedLight ) { this.animatable = animatable; Minecraft mc = Minecraft.getInstance(); @@ -143,7 +142,16 @@ public void render( if (buffer == null) bufferSource = Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); - defaultRender(poseStack, animatable, bufferSource, renderType, buffer, 0, mc.getTimer().getGameTimeDeltaTicks(), packedLight); + defaultRender( + poseStack, + animatable, + bufferSource, + renderType, + buffer, + 0, + mc.getTimer().getGameTimeDeltaTicks(), + packedLight + ); } /** @@ -153,29 +161,29 @@ public void render( */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.objectRenderTranslations = new Matrix4f(poseStack.last().pose()); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); poseStack.translate(0.5f, 0.51f, 0.5f); @@ -188,17 +196,17 @@ public void preRender( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); @@ -213,17 +221,17 @@ public void actuallyRender( this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); } @@ -233,17 +241,17 @@ public void actuallyRender( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); @@ -251,22 +259,22 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset().toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset().toVector3f()) ); } GeoRenderer.super.renderRecursively( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -301,13 +309,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireObjectPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireObjectPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -315,12 +330,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireObjectPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireObjectPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java index f7d06daf8..8b8f4862a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -13,18 +11,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; @@ -48,6 +34,19 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; + /** * An alternate to {@link GeoEntityRenderer}, used specifically for replacing existing non-AzureLib entities with * AzureLib rendering dynamically, without the need for an additional entity class @@ -83,21 +82,21 @@ public GeoReplacedEntityRenderer(EntityRendererProvider.Context renderManager, G * duplicated here for flexible usage */ private static void renderLeashPiece( - VertexConsumer buffer, - Matrix4f positionMatrix, - float xDif, - float yDif, - float zDif, - int entityBlockLight, - int holderBlockLight, - int entitySkyLight, - int holderSkyLight, - float width, - float yOffset, - float xOffset, - float zOffset, - int segment, - boolean isLeashKnot + VertexConsumer buffer, + Matrix4f positionMatrix, + float xDif, + float yDif, + float zDif, + int entityBlockLight, + int holderBlockLight, + int entitySkyLight, + int holderSkyLight, + float width, + float yOffset, + float xOffset, + float zOffset, + int segment, + boolean isLeashKnot ) { float piecePosPercent = segment / 24f; int lerpBlockLight = (int) Mth.lerp(piecePosPercent, entityBlockLight, holderBlockLight); @@ -109,16 +108,16 @@ private static void renderLeashPiece( float blue = 0.3f * knotColourMod; float x = xDif * piecePosPercent; float y = yDif > 0.0f - ? yDif * piecePosPercent * piecePosPercent - : yDif - yDif * (1.0f - piecePosPercent) * (1.0f - piecePosPercent); + ? yDif * piecePosPercent * piecePosPercent + : yDif - yDif * (1.0f - piecePosPercent) * (1.0f - piecePosPercent); float z = zDif * piecePosPercent; buffer.addVertex(positionMatrix, x - xOffset, y + yOffset, z + zOffset) - .setColor(red, green, blue, 1) - .setLight(packedLight); + .setColor(red, green, blue, 1) + .setLight(packedLight); buffer.addVertex(positionMatrix, x + xOffset, y + width - yOffset, z - zOffset) - .setColor(red, green, blue, 1) - .setLight(packedLight); + .setColor(red, green, blue, 1) + .setLight(packedLight); } /** @@ -207,40 +206,40 @@ public GeoReplacedEntityRenderer withScale(float scaleWidth, float scaleHe */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.entityRenderTranslations = new Matrix4f(poseStack.last().pose()); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); } @Override public void render( - E entity, - float entityYaw, - float partialTick, - PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight + E entity, + float entityYaw, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight ) { this.currentEntity = entity; @@ -254,17 +253,17 @@ public void render( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); @@ -272,11 +271,11 @@ public void actuallyRender( boolean shouldSit = this.currentEntity.isPassenger() && (this.currentEntity.getVehicle() != null); float lerpBodyRot = livingEntity == null - ? 0 - : Mth.rotLerp(partialTick, livingEntity.yBodyRotO, livingEntity.yBodyRot); + ? 0 + : Mth.rotLerp(partialTick, livingEntity.yBodyRotO, livingEntity.yBodyRot); float lerpHeadRot = livingEntity == null - ? 0 - : Mth.rotLerp(partialTick, livingEntity.yHeadRotO, livingEntity.yHeadRot); + ? 0 + : Mth.rotLerp(partialTick, livingEntity.yHeadRotO, livingEntity.yHeadRot); float netHeadYaw = lerpHeadRot - lerpBodyRot; if (shouldSit && this.currentEntity.getVehicle() instanceof LivingEntity livingentity) { @@ -298,9 +297,9 @@ public void actuallyRender( float eyePosOffset = livingEntity.getEyeHeight(Pose.STANDING) - 0.1F; poseStack.translate( - -bedDirection.getStepX() * eyePosOffset, - 0, - -bedDirection.getStepZ() * eyePosOffset + -bedDirection.getStepX() * eyePosOffset, + 0, + -bedDirection.getStepZ() * eyePosOffset ); } } @@ -315,9 +314,9 @@ public void actuallyRender( if (!shouldSit && this.currentEntity.isAlive() && livingEntity != null) { limbSwingAmount = Mth.lerp( - partialTick, - livingEntity.walkAnimation.speedOld, - livingEntity.walkAnimation.speed() + partialTick, + livingEntity.walkAnimation.speedOld, + livingEntity.walkAnimation.speed() ); limbSwing = livingEntity.walkAnimation.position() - livingEntity.walkAnimation.speed() * (1 - partialTick); @@ -343,20 +342,24 @@ public void actuallyRender( if (!isReRender) { AnimationState animationState = new AnimationState( - animatable, - limbSwing, - limbSwingAmount, - partialTick, - isMoving + animatable, + limbSwing, + limbSwingAmount, + partialTick, + isMoving ); long instanceId = getInstanceId(animatable); animationState.setData(DataTickets.TICK, animatable.getTick(this.currentEntity)); animationState.setData(DataTickets.ENTITY, this.currentEntity); animationState.setData( - DataTickets.ENTITY_MODEL_DATA, - new EntityModelData(shouldSit, livingEntity != null && livingEntity.isBaby(), -netHeadYaw, - -headPitch) + DataTickets.ENTITY_MODEL_DATA, + new EntityModelData( + shouldSit, + livingEntity != null && livingEntity.isBaby(), + -netHeadYaw, + -headPitch + ) ); this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); this.model.handleAnimations(animatable, instanceId, animationState); @@ -370,17 +373,17 @@ public void actuallyRender( assert Minecraft.getInstance().player != null; if (!this.currentEntity.isInvisibleTo(Minecraft.getInstance().player)) GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -391,27 +394,27 @@ public void actuallyRender( */ @Override public void applyRenderLayers( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { if (!this.currentEntity.isSpectator()) GeoRenderer.super.applyRenderLayers( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay ); } @@ -421,15 +424,15 @@ public void applyRenderLayers( */ @Override public void renderFinal( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { super.render(this.currentEntity, 0, partialTick, poseStack, bufferSource, packedLight); @@ -446,17 +449,17 @@ public void renderFinal( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -470,10 +473,10 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.currentEntity, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.currentEntity, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) ); } @@ -486,54 +489,62 @@ public void renderRecursively( if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); } /** - * Applies rotation transformations to the renderer prior to render time to account for various entity states, default scale of 1 + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * default scale of 1 */ protected void applyRotations( - T animatable, - PoseStack poseStack, - float ageInTicks, - float rotationYaw, - float partialTick + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick ) { applyRotations(animatable, poseStack, ageInTicks, rotationYaw, partialTick, 1); } /** - * Applies rotation transformations to the renderer prior to render time to account for various entity states, scalable + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * scalable */ - protected void applyRotations(T animatable, PoseStack poseStack, float ageInTicks, float rotationYaw, - float partialTick, float nativeScale) { + protected void applyRotations( + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick, + float nativeScale + ) { if (isShaking(animatable)) - rotationYaw += (float)(Math.cos(this.currentEntity.tickCount * 3.25d) * Math.PI * 0.4d); + rotationYaw += (float) (Math.cos(this.currentEntity.tickCount * 3.25d) * Math.PI * 0.4d); if (!this.currentEntity.hasPose(Pose.SLEEPING)) poseStack.mulPose(Axis.YP.rotationDegrees(180f - rotationYaw)); @@ -542,20 +553,23 @@ protected void applyRotations(T animatable, PoseStack poseStack, float ageInTick if (livingEntity.deathTime > 0) { float deathRotation = (livingEntity.deathTime + partialTick - 1f) / 20f * 1.6f; - poseStack.mulPose(Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable))); - } - else if (livingEntity.isAutoSpinAttack()) { + poseStack.mulPose( + Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable)) + ); + } else if (livingEntity.isAutoSpinAttack()) { poseStack.mulPose(Axis.XP.rotationDegrees(-90f - livingEntity.getXRot())); poseStack.mulPose(Axis.YP.rotationDegrees((livingEntity.tickCount + partialTick) * -75f)); - } - else if (livingEntity.hasPose(Pose.SLEEPING)) { + } else if (livingEntity.hasPose(Pose.SLEEPING)) { Direction bedOrientation = livingEntity.getBedOrientation(); - poseStack.mulPose(Axis.YP.rotationDegrees(bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw)); + poseStack.mulPose( + Axis.YP.rotationDegrees( + bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw + ) + ); poseStack.mulPose(Axis.ZP.rotationDegrees(getDeathMaxRotation(animatable))); poseStack.mulPose(Axis.YP.rotationDegrees(270f)); - } - else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { + } else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { poseStack.translate(0, (livingEntity.getBbHeight() + 0.1f) / nativeScale, 0); poseStack.mulPose(Axis.ZP.rotationDegrees(180f)); } @@ -587,8 +601,8 @@ public boolean shouldShowName(@NotNull E entity) { return false; if ( - entity instanceof Mob && (!entity.shouldShowName() && (!entity.hasCustomName() - || entity != this.entityRenderDispatcher.crosshairPickEntity)) + entity instanceof Mob && (!entity.shouldShowName() && (!entity.hasCustomName() + || entity != this.entityRenderDispatcher.crosshairPickEntity)) ) return false; @@ -599,7 +613,7 @@ public boolean shouldShowName(@NotNull E entity) { if (entityTeam == null) return Minecraft.renderNames() && entity != minecraft.getCameraEntity() && visibleToClient && !entity - .isVehicle(); + .isVehicle(); var playerTeam = minecraft.player.getTeam(); @@ -607,11 +621,11 @@ public boolean shouldShowName(@NotNull E entity) { case ALWAYS -> visibleToClient; case NEVER -> false; case HIDE_FOR_OTHER_TEAMS -> playerTeam == null - ? visibleToClient - : entityTeam.isAlliedTo(playerTeam) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); + ? visibleToClient + : entityTeam.isAlliedTo(playerTeam) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); case HIDE_FOR_OWN_TEAM -> playerTeam == null - ? visibleToClient - : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; + ? visibleToClient + : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; }; } @@ -634,11 +648,11 @@ public int getPackedOverlay(T animatable, float u, float partialTick) { * duplicated here for flexible usage */ public void renderLeash( - M mob, - float partialTick, - PoseStack poseStack, - MultiBufferSource bufferSource, - H leashHolder + M mob, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + H leashHolder ) { double lerpBodyAngle = (Mth.lerp(partialTick, mob.yBodyRotO, mob.yBodyRot) * Mth.DEG_TO_RAD) + Mth.HALF_PI; Vec3 leashOffset = mob.getLeashOffset(); @@ -659,8 +673,8 @@ public void renderLeash( BlockPos holderEyePos = BlockPos.containing(leashHolder.getEyePosition(partialTick)); int entityBlockLight = getBlockLightLevel((E) mob, entityEyePos); int holderBlockLight = leashHolder.isOnFire() - ? 15 - : leashHolder.level().getBrightness(LightLayer.BLOCK, holderEyePos); + ? 15 + : leashHolder.level().getBrightness(LightLayer.BLOCK, holderEyePos); int entitySkyLight = mob.level().getBrightness(LightLayer.SKY, entityEyePos); int holderSkyLight = mob.level().getBrightness(LightLayer.SKY, holderEyePos); @@ -671,41 +685,41 @@ public void renderLeash( for (int segment = 0; segment <= 24; ++segment) { renderLeashPiece( - vertexConsumer, - posMatrix, - xDif, - yDif, - zDif, - entityBlockLight, - holderBlockLight, - entitySkyLight, - holderSkyLight, - 0.025f, - 0.025f, - xOffset, - zOffset, - segment, - false + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.025f, + xOffset, + zOffset, + segment, + false ); } for (int segment = 24; segment >= 0; --segment) { renderLeashPiece( - vertexConsumer, - posMatrix, - xDif, - yDif, - zDif, - entityBlockLight, - holderBlockLight, - entitySkyLight, - holderSkyLight, - 0.025f, - 0.0f, - xOffset, - zOffset, - segment, - true + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.0f, + xOffset, + zOffset, + segment, + true ); } @@ -726,8 +740,8 @@ public boolean isShaking(T entity) { @Override public void updateAnimatedTextureFrame(T animatable) { AnimatableTexture.setAndUpdate( - getTextureLocation(animatable), - this.currentEntity.getId() + (int) animatable.getTick(this.currentEntity) + getTextureLocation(animatable), + this.currentEntity.getId() + (int) animatable.getTick(this.currentEntity) ); } @@ -746,13 +760,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireReplacedEntityPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireReplacedEntityPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -760,12 +781,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireReplacedEntityPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireReplacedEntityPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoArmorRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoArmorRenderer.java index ac0cee3c3..e040ed641 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoArmorRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoArmorRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.dynamic; @@ -11,19 +9,10 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRendererConstants; -import mod.azure.azurelib.common.api.client.renderer.GeoBlockRenderer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; -import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -31,6 +20,13 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRendererConstants; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; + /** * Extended special-armor renderer for more advanced or dynamic models.
    * Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider @@ -39,7 +35,7 @@ public abstract class DynamicGeoArmorRenderer extends GeoArmorRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; @@ -71,11 +67,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -86,14 +82,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -103,17 +99,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -128,7 +124,7 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix(RenderUtils.translateMatrix(localMatrix, GeoArmorRendererConstants.ZERO)); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) ); } @@ -136,14 +132,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -153,49 +149,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -207,30 +203,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -241,23 +237,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -268,13 +264,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -282,23 +278,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoBlockRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoBlockRenderer.java index ed6d3d180..881e77ee8 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoBlockRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoBlockRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.dynamic; @@ -11,11 +9,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoBlockRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; @@ -27,6 +20,12 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoBlockRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Extended special-block-entity renderer for more advanced or dynamic models.
    * Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider @@ -35,7 +34,7 @@ public abstract class DynamicGeoBlockRenderer extends GeoBlockRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; @@ -67,11 +66,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -82,14 +81,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -99,17 +98,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -123,17 +122,17 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix( - new Matrix4f(localMatrix), - new Vector3f( - this.animatable.getBlockPos().getX(), - this.animatable.getBlockPos().getY(), - this.animatable.getBlockPos().getZ() - ) + RenderUtils.translateMatrix( + new Matrix4f(localMatrix), + new Vector3f( + this.animatable.getBlockPos().getX(), + this.animatable.getBlockPos().getY(), + this.animatable.getBlockPos().getZ() ) + ) ); } @@ -141,14 +140,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -158,49 +157,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -212,30 +211,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -246,23 +245,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -273,13 +272,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -287,23 +286,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoItemRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoItemRenderer.java index 3eaf2b2fb..aebd14a1a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoItemRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.dynamic; @@ -11,17 +9,10 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoBlockRenderer; -import mod.azure.azurelib.common.api.client.renderer.GeoItemRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; -import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -29,6 +20,12 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoItemRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Extended special-item renderer for more advanced or dynamic models.
    * Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider @@ -37,7 +34,7 @@ public abstract class DynamicGeoItemRenderer extends GeoItemRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; @@ -69,11 +66,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -84,14 +81,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -101,17 +98,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -125,10 +122,10 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); } @@ -136,14 +133,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -153,49 +150,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -207,30 +204,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -241,23 +238,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -268,13 +265,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -282,23 +279,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoObjectRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoObjectRenderer.java index e45b87984..3c8d8f792 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoObjectRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoObjectRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.dynamic; @@ -11,16 +9,9 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoItemRenderer; -import mod.azure.azurelib.common.api.client.renderer.GeoObjectRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -28,6 +19,12 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoObjectRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Extended special-object renderer for more advanced or dynamic models.
    * Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider @@ -36,7 +33,7 @@ public abstract class DynamicGeoObjectRenderer extends GeoObjectRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; @@ -68,11 +65,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -83,14 +80,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -100,17 +97,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -124,7 +121,7 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset().toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset().toVector3f()) ); } @@ -132,14 +129,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -149,49 +146,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -203,30 +200,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -237,23 +234,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -264,13 +261,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -278,23 +275,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoReplacedEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoReplacedEntityRenderer.java index a0c8cf76b..d78998761 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoReplacedEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoReplacedEntityRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.dynamic; @@ -11,12 +9,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoEntityRenderer; -import mod.azure.azurelib.common.api.client.renderer.GeoReplacedEntityRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRendererProvider; @@ -29,19 +21,29 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoReplacedEntityRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Extended special-entity renderer for more advanced or dynamic models.
    * Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider * whether the benefits are worth the cost for your needs. */ -public abstract class DynamicGeoReplacedEntityRenderer extends GeoReplacedEntityRenderer { +public abstract class DynamicGeoReplacedEntityRenderer extends GeoReplacedEntityRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; - protected DynamicGeoReplacedEntityRenderer(EntityRendererProvider.Context renderManager, GeoModel model, T animatable) { + protected DynamicGeoReplacedEntityRenderer( + EntityRendererProvider.Context renderManager, + GeoModel model, + T animatable + ) { super(renderManager, model, animatable); } @@ -69,11 +71,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -84,14 +86,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -101,17 +103,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -125,10 +127,10 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.currentEntity, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.currentEntity, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) ); } @@ -136,14 +138,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -153,49 +155,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -207,30 +209,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -241,23 +243,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -268,13 +270,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -282,23 +284,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java index 1ca7d5200..8442a81f3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java @@ -1,22 +1,20 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; + import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; import mod.azure.azurelib.common.internal.common.cache.texture.AutoGlowingTexture; import mod.azure.azurelib.core.animatable.GeoAnimatable; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.resources.ResourceLocation; /** * {@link GeoRenderLayer} for rendering the auto-generated glowlayer functionality implemented by AzureLib using the @@ -42,22 +40,31 @@ protected RenderType getRenderType(T animatable) { */ @Override public void render( - PoseStack poseStack, - T animatable, - BakedGeoModel bakedModel, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { renderType = getRenderType(animatable); if (renderType != null) { - getRenderer().reRender(bakedModel, poseStack, bufferSource, animatable, renderType, - bufferSource.getBuffer(renderType), partialTick, 15728640, packedOverlay, - getRenderer().getRenderColor(animatable, partialTick, packedLight).argbInt()); + getRenderer().reRender( + bakedModel, + poseStack, + bufferSource, + animatable, + renderType, + bufferSource.getBuffer(renderType), + partialTick, + 15728640, + packedOverlay, + getRenderer().getRenderColor(animatable, partialTick, packedLight).argbInt() + ); } } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java index 63ab564dd..6fcbe29c9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java @@ -1,18 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; @@ -25,6 +19,11 @@ import java.util.function.BiFunction; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * {@link GeoRenderLayer} for rendering {@link net.minecraft.world.level.block.state.BlockState BlockStates} or * {@link net.minecraft.world.item.ItemStack ItemStacks} on a given {@link GeoAnimatable} @@ -40,9 +39,9 @@ public BlockAndItemGeoLayer(GeoRenderer renderer) { } public BlockAndItemGeoLayer( - GeoRenderer renderer, - BiFunction stackForBone, - BiFunction blockForBone + GeoRenderer renderer, + BiFunction stackForBone, + BiFunction blockForBone ) { super(renderer); @@ -87,15 +86,15 @@ protected ItemDisplayContext getTransformTypeForStack(GeoBone bone, ItemStack st */ @Override public void renderForBone( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { ItemStack stack = getStackForBone(bone, animatable); BlockState blockState = getBlockForBone(bone, animatable); @@ -108,26 +107,26 @@ public void renderForBone( if (stack != null) renderStackForBone( - poseStack, - bone, - stack, - animatable, - bufferSource, - partialTick, - packedLight, - packedOverlay + poseStack, + bone, + stack, + animatable, + bufferSource, + partialTick, + packedLight, + packedOverlay ); if (blockState != null) renderBlockForBone( - poseStack, - bone, - blockState, - animatable, - bufferSource, - partialTick, - packedLight, - packedOverlay + poseStack, + bone, + blockState, + animatable, + bufferSource, + partialTick, + packedLight, + packedOverlay ); poseStack.popPose(); @@ -137,43 +136,43 @@ public void renderForBone( * Render the given {@link ItemStack} for the provided {@link GeoBone}. */ protected void renderStackForBone( - PoseStack poseStack, - GeoBone bone, - ItemStack stack, - T animatable, - MultiBufferSource bufferSource, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + GeoBone bone, + ItemStack stack, + T animatable, + MultiBufferSource bufferSource, + float partialTick, + int packedLight, + int packedOverlay ) { if (animatable instanceof LivingEntity livingEntity) { Minecraft.getInstance() - .getItemRenderer() - .renderStatic( - livingEntity, - stack, - getTransformTypeForStack(bone, stack, animatable), - false, - poseStack, - bufferSource, - livingEntity.level(), - packedLight, - packedOverlay, - livingEntity.getId() - ); + .getItemRenderer() + .renderStatic( + livingEntity, + stack, + getTransformTypeForStack(bone, stack, animatable), + false, + poseStack, + bufferSource, + livingEntity.level(), + packedLight, + packedOverlay, + livingEntity.getId() + ); } else { Minecraft.getInstance() - .getItemRenderer() - .renderStatic( - stack, - getTransformTypeForStack(bone, stack, animatable), - packedLight, - packedOverlay, - poseStack, - bufferSource, - Minecraft.getInstance().level, - (int) this.renderer.getInstanceId(animatable) - ); + .getItemRenderer() + .renderStatic( + stack, + getTransformTypeForStack(bone, stack, animatable), + packedLight, + packedOverlay, + poseStack, + bufferSource, + Minecraft.getInstance().level, + (int) this.renderer.getInstanceId(animatable) + ); } } @@ -181,21 +180,21 @@ protected void renderStackForBone( * Render the given {@link BlockState} for the provided {@link GeoBone}. */ protected void renderBlockForBone( - PoseStack poseStack, - GeoBone bone, - BlockState state, - T animatable, - MultiBufferSource bufferSource, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + GeoBone bone, + BlockState state, + T animatable, + MultiBufferSource bufferSource, + float partialTick, + int packedLight, + int packedOverlay ) { poseStack.pushPose(); poseStack.translate(-0.25f, -0.25f, -0.25f); poseStack.scale(0.5f, 0.5f, 0.5f); Minecraft.getInstance() - .getBlockRenderer() - .renderSingleBlock(state, poseStack, bufferSource, packedLight, OverlayTexture.NO_OVERLAY); + .getBlockRenderer() + .renderSingleBlock(state, poseStack, bufferSource, packedLight, OverlayTexture.NO_OVERLAY); poseStack.popPose(); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java index b4e4a5c3a..0edebc056 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java @@ -1,21 +1,20 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import org.apache.logging.log4j.util.TriConsumer; + import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; import mod.azure.azurelib.core.animatable.GeoAnimatable; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import org.apache.logging.log4j.util.TriConsumer; /** * {@link GeoRenderLayer} for auto-applying some form of modification to bones of a model prior to rendering.
    @@ -28,8 +27,7 @@ public class BoneFilterGeoLayer extends GeoRenderLayer< protected final TriConsumer checkAndApply; public BoneFilterGeoLayer(GeoRenderer renderer) { - this(renderer, (bone, animatable, partialTick) -> { - }); + this(renderer, (bone, animatable, partialTick) -> {}); } public BoneFilterGeoLayer(GeoRenderer renderer, TriConsumer checkAndApply) { @@ -48,15 +46,15 @@ protected void checkAndApply(GeoBone bone, T animatable, float partialTick) { @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel bakedModel, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { for (GeoBone bone : bakedModel.getTopLevelBones()) { checkChildBones(bone, animatable, partialTick); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java index fcac8d97b..630844623 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java @@ -1,18 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import org.apache.logging.log4j.util.TriConsumer; @@ -20,6 +14,11 @@ import java.util.List; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * A more efficient version of {@link BoneFilterGeoLayer}.
    * This version requires you provide the list of bones to filter up-front, so that the bone hierarchy doesn't need to be @@ -34,14 +33,13 @@ public FastBoneFilterGeoLayer(GeoRenderer renderer) { } public FastBoneFilterGeoLayer(GeoRenderer renderer, Supplier> boneSupplier) { - this(renderer, boneSupplier, (bone, animatable, partialTick) -> { - }); + this(renderer, boneSupplier, (bone, animatable, partialTick) -> {}); } public FastBoneFilterGeoLayer( - GeoRenderer renderer, - Supplier> boneSupplier, - TriConsumer checkAndApply + GeoRenderer renderer, + Supplier> boneSupplier, + TriConsumer checkAndApply ) { super(renderer, checkAndApply); @@ -58,20 +56,20 @@ protected List getAffectedBones() { @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel bakedModel, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { for (String boneName : getAffectedBones()) { this.renderer.getGeoModel() - .getBone(boneName) - .ifPresent(bone -> checkAndApply(bone, animatable, partialTick)); + .getBone(boneName) + .ifPresent(bone -> checkAndApply(bone, animatable, partialTick)); } } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java index 249da8ffb..91ebda9bb 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java @@ -1,28 +1,28 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; + import mod.azure.azurelib.common.api.client.model.GeoModel; import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; import mod.azure.azurelib.core.animatable.GeoAnimatable; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.resources.ResourceLocation; /** * Render layer base class for rendering additional layers of effects or textures over an existing model at runtime.
    * Contains the base boilerplate and helper code for various render layer features */ public abstract class GeoRenderLayer { + protected final GeoRenderer renderer; public GeoRenderLayer(GeoRenderer entityRendererIn) { @@ -37,8 +37,7 @@ public GeoModel getGeoModel() { } /** - * Gets the {@link BakedGeoModel} instance that is currently being used. - * This can be directly used for re-rendering + * Gets the {@link BakedGeoModel} instance that is currently being used. This can be directly used for re-rendering */ public BakedGeoModel getDefaultBakedModel(T animatable) { return getGeoModel().getBakedModel(getGeoModel().getModelResource(animatable)); @@ -60,32 +59,59 @@ protected ResourceLocation getTextureResource(T animatable) { } /** - * This method is called by the {@link GeoRenderer} before rendering, immediately after {@link GeoRenderer#preRender} has been called.
    + * This method is called by the {@link GeoRenderer} before rendering, immediately after + * {@link GeoRenderer#preRender} has been called.
    * This allows for RenderLayers to perform pre-render manipulations such as hiding or showing bones */ - public void preRender(PoseStack poseStack, T animatable, BakedGeoModel bakedModel, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, - int packedLight, int packedOverlay) {} + public void preRender( + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) {} /** * This is the method that is actually called by the render for your render layer to function.
    * This is called after the animatable has been rendered, but before supplementary rendering like nametags. */ - public void render(PoseStack poseStack, T animatable, BakedGeoModel bakedModel, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, - int packedLight, int packedOverlay) {} + public void render( + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) {} /** * This method is called by the {@link GeoRenderer} for each bone being rendered.
    * This is a more expensive call, particularly if being used to render something on a different buffer.
    - * It does however have the benefit of having the matrix translations and other transformations already applied from render-time.
    + * It does however have the benefit of having the matrix translations and other transformations already applied from + * render-time.
    * It's recommended to avoid using this unless necessary.
    *
    * The {@link GeoBone} in question has already been rendered by this stage.
    *
    - * If you do use it, and you render something that changes the {@link VertexConsumer buffer}, you need to reset it back to the previous buffer - * using {@link MultiBufferSource#getBuffer} before ending the method + * If you do use it, and you render something that changes the {@link VertexConsumer buffer}, you need to + * reset it back to the previous buffer using {@link MultiBufferSource#getBuffer} before ending the method */ - public void renderForBone(PoseStack poseStack, T animatable, GeoBone bone, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) {} -} \ No newline at end of file + public void renderForBone( + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) {} +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java index f37b94b61..a456596ff 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import java.util.List; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Base interface for a container for {@link GeoRenderLayer GeoRenderLayers}
    * Each renderer should contain an instance of this, for holding its layers and handling events. diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java index 61de3514c..e5992f53a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java @@ -1,23 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.Minecraft; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.SkullModelBase; @@ -43,6 +32,16 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Builtin class for handling dynamic armor rendering on AzureLib entities.
    * Supports both {@link GeoItem AzureLib} and {@link net.minecraft.world.item.ArmorItem Vanilla} armor models.
    @@ -51,11 +50,11 @@ public class ItemArmorGeoLayer extends GeoRenderLayer { protected static final HumanoidModel INNER_ARMOR_MODEL = new HumanoidModel<>( - Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR) + Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR) ); protected static final HumanoidModel OUTER_ARMOR_MODEL = new HumanoidModel<>( - Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR) + Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR) ); @Nullable @@ -102,11 +101,11 @@ protected EquipmentSlot getEquipmentSlotForBone(GeoBone bone, ItemStack stack, T */ @NotNull protected ModelPart getModelPartForBone( - GeoBone bone, - EquipmentSlot slot, - ItemStack stack, - T animatable, - HumanoidModel baseModel + GeoBone bone, + EquipmentSlot slot, + ItemStack stack, + T animatable, + HumanoidModel baseModel ) { return baseModel.body; } @@ -127,15 +126,15 @@ protected ItemStack getArmorItemForBone(GeoBone bone, T animatable) { */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel bakedModel, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { this.mainHandStack = animatable.getItemBySlot(EquipmentSlot.MAINHAND); this.offhandStack = animatable.getItemBySlot(EquipmentSlot.OFFHAND); @@ -159,15 +158,15 @@ public void preRender( */ @Override public void renderForBone( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { ItemStack armorStack = getArmorItemForBone(bone, animatable); @@ -175,8 +174,8 @@ public void renderForBone( return; if ( - armorStack.getItem() instanceof BlockItem blockItem && blockItem - .getBlock() instanceof AbstractSkullBlock skullBlock + armorStack.getItem() instanceof BlockItem blockItem && blockItem + .getBlock() instanceof AbstractSkullBlock skullBlock ) { renderSkullAsArmor(poseStack, bone, armorStack, skullBlock, bufferSource, packedLight); } else { @@ -192,21 +191,28 @@ public void renderForBone( prepModelPartForRender(poseStack, bone, modelPart); geoArmorRenderer.prepForRender(animatable, armorStack, slot, model); geoArmorRenderer.applyBoneVisibilityByPart(slot, modelPart, model); - geoArmorRenderer.renderToBuffer(poseStack, null, packedLight, packedOverlay, armorStack.is( - ItemTags.DYEABLE) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(armorStack, -6265536)) : -1); + geoArmorRenderer.renderToBuffer( + poseStack, + null, + packedLight, + packedOverlay, + armorStack.is( + ItemTags.DYEABLE + ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(armorStack, -6265536)) : -1 + ); } else if (armorStack.getItem() instanceof ArmorItem) { prepModelPartForRender(poseStack, bone, modelPart); renderVanillaArmorPiece( - poseStack, - animatable, - bone, - slot, - armorStack, - modelPart, - bufferSource, - partialTick, - packedLight, - packedOverlay + poseStack, + animatable, + bone, + slot, + armorStack, + modelPart, + bufferSource, + partialTick, + packedLight, + packedOverlay ); } @@ -219,23 +225,32 @@ public void renderForBone( * Renders an individual armor piece base on the given {@link GeoBone} and {@link ItemStack} */ protected void renderVanillaArmorPiece( - PoseStack poseStack, - T animatable, - GeoBone bone, - EquipmentSlot slot, - ItemStack armorStack, - ModelPart modelPart, - MultiBufferSource bufferSource, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + GeoBone bone, + EquipmentSlot slot, + ItemStack armorStack, + ModelPart modelPart, + MultiBufferSource bufferSource, + float partialTick, + int packedLight, + int packedOverlay ) { Holder material = ((ArmorItem) armorStack.getItem()).getMaterial(); for (ArmorMaterial.Layer layer : material.value().layers()) { int color = armorStack.is(ItemTags.DYEABLE) ? DyedItemColor.getOrDefault(armorStack, -6265536) : 0xFFFFFF; - VertexConsumer buffer = getVanillaArmorBuffer(bufferSource, animatable, armorStack, slot, bone, layer, - packedLight, packedOverlay, false); + VertexConsumer buffer = getVanillaArmorBuffer( + bufferSource, + animatable, + armorStack, + slot, + bone, + layer, + packedLight, + packedOverlay, + false + ); modelPart.render(poseStack, buffer, packedLight, packedOverlay); } @@ -243,21 +258,51 @@ protected void renderVanillaArmorPiece( ArmorTrim trim = armorStack.get(DataComponents.TRIM); if (trim != null) { - TextureAtlasSprite sprite = Minecraft.getInstance().getModelManager().getAtlas( - Sheets.ARMOR_TRIMS_SHEET).getSprite( - slot == EquipmentSlot.LEGS ? trim.innerTexture(material) : trim.outerTexture(material)); + TextureAtlasSprite sprite = Minecraft.getInstance() + .getModelManager() + .getAtlas( + Sheets.ARMOR_TRIMS_SHEET + ) + .getSprite( + slot == EquipmentSlot.LEGS ? trim.innerTexture(material) : trim.outerTexture(material) + ); VertexConsumer buffer = sprite.wrap( - bufferSource.getBuffer(Sheets.armorTrimsSheet(trim.pattern().value().decal()))); + bufferSource.getBuffer(Sheets.armorTrimsSheet(trim.pattern().value().decal())) + ); modelPart.render(poseStack, buffer, packedLight, packedOverlay); } if (armorStack.hasFoil()) - modelPart.render(poseStack, - getVanillaArmorBuffer(bufferSource, animatable, armorStack, slot, bone, null, packedLight, - packedOverlay, true), packedLight, packedOverlay, 1); + modelPart.render( + poseStack, + getVanillaArmorBuffer( + bufferSource, + animatable, + armorStack, + slot, + bone, + null, + packedLight, + packedOverlay, + true + ), + packedLight, + packedOverlay, + 1 + ); } - protected VertexConsumer getVanillaArmorBuffer(MultiBufferSource bufferSource, T animatable, ItemStack stack, EquipmentSlot slot, GeoBone bone, @Nullable ArmorMaterial.Layer layer, int packedLight, int packedOverlay, boolean forGlint) { + protected VertexConsumer getVanillaArmorBuffer( + MultiBufferSource bufferSource, + T animatable, + ItemStack stack, + EquipmentSlot slot, + GeoBone bone, + @Nullable ArmorMaterial.Layer layer, + int packedLight, + int packedOverlay, + boolean forGlint + ) { if (forGlint) return bufferSource.getBuffer(RenderType.armorEntityGlint()); @@ -279,16 +324,18 @@ protected HumanoidModel getModelForItem(GeoBone bone, EquipmentSlot slot, Ite * Render a given {@link AbstractSkullBlock} as a worn armor piece in relation to a given {@link GeoBone} */ protected void renderSkullAsArmor( - PoseStack poseStack, - GeoBone bone, - ItemStack stack, - AbstractSkullBlock skullBlock, - MultiBufferSource bufferSource, - int packedLight + PoseStack poseStack, + GeoBone bone, + ItemStack stack, + AbstractSkullBlock skullBlock, + MultiBufferSource bufferSource, + int packedLight ) { SkullBlock.Type type = skullBlock.getType(); - SkullModelBase model = SkullBlockRenderer.createSkullRenderers(Minecraft.getInstance().getEntityModels()).get( - type); + SkullModelBase model = SkullBlockRenderer.createSkullRenderers(Minecraft.getInstance().getEntityModels()) + .get( + type + ); RenderType renderType = SkullBlockRenderer.getRenderType(type, stack.get(DataComponents.PROFILE)); poseStack.pushPose(); @@ -321,9 +368,9 @@ protected void prepModelPartForRender(PoseStack poseStack, GeoBone bone, ModelPa float scaleZ = (float) (armorBoneSizeZ / actualArmorSizeZ); sourcePart.setPos( - -(bone.getPivotX() - ((bone.getPivotX() * scaleX) - bone.getPivotX()) / scaleX), - -(bone.getPivotY() - ((bone.getPivotY() * scaleY) - bone.getPivotY()) / scaleY), - (bone.getPivotZ() - ((bone.getPivotZ() * scaleZ) - bone.getPivotZ()) / scaleZ) + -(bone.getPivotX() - ((bone.getPivotX() * scaleX) - bone.getPivotX()) / scaleX), + -(bone.getPivotY() - ((bone.getPivotY() * scaleY) - bone.getPivotY()) / scaleY), + (bone.getPivotZ() - ((bone.getPivotZ() * scaleZ) - bone.getPivotZ()) / scaleZ) ); sourcePart.xRot = -bone.getRotX(); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/ai/pathing/AzureNavigation.java b/common/src/main/java/mod/azure/azurelib/common/api/common/ai/pathing/AzureNavigation.java index 1f35492af..6c38cbc5a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/ai/pathing/AzureNavigation.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/ai/pathing/AzureNavigation.java @@ -1,6 +1,5 @@ package mod.azure.azurelib.common.api.common.ai.pathing; -import mod.azure.azurelib.common.internal.common.ai.pathing.AzurePathFinder; import net.minecraft.core.BlockPos; import net.minecraft.tags.BlockTags; import net.minecraft.util.Mth; @@ -16,6 +15,8 @@ import java.util.Objects; +import mod.azure.azurelib.common.internal.common.ai.pathing.AzurePathFinder; + /* * Credit to Bob Mowzie and pau101 for most of the code, code source for the base class can be found here: * https://github.com/BobMowzie/MowziesMobs/blob/master/src/main/java/com/bobmowzie/mowziesmobs/server/ai/ @@ -24,6 +25,7 @@ public class AzureNavigation extends GroundPathNavigation { static final float EPSILON = 1.0E-8F; + @Nullable protected BlockPos pathToPosition; @@ -40,8 +42,8 @@ public AzureNavigation(Mob entity, Level world) { /** * Forces the entity to stop its current pathfinding by clearing both the {@code path} and {@code pathToPosition}. - * Unlike the normal {@code stop()} method, this ensures that {@code pathToPosition} is cleared as well, - * preventing potential pathfinding issues caused by lingering path data. + * Unlike the normal {@code stop()} method, this ensures that {@code pathToPosition} is cleared as well, preventing + * potential pathfinding issues caused by lingering path data. *

    * Special thanks to JayZX535 for contributing this method. */ @@ -79,8 +81,12 @@ protected void followThePath() { } final Vec3 base = entityPos.add(-this.mob.getBbWidth() * 0.5F, 0.0F, -this.mob.getBbWidth() * 0.5F); final Vec3 max = base.add(this.mob.getBbWidth(), this.mob.getBbHeight(), this.mob.getBbWidth()); - if (this.tryShortcut(path, new Vec3(this.mob.getX(), this.mob.getY(), this.mob.getZ()), pathLength, base, max)) { - if (this.isAt(path, 0.5F) || this.atElevationChange(path) && this.isAt(path, this.mob.getBbWidth() * 0.5F)) { + if ( + this.tryShortcut(path, new Vec3(this.mob.getX(), this.mob.getY(), this.mob.getZ()), pathLength, base, max) + ) { + if ( + this.isAt(path, 0.5F) || this.atElevationChange(path) && this.isAt(path, this.mob.getBbWidth() * 0.5F) + ) { path.setNextNodeIndex(path.getNextNodeIndex() + 1); } } @@ -116,35 +122,35 @@ public void tick() { if (this.isDone()) { if (this.pathToPosition != null) { if ( - this.pathToPosition.closerToCenterThan(this.mob.position(), this.mob.getBbWidth()) || this.mob - .getY() > (double) this.pathToPosition.getY() && BlockPos.containing( - this.pathToPosition.getX(), - this.mob.getY(), - this.pathToPosition.getZ() + this.pathToPosition.closerToCenterThan(this.mob.position(), this.mob.getBbWidth()) || this.mob + .getY() > (double) this.pathToPosition.getY() && BlockPos.containing( + this.pathToPosition.getX(), + this.mob.getY(), + this.pathToPosition.getZ() ).closerToCenterThan(this.mob.position(), this.mob.getBbWidth()) ) { this.pathToPosition = null; } else { this.mob.getMoveControl() - .setWantedPosition( - this.pathToPosition.getX(), - this.pathToPosition.getY(), - this.pathToPosition.getZ(), - this.speedModifier - ); + .setWantedPosition( + this.pathToPosition.getX(), + this.pathToPosition.getY(), + this.pathToPosition.getZ(), + this.speedModifier + ); } } return; } if (this.getTargetPos() != null) this.mob.getLookControl() - .setLookAt(this.getTargetPos().getX(), this.getTargetPos().getY(), this.getTargetPos().getZ()); + .setLookAt(this.getTargetPos().getX(), this.getTargetPos().getY(), this.getTargetPos().getZ()); } private boolean isAt(Path path, float threshold) { final Vec3 pathPos = path.getNextEntityPos(this.mob); return Mth.abs((float) (this.mob.getX() - pathPos.x)) < threshold && Mth.abs( - (float) (this.mob.getZ() - pathPos.z) + (float) (this.mob.getZ() - pathPos.z) ) < threshold && Math.abs(this.mob.getY() - pathPos.y) < 1.0D; } @@ -161,7 +167,7 @@ private boolean atElevationChange(Path path) { } private boolean tryShortcut(Path path, Vec3 entityPos, int pathLength, Vec3 base, Vec3 max) { - for (int i = pathLength; --i > path.getNextNodeIndex(); ) { + for (int i = pathLength; --i > path.getNextNodeIndex();) { final Vec3 vec = path.getEntityPosAtNode(this.mob, i).subtract(entityPos); if (this.sweep(vec, base, max)) { path.setNextNodeIndex(i); @@ -176,7 +182,8 @@ private boolean tryShortcut(Path path, Vec3 entityPos, int pathLength, Vec3 base private boolean sweep(Vec3 vec, Vec3 base, Vec3 max) { float t = 0.0F; float max_t = (float) vec.length(); - if (max_t < EPSILON) return true; + if (max_t < EPSILON) + return true; final float[] tr = new float[3]; final int[] ldi = new int[3]; final int[] tri = new int[3]; @@ -200,9 +207,7 @@ private boolean sweep(Vec3 vec, Vec3 base, Vec3 max) { final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); do { // stepForward - int axis = (tNext[0] < tNext[1]) ? - ((tNext[0] < tNext[2]) ? 0 : 2) : - ((tNext[1] < tNext[2]) ? 1 : 2); + int axis = (tNext[0] < tNext[1]) ? ((tNext[0] < tNext[2]) ? 0 : 2) : ((tNext[1] < tNext[2]) ? 1 : 2); float dt = tNext[axis] - t; t = tNext[axis]; ldi[axis] += step[axis]; @@ -225,14 +230,23 @@ private boolean sweep(Vec3 vec, Vec3 base, Vec3 max) { for (int z = z0; z != z1; z += stepz) { for (int y = y0; y != y1; y += stepy) { BlockState block = this.level.getBlockState(pos.set(x, y, z)); - if (!block.isPathfindable(PathComputationType.LAND)) return false; + if (!block.isPathfindable(PathComputationType.LAND)) + return false; } - PathType below = this.nodeEvaluator.getPathType(new PathfindingContext(mob.level(), mob), x, y0 - 1, z); - if (below == PathType.WATER || below == PathType.LAVA || below == PathType.OPEN) return false; + PathType below = this.nodeEvaluator.getPathType( + new PathfindingContext(mob.level(), mob), + x, + y0 - 1, + z + ); + if (below == PathType.WATER || below == PathType.LAVA || below == PathType.OPEN) + return false; PathType in = this.nodeEvaluator.getPathType(new PathfindingContext(mob.level(), mob), x, y0, z); float priority = this.mob.getPathfindingMalus(in); - if (priority < 0.0F || priority >= 8.0F) return false; - if (in == PathType.DAMAGE_FIRE || in == PathType.DANGER_FIRE || in == PathType.DAMAGE_OTHER) return false; + if (priority < 0.0F || priority >= 8.0F) + return false; + if (in == PathType.DAMAGE_FIRE || in == PathType.DANGER_FIRE || in == PathType.DAMAGE_OTHER) + return false; } } } while (t <= max_t); @@ -249,10 +263,14 @@ static int trailEdgeToInt(float coord, int step) { static float element(Vec3 v, int i) { switch (i) { - case 0: return (float) v.x; - case 1: return (float) v.y; - case 2: return (float) v.z; - default: return 0.0F; + case 0: + return (float) v.x; + case 1: + return (float) v.y; + case 2: + return (float) v.z; + default: + return 0.0F; } } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java index 9e39dc7be..e47c06966 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java @@ -1,12 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.common.animatable; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.Nullable; + import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; @@ -16,11 +20,6 @@ import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.AnimationController; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import org.jetbrains.annotations.Nullable; /** * The {@link GeoAnimatable} interface specific to {@link BlockEntity BlockEntities} @@ -53,8 +52,8 @@ default void setAnimData(SerializableDataTicket dataTicket, D data) { if (level == null) { AzureLib.LOGGER.error( - "Attempting to set animation data for BlockEntity too early! Must wait until after the BlockEntity has been set in the world. ({})", - blockEntity.getClass() + "Attempting to set animation data for BlockEntity too early! Must wait until after the BlockEntity has been set in the world. ({})", + blockEntity.getClass() ); return; @@ -66,9 +65,9 @@ default void setAnimData(SerializableDataTicket dataTicket, D data) { BlockPos pos = blockEntity.getBlockPos(); BlockEntityAnimDataSyncPacket blockEntityAnimDataSyncPacket = new BlockEntityAnimDataSyncPacket<>( - pos, - dataTicket, - data + pos, + dataTicket, + data ); Services.NETWORK.sendToEntitiesTrackingChunk(blockEntityAnimDataSyncPacket, (ServerLevel) level, pos); } @@ -89,8 +88,8 @@ default void triggerAnim(@Nullable String controllerName, String animName) { if (level == null) { AzureLib.LOGGER.error( - "Attempting to trigger an animation for a BlockEntity too early! Must wait until after the BlockEntity has been set in the world. ({})", - blockEntity.getClass() + "Attempting to trigger an animation for a BlockEntity too early! Must wait until after the BlockEntity has been set in the world. ({})", + blockEntity.getClass() ); return; @@ -102,9 +101,9 @@ default void triggerAnim(@Nullable String controllerName, String animName) { BlockPos pos = blockEntity.getBlockPos(); BlockEntityAnimTriggerPacket blockEntityAnimTriggerPacket = new BlockEntityAnimTriggerPacket( - pos, - controllerName, - animName + pos, + controllerName, + animName ); Services.NETWORK.sendToEntitiesTrackingChunk(blockEntityAnimTriggerPacket, (ServerLevel) level, pos); } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java index 3f5b2ea01..b3d2330b5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java @@ -1,12 +1,13 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.common.animatable; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; + import mod.azure.azurelib.common.api.client.renderer.GeoReplacedEntityRenderer; import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; @@ -16,8 +17,6 @@ import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.AnimationController; -import net.minecraft.world.entity.Entity; -import org.jetbrains.annotations.Nullable; /** * The {@link GeoAnimatable} interface specific to {@link net.minecraft.world.entity.Entity Entities}. This also applies @@ -54,10 +53,10 @@ default void setAnimData(SerializableDataTicket dataTicket, D data) { getAnimatableInstanceCache().getManagerForId(entity.getId()).setData(dataTicket, data); } else { EntityAnimDataSyncPacket entityAnimDataSyncPacket = new EntityAnimDataSyncPacket<>( - entity.getId(), - false, - dataTicket, - data + entity.getId(), + false, + dataTicket, + data ); Services.NETWORK.sendToTrackingEntityAndSelf(entityAnimDataSyncPacket, entity); } @@ -79,10 +78,10 @@ default void triggerAnim(@Nullable String controllerName, String animName) { getAnimatableInstanceCache().getManagerForId(entity.getId()).tryTriggerAnimation(controllerName, animName); } else { EntityAnimTriggerPacket entityAnimTriggerPacket = new EntityAnimTriggerPacket( - entity.getId(), - false, - controllerName, - animName + entity.getId(), + false, + controllerName, + animName ); Services.NETWORK.sendToTrackingEntityAndSelf(entityAnimTriggerPacket, entity); } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java index 96a0c192d..0383be6ec 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java @@ -1,24 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.common.animatable; import com.google.common.base.Suppliers; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; -import mod.azure.azurelib.common.internal.common.cache.AnimatableIdCache; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; -import mod.azure.azurelib.core.animatable.instance.SingletonAnimatableInstanceCache; -import mod.azure.azurelib.core.animation.AnimatableManager; -import mod.azure.azurelib.core.animation.ContextAwareAnimatableManager; import net.minecraft.core.component.PatchedDataComponentMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.item.ItemDisplayContext; @@ -31,6 +18,18 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; +import mod.azure.azurelib.common.internal.common.cache.AnimatableIdCache; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; +import mod.azure.azurelib.core.animatable.instance.SingletonAnimatableInstanceCache; +import mod.azure.azurelib.core.animation.AnimatableManager; +import mod.azure.azurelib.core.animation.ContextAwareAnimatableManager; + /** * The {@link GeoAnimatable GeoAnimatable} interface specific to {@link net.minecraft.world.item.Item Items}. This also * applies to armor, as they are just items too. @@ -69,9 +68,9 @@ static void registerSyncedAnimatable(GeoAnimatable animatable) { */ static long getId(ItemStack stack) { return Optional.ofNullable(stack.getComponentsPatch().get(AzureLib.STACK_ANIMATABLE_ID_COMPONENT.get())) - .filter(Optional::isPresent) - .map(Optional::get) - .orElse(Long.MAX_VALUE); + .filter(Optional::isPresent) + .map(Optional::get) + .orElse(Long.MAX_VALUE); } /** @@ -142,31 +141,31 @@ public ContextBasedAnimatableInstanceCache(GeoAnimatable animatable) { public AnimatableManager getManagerForId(long uniqueId) { if (!this.managers.containsKey(uniqueId)) this.managers.put( - uniqueId, - new ContextAwareAnimatableManager(this.animatable) { - - @Override - protected Map> buildContextOptions( - GeoAnimatable animatable - ) { - Map> map = new EnumMap<>( - ItemDisplayContext.class - ); - - for (ItemDisplayContext context : ItemDisplayContext.values()) { - map.put(context, new AnimatableManager<>(animatable)); - } - - return map; + uniqueId, + new ContextAwareAnimatableManager(this.animatable) { + + @Override + protected Map> buildContextOptions( + GeoAnimatable animatable + ) { + Map> map = new EnumMap<>( + ItemDisplayContext.class + ); + + for (ItemDisplayContext context : ItemDisplayContext.values()) { + map.put(context, new AnimatableManager<>(animatable)); } - @Override - public ItemDisplayContext getCurrentContext() { - ItemDisplayContext context = getData(DataTickets.ITEM_RENDER_PERSPECTIVE); + return map; + } - return context == null ? ItemDisplayContext.NONE : context; - } + @Override + public ItemDisplayContext getCurrentContext() { + ItemDisplayContext context = getData(DataTickets.ITEM_RENDER_PERSPECTIVE); + + return context == null ? ItemDisplayContext.NONE : context; } + } ); return this.managers.get(uniqueId); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java index da12b83f9..eb601e5ac 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java @@ -1,12 +1,17 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.common.animatable; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Supplier; + import mod.azure.azurelib.common.internal.client.RenderProvider; import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; @@ -16,12 +21,6 @@ import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.AnimationController; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; -import java.util.function.Supplier; /** * The {@link GeoAnimatable} interface specific to {@link Entity Entities}. This interface is specifically for @@ -62,10 +61,10 @@ default void setAnimData(Entity relatedEntity, SerializableDataTicket dat getAnimatableInstanceCache().getManagerForId(relatedEntity.getId()).setData(dataTicket, data); } else { EntityAnimDataSyncPacket entityAnimDataSyncPacket = new EntityAnimDataSyncPacket<>( - relatedEntity.getId(), - true, - dataTicket, - data + relatedEntity.getId(), + true, + dataTicket, + data ); Services.NETWORK.sendToTrackingEntityAndSelf(entityAnimDataSyncPacket, relatedEntity); } @@ -84,13 +83,13 @@ default void setAnimData(Entity relatedEntity, SerializableDataTicket dat default void triggerAnim(Entity relatedEntity, @Nullable String controllerName, String animName) { if (relatedEntity.level().isClientSide()) { getAnimatableInstanceCache().getManagerForId(relatedEntity.getId()) - .tryTriggerAnimation(controllerName, animName); + .tryTriggerAnimation(controllerName, animName); } else { EntityAnimTriggerPacket entityAnimTriggerPacket = new EntityAnimTriggerPacket( - relatedEntity.getId(), - true, - controllerName, - animName + relatedEntity.getId(), + true, + controllerName, + animName ); Services.NETWORK.sendToTrackingEntityAndSelf(entityAnimTriggerPacket, relatedEntity); } @@ -111,8 +110,7 @@ default double getTick(Object entity) { // These methods aren't used for GeoReplacedEntity @Override - default void createRenderer(Consumer consumer) { - } + default void createRenderer(Consumer consumer) {} // These methods aren't used for GeoReplacedEntity @Override diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/config/Config.java b/common/src/main/java/mod/azure/azurelib/common/api/common/config/Config.java index a9b9d6fa6..9c566c853 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/config/Config.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/config/Config.java @@ -1,18 +1,16 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.api.common.config; -import mod.azure.azurelib.common.internal.common.config.Configurable; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import mod.azure.azurelib.common.internal.common.config.Configurable; + /** * Config marker annotation. Every registered config class must have this annotation. Inside this class you should * define all configurable fields (cannot be {@code STATIC})!. All configurable fields must be annotated with @@ -54,6 +52,5 @@ */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) - @interface NoAutoSync { - } + @interface NoAutoSync {} } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/config/TestingConfig.java b/common/src/main/java/mod/azure/azurelib/common/api/common/config/TestingConfig.java index a314b7d0a..ea0f090d0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/config/TestingConfig.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/config/TestingConfig.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.api.common.config; -import mod.azure.azurelib.common.internal.client.config.IValidationHandler; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.Configurable; -import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; import net.minecraft.network.chat.Component; import java.util.Arrays; import java.util.regex.Pattern; +import mod.azure.azurelib.common.internal.client.config.IValidationHandler; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.Configurable; +import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; + @Config(id = AzureLib.MOD_ID) public final class TestingConfig { @@ -50,22 +49,22 @@ public final class TestingConfig { @Configurable @Configurable.FixedSize - public boolean[] boolArray = {false, false, true, false}; + public boolean[] boolArray = { false, false, true, false }; @Configurable @Configurable.Range(min = 50, max = 160) - public int[] intArray = {153, 123, 54}; + public int[] intArray = { 153, 123, 54 }; @Configurable - public long[] longArray = {13, 56, 133}; + public long[] longArray = { 13, 56, 133 }; @Configurable @Configurable.DecimalRange(min = 500.0F) - public float[] floatArray = {135.32F, 1561.23F}; + public float[] floatArray = { 135.32F, 1561.23F }; @Configurable @Configurable.ValueUpdateCallback(method = "onUpdate") - public String[] stringArray = {"minecraft:test"}; + public String[] stringArray = { "minecraft:test" }; @Configurable public TestEnum testEnum = TestEnum.C; @@ -76,7 +75,7 @@ public final class TestingConfig { public void onUpdate(String[] value, IValidationHandler handler) { AzureLib.LOGGER.debug(() -> Arrays.toString(value)); handler.setValidationResult( - ValidationResult.warn(Component.translatable("config.azurelib.option.genericwarning")) + ValidationResult.warn(Component.translatable("config.azurelib.option.genericwarning")) ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/entities/AzureVibrationUser.java b/common/src/main/java/mod/azure/azurelib/common/api/common/entities/AzureVibrationUser.java index c753d3047..ef691115d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/entities/AzureVibrationUser.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/entities/AzureVibrationUser.java @@ -79,14 +79,14 @@ public boolean isValidVibration(Holder gameEvent, @NotNull Context co @Override public boolean canReceiveVibration( - @NotNull ServerLevel serverLevel, - @NotNull BlockPos blockPos, - @NotNull Holder gameEvent, - GameEvent.@NotNull Context context + @NotNull ServerLevel serverLevel, + @NotNull BlockPos blockPos, + @NotNull Holder gameEvent, + GameEvent.@NotNull Context context ) { if ( - mob.isNoAi() || mob.isDeadOrDying() || !mob.level().getWorldBorder().isWithinBounds(blockPos) || mob - .isRemoved() + mob.isNoAi() || mob.isDeadOrDying() || !mob.level().getWorldBorder().isWithinBounds(blockPos) || mob + .isRemoved() ) return false; var entity = context.sourceEntity(); @@ -95,12 +95,12 @@ public boolean canReceiveVibration( @Override public void onReceiveVibration( - @NotNull ServerLevel serverLevel, - @NotNull BlockPos blockPos, - @NotNull Holder gameEvent, - @Nullable Entity entity, - @Nullable Entity entity2, - float f + @NotNull ServerLevel serverLevel, + @NotNull BlockPos blockPos, + @NotNull Holder gameEvent, + @Nullable Entity entity, + @Nullable Entity entity2, + float f ) { // Do nothing. } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/helper/CommonUtils.java b/common/src/main/java/mod/azure/azurelib/common/api/common/helper/CommonUtils.java index 1b1eef033..58ab7105e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/helper/CommonUtils.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/helper/CommonUtils.java @@ -1,10 +1,5 @@ package mod.azure.azurelib.common.api.common.helper; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; -import mod.azure.azurelib.common.internal.common.registry.AzureBlocksRegistry; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.common.platform.services.IPlatformHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.particles.ParticleOptions; @@ -13,14 +8,12 @@ import net.minecraft.world.entity.AreaEffectCloud; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.projectile.Projectile; -import net.minecraft.world.entity.projectile.ProjectileUtil; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; +import mod.azure.azurelib.common.internal.common.registry.AzureBlocksRegistry; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; + public record CommonUtils() { /** @@ -36,26 +29,26 @@ public record CommonUtils() { * @param effectTime How long the effect should be applied for? */ public static void summonAoE( - LivingEntity entity, - ParticleOptions particle, - int yOffset, - int duration, - float radius, - boolean hasEffect, - @Nullable Holder effect, - int effectTime + LivingEntity entity, + ParticleOptions particle, + int yOffset, + int duration, + float radius, + boolean hasEffect, + @Nullable Holder effect, + int effectTime ) { var areaEffectCloudEntity = new AreaEffectCloud( - entity.level(), - entity.getX(), - entity.getY() + yOffset, - entity.getZ() + entity.level(), + entity.getX(), + entity.getY() + yOffset, + entity.getZ() ); areaEffectCloudEntity.setRadius(radius); areaEffectCloudEntity.setDuration(duration); areaEffectCloudEntity.setParticle(particle); areaEffectCloudEntity.setRadiusPerTick( - -areaEffectCloudEntity.getRadius() / areaEffectCloudEntity.getDuration() + -areaEffectCloudEntity.getRadius() / areaEffectCloudEntity.getDuration() ); if (hasEffect && effect != null && !entity.hasEffect(effect)) areaEffectCloudEntity.addEffect(new MobEffectInstance(effect, effectTime, 0)); @@ -63,8 +56,8 @@ public static void summonAoE( } /** - * Spawns or refreshes a light source at the position of the firing entity. This method should - * only be called on the server side to place a temporary light-block. + * Spawns or refreshes a light source at the position of the firing entity. This method should only be called on the + * server side to place a temporary light-block. * * @param entity The entity (e.g., player or mob) using the weapon. * @param isInWaterBlock If true, the light-block will refresh faster when in water. @@ -82,7 +75,8 @@ public static void spawnLightSource(Entity entity, boolean isInWaterBlock) { tickingLightEntity.refresh(isInWaterBlock ? 20 : 0); } else { // Otherwise, place a new ticking light block - entity.level().setBlockAndUpdate(lightBlockPos, AzureBlocksRegistry.TICKING_LIGHT_BLOCK.get().defaultBlockState()); + entity.level() + .setBlockAndUpdate(lightBlockPos, AzureBlocksRegistry.TICKING_LIGHT_BLOCK.get().defaultBlockState()); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/interfaces/AzureTicker.java b/common/src/main/java/mod/azure/azurelib/common/api/common/interfaces/AzureTicker.java index e1accbce5..5aaf91afe 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/interfaces/AzureTicker.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/interfaces/AzureTicker.java @@ -1,7 +1,5 @@ package mod.azure.azurelib.common.api.common.interfaces; -import mod.azure.azurelib.common.api.common.entities.AzureVibrationUser; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.VibrationParticleOption; import net.minecraft.server.level.ServerLevel; @@ -12,6 +10,9 @@ import net.minecraft.world.level.gameevent.vibrations.VibrationSystem.Listener; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem.User; +import mod.azure.azurelib.common.api.common.entities.AzureVibrationUser; +import mod.azure.azurelib.common.platform.Services; + /** * Custom class for use with {@link AzureVibrationUser} */ @@ -45,15 +46,15 @@ private static void trySelectAndScheduleVibration(ServerLevel serverLevel, Data data.setTravelTimeInTicks(user.calculateTravelTimeInTicks(vibrationInfo.distance())); if (Services.PLATFORM.isDevelopmentEnvironment()) serverLevel.sendParticles( - new VibrationParticleOption(user.getPositionSource(), data.getTravelTimeInTicks()), - vec3.x, - vec3.y, - vec3.z, - 1, - 0.0, - 0.0, - 0.0, - 0.0 + new VibrationParticleOption(user.getPositionSource(), data.getTravelTimeInTicks()), + vec3.x, + vec3.y, + vec3.z, + 1, + 0.0, + 0.0, + 0.0, + 0.0 ); user.onDataChanged(); data.getSelectionStrategy().startOver(); @@ -61,10 +62,10 @@ private static void trySelectAndScheduleVibration(ServerLevel serverLevel, Data } private static boolean receiveVibration( - ServerLevel serverLevel, - Data data, - User user, - VibrationInfo vibrationInfo + ServerLevel serverLevel, + Data data, + User user, + VibrationInfo vibrationInfo ) { var blockPos = BlockPos.containing(vibrationInfo.pos()); var blockPos2 = user.getPositionSource().getPosition(serverLevel).map(BlockPos::containing).orElse(blockPos); @@ -72,12 +73,12 @@ private static boolean receiveVibration( return false; } user.onReceiveVibration( - serverLevel, - blockPos, - vibrationInfo.gameEvent(), - vibrationInfo.getEntity(serverLevel).orElse(null), - vibrationInfo.getProjectileOwner(serverLevel).orElse(null), - Listener.distanceBetweenInBlocks(blockPos, blockPos2) + serverLevel, + blockPos, + vibrationInfo.gameEvent(), + vibrationInfo.getEntity(serverLevel).orElse(null), + vibrationInfo.getProjectileOwner(serverLevel).orElse(null), + Listener.distanceBetweenInBlocks(blockPos, blockPos2) ); data.setCurrentVibration(null); return true; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonArmorMaterialRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonArmorMaterialRegistryInterface.java index 0922c338f..5814b8728 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonArmorMaterialRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonArmorMaterialRegistryInterface.java @@ -1,18 +1,22 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.core.Holder; import net.minecraft.world.item.ArmorMaterial; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new Item: *

    * The following code demonstrates how to register a new armor material in the game: *

    + * *
    {@code
    - * public static final Holder TEST_ARMOR_MATERIAL = CommonArmorMaterialRegistryInterface.registerArmorMaterial("modid", "materialname", YOURCLASS::dummyArmorMaterial);
    + *
    + * public static final Holder TEST_ARMOR_MATERIAL = CommonArmorMaterialRegistryInterface
    + *     .registerArmorMaterial("modid", "materialname", YOURCLASS::dummyArmorMaterial);
      *
      * private static ArmorMaterial dummyArmorMaterial() {
      *     ArmorMaterial diamond = ArmorMaterials.DIAMOND.value();
    @@ -31,11 +35,14 @@
      * In this example:
      * 

    *
      - *
    • registerArmorMaterial is a method to register a new armor material with the specified mod ID and material name.
    • - *
    • dummyArmorMaterial creates a new instance of ArmorMaterial using the properties of the existing ArmorMaterials.DIAMOND.
    • + *
    • registerArmorMaterial is a method to register a new armor material with the specified mod ID and + * material name.
    • + *
    • dummyArmorMaterial creates a new instance of ArmorMaterial using the properties of the + * existing ArmorMaterials.DIAMOND.
    • *
    *

    - * The {@link net.minecraft.world.item.ArmorMaterial ArmorMaterial} class represents the material properties for an armor item. + * The {@link net.minecraft.world.item.ArmorMaterial ArmorMaterial} class represents the material properties for an + * armor item. *

    */ public interface CommonArmorMaterialRegistryInterface { @@ -49,7 +56,11 @@ public interface CommonArmorMaterialRegistryInterface { * @param The type of the armor material. * @return A holder for the registered armor material. */ - static Holder registerArmorMaterial(String modID, String matName, Supplier armorMaterial) { + static Holder registerArmorMaterial( + String modID, + String matName, + Supplier armorMaterial + ) { return Services.COMMON_REGISTRY.registerArmorMaterial(modID, matName, armorMaterial); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockEntityRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockEntityRegistryInterface.java index 9ccbaf53f..ac2b878d4 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockEntityRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockEntityRegistryInterface.java @@ -1,29 +1,40 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new Block Entity: *

    * The following code demonstrates how to register a new block entity type in the game: *

    + * *
    {@code
    - * public static final Supplier> TEST_BLOCKENTITY = CommonBlockEntityRegistryInterface.registerBlockEntity("modid", "blockentityname", () -> BlockEntityType.Builder.of(TestBlockEntity::new, TEST_BLOCK.get()).build(null));
    + *
    + * public static final Supplier> TEST_BLOCKENTITY = CommonBlockEntityRegistryInterface
    + *     .registerBlockEntity(
    + *         "modid",
    + *         "blockentityname",
    + *         () -> BlockEntityType.Builder.of(TestBlockEntity::new, TEST_BLOCK.get()).build(null)
    + *     );
      * }
    *

    * In this example: *

    *
      - *
    • registerBlockEntity is a method to register a new block entity with the specified mod ID and block entity name.
    • - *
    • TestBlockEntity::new is a reference to the constructor of the TestBlockEntity class.
    • + *
    • registerBlockEntity is a method to register a new block entity with the specified mod ID and block + * entity name.
    • + *
    • TestBlockEntity::new is a reference to the constructor of the TestBlockEntity + * class.
    • *
    • TEST_BLOCK.get() is a reference to the block associated with this block entity.
    • *
    *

    - * The {@link net.minecraft.world.level.block.entity.BlockEntityType BlockEntityType} class represents a block entity type in the game. + * The {@link net.minecraft.world.level.block.entity.BlockEntityType BlockEntityType} class represents a block entity + * type in the game. *

    */ public interface CommonBlockEntityRegistryInterface { @@ -37,7 +48,11 @@ public interface CommonBlockEntityRegistryInterface { * @param The type of the block entity. * @return A supplier for the registered block entity type. */ - static Supplier> registerBlockEntity(String modID, String blockEntityName, Supplier> blockEntity) { + static Supplier> registerBlockEntity( + String modID, + String blockEntityName, + Supplier> blockEntity + ) { return Services.COMMON_REGISTRY.registerBlockEntity(modID, blockEntityName, blockEntity); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockRegistryInterface.java index 129e1e181..06a8a5c98 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockRegistryInterface.java @@ -1,17 +1,24 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.world.level.block.Block; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new Block: *

    * The following code demonstrates how to register a new block in the game: *

    + * *
    {@code
    - * public static final Supplier TEST_BLOCK = CommonBlockRegistryInterface.registerBlock("modid", "blockname", TestBlock::new);
    + *
    + * public static final Supplier TEST_BLOCK = CommonBlockRegistryInterface.registerBlock(
    + *     "modid",
    + *     "blockname",
    + *     TestBlock::new
    + * );
      * }
    *

    * In this example: @@ -38,4 +45,4 @@ public interface CommonBlockRegistryInterface { static Supplier registerBlock(String modID, String blockName, Supplier block) { return Services.COMMON_REGISTRY.registerBlock(modID, blockName, block); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonCreativeTabRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonCreativeTabRegistryInterface.java index 76edcdeb9..3bf0044be 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonCreativeTabRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonCreativeTabRegistryInterface.java @@ -5,26 +5,31 @@ *

    * The following code demonstrates how to register a new creative mode tab in the game: *

    + * *
    {@code
    + *
      * public static final Supplier EXAMPLEMOD_TAB = Services.COMMON_REGISTRY.registerCreativeModeTab(
    - *         AzureLib.MOD_ID,
    - *         "examplemod_items",
    - *         () -> Services.COMMON_REGISTRY.newCreativeTabBuilder()
    - *             .title(Component.translatable("itemGroup." + AzureLib.MOD_ID + ".examplemod_items"))
    - *             .icon(() -> new ItemStack(Items.ITEM_FRAME))
    - *             .displayItems((enabledFeatures, entries) -> entries.accept(Items.ITEM_FRAME))
    - *             .build());
    + *     AzureLib.MOD_ID,
    + *     "examplemod_items",
    + *     () -> Services.COMMON_REGISTRY.newCreativeTabBuilder()
    + *         .title(Component.translatable("itemGroup." + AzureLib.MOD_ID + ".examplemod_items"))
    + *         .icon(() -> new ItemStack(Items.ITEM_FRAME))
    + *         .displayItems((enabledFeatures, entries) -> entries.accept(Items.ITEM_FRAME))
    + *         .build()
    + * );
      * }
    *

    * In this example: *

    *
      - *
    • registerCreativeModeTab is a method to register a new creative mode tab with the specified mod ID and tab name.
    • - *
    • The newCreativeTabBuilder method is used to build the creative tab with a title, icon, and displayed items.
    • + *
    • registerCreativeModeTab is a method to register a new creative mode tab with the specified mod ID + * and tab name.
    • + *
    • The newCreativeTabBuilder method is used to build the creative tab with a title, icon, and displayed + * items.
    • *
    *

    - * The {@link net.minecraft.world.item.CreativeModeTab CreativeModeTab} class represents a tab in the creative inventory menu. + * The {@link net.minecraft.world.item.CreativeModeTab CreativeModeTab} class represents a tab in the creative inventory + * menu. *

    */ -public interface CommonCreativeTabRegistryInterface { -} +public interface CommonCreativeTabRegistryInterface {} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonEntityRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonEntityRegistryInterface.java index 2b965cc2f..6a4469773 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonEntityRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonEntityRegistryInterface.java @@ -1,29 +1,40 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.MobCategory; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new Entity: *

    * The following code demonstrates how to register a new entity type in the game: *

    + * *
    {@code
    - * public static final Supplier> TEST = CommonEntityRegistryInterface.registerEntity("modid", "entityname", TestEntity::new, MobCategory.CREATURE, 0.7f, 1.3f);
    + *
    + * public static final Supplier> TEST = CommonEntityRegistryInterface.registerEntity(
    + *     "modid",
    + *     "entityname",
    + *     TestEntity::new,
    + *     MobCategory.CREATURE,
    + *     0.7f,
    + *     1.3f
    + * );
      * }
    *

    * In this example: *

    *
      - *
    • registerEntity is a method to register a new entity with the specified mod ID, entity name, factory method, dimensions, and spawn egg colors.
    • + *
    • registerEntity is a method to register a new entity with the specified mod ID, entity name, factory + * method, dimensions, and spawn egg colors.
    • *
    • TestEntity::new is a reference to the constructor of the TestEntity class.
    • *
    • 0.7f and 1.3f represent the width and height of the entity, respectively.
    • - *
    • 0x1F1F1F and 0x0D0D0D represent the primary and secondary colors of the entity's spawn egg.
    • + *
    • 0x1F1F1F and 0x0D0D0D represent the primary and secondary colors of the entity's spawn + * egg.
    • *
    *

    * The {@link net.minecraft.world.entity.EntityType EntityType} class represents an entity type in the game. @@ -42,8 +53,18 @@ public interface CommonEntityRegistryInterface { * @param The type of the entity. * @return A supplier for the registered entity type. */ - static Supplier> registerEntity(String modID, String entityName, EntityType.EntityFactory entity, MobCategory mobCategory, float width, float height) { - return Services.COMMON_REGISTRY.registerEntity(modID, entityName, - () -> EntityType.Builder.of(entity, mobCategory).sized(width, height).build(entityName)); + static Supplier> registerEntity( + String modID, + String entityName, + EntityType.EntityFactory entity, + MobCategory mobCategory, + float width, + float height + ) { + return Services.COMMON_REGISTRY.registerEntity( + modID, + entityName, + () -> EntityType.Builder.of(entity, mobCategory).sized(width, height).build(entityName) + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonFluidRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonFluidRegistryInterface.java index 159754ec0..1f8bd8704 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonFluidRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonFluidRegistryInterface.java @@ -1,17 +1,24 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.world.level.material.Fluid; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new Fluid: *

    * The following code demonstrates how to register a new Fluid in the game: *

    + * *
    {@code
    - * public static final Supplier TEST_FLUID = CommonFluidRegistryInterface.registerFluid("modid", "fluidName", () -> new CustomFluid());
    + *
    + * public static final Supplier TEST_FLUID = CommonFluidRegistryInterface.registerFluid(
    + *     "modid",
    + *     "fluidName",
    + *     () -> new CustomFluid()
    + * );
      * }
    *

    * In this example: diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonItemRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonItemRegistryInterface.java index 991d2798f..29f08710f 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonItemRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonItemRegistryInterface.java @@ -1,18 +1,30 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.world.item.Item; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new Item: *

    * The following code demonstrates how to register a new item and a spawn egg in the game: *

    + * *
    {@code
    - * public static final Supplier TEST_ITEM = CommonItemRegistryInterface.registerItem("modid", "itemname", () -> new Item(new Item.Properties()));
    - * public static final Supplier TEST_SPAWN_EGG = CommonItemRegistryInterface.registerItem("modid", "entityname_spawn_egg", Services.COMMON_REGISTRY.makeSpawnEggFor(TESTENTITY, 0x1F1F1F, 0x0D0D0D, new Item.Properties()));
    + *
    + * public static final Supplier TEST_ITEM = CommonItemRegistryInterface.registerItem(
    + *     "modid",
    + *     "itemname",
    + *     () -> new Item(new Item.Properties())
    + * );
    + *
    + * public static final Supplier TEST_SPAWN_EGG = CommonItemRegistryInterface.registerItem(
    + *     "modid",
    + *     "entityname_spawn_egg",
    + *     Services.COMMON_REGISTRY.makeSpawnEggFor(TESTENTITY, 0x1F1F1F, 0x0D0D0D, new Item.Properties())
    + * );
      * }
    *

    * In this example: @@ -20,7 +32,8 @@ *

      *
    • registerItem is a method to register a new item with the specified mod ID and item name.
    • *
    • Item is used to create a new item instance with default properties.
    • - *
    • makeSpawnEggFor is a method to create a spawn egg for the specified entity with primary and secondary colors.
    • + *
    • makeSpawnEggFor is a method to create a spawn egg for the specified entity with primary and + * secondary colors.
    • *
    *

    * The {@link net.minecraft.world.item.Item Item} class represents an item in the game. @@ -43,4 +56,4 @@ public interface CommonItemRegistryInterface { static Supplier registerItem(String modID, String itemName, Supplier item) { return Services.COMMON_REGISTRY.registerItem(modID, itemName, item); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonMenuTypesRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonMenuTypesRegistryInterface.java index 2abc3a70a..a70980b49 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonMenuTypesRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonMenuTypesRegistryInterface.java @@ -1,23 +1,31 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.world.inventory.MenuType; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new MenuType: *

    * The following code demonstrates how to register a new screen type in the game: *

    + * *
    {@code
    - * public static final Supplier> TEST = CommonMenuTypesRegistryInterface.registerScreen("modid", "screenname", () -> new MenuType<>(CustomScreenHandler::new, FeatureFlags.VANILLA_SET));
    + *
    + * public static final Supplier> TEST = CommonMenuTypesRegistryInterface.registerScreen(
    + *     "modid",
    + *     "screenname",
    + *     () -> new MenuType<>(CustomScreenHandler::new, FeatureFlags.VANILLA_SET)
    + * );
      * }
    *

    * In this example: *

    *
      - *
    • registerScreen is a method to register a new screen type with the specified mod ID and screen name.
    • + *
    • registerScreen is a method to register a new screen type with the specified mod ID and screen + * name.
    • *
    • MenuType is used to create a new screen type instance.
    • *
    *

    @@ -38,4 +46,4 @@ public interface CommonMenuTypesRegistryInterface { static > Supplier registerScreen(String modID, String screenName, Supplier item) { return Services.COMMON_REGISTRY.registerScreen(modID, screenName, item); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonParticleRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonParticleRegistryInterface.java index 46ea086f9..92e5b0b8d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonParticleRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonParticleRegistryInterface.java @@ -1,27 +1,36 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.core.particles.ParticleType; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new Particle: *

    * The following code demonstrates how to register a new particle type in the game: *

    + * *
    {@code
    - * public static final Supplier TEST = CommonParticleRegistryInterface.registerParticle("modid", "particlename", () -> new SimpleParticleType(true));
    + *
    + * public static final Supplier TEST = CommonParticleRegistryInterface.registerParticle(
    + *     "modid",
    + *     "particlename",
    + *     () -> new SimpleParticleType(true)
    + * );
      * }
    *

    * In this example: *

    *
      - *
    • registerParticle is a method to register a new particle with the specified mod ID and particle name.
    • + *
    • registerParticle is a method to register a new particle with the specified mod ID and particle + * name.
    • *
    • SimpleParticleType is used to create a new particle type instance.
    • *
    *

    - * The {@link net.minecraft.core.particles.SimpleParticleType SimpleParticleType} class represents a basic particle type in the game. + * The {@link net.minecraft.core.particles.SimpleParticleType SimpleParticleType} class represents a basic particle type + * in the game. *

    */ public interface CommonParticleRegistryInterface { @@ -35,7 +44,11 @@ public interface CommonParticleRegistryInterface { * @param The type of the particle type. * @return A supplier for the registered particle type. */ - static > Supplier registerParticle(String modID, String particleName, Supplier particle) { + static > Supplier registerParticle( + String modID, + String particleName, + Supplier particle + ) { return Services.COMMON_REGISTRY.registerParticle(modID, particleName, particle); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonSoundRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonSoundRegistryInterface.java index a3c4ca6bd..28121fa6e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonSoundRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonSoundRegistryInterface.java @@ -1,24 +1,33 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.sounds.SoundEvent; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new SoundEvent: *

    * The following code demonstrates how to register a new sound event in the game: *

    + * *
    {@code
    - * public static Supplier TEST_SOUND = CommonSoundRegistryInterface.registerSound("modid", "test_sound", () -> SoundEvent.createVariableRangeEvent(
    - *             ResourceLocation.fromNamespaceAndPath("modid", "test_sound")));
    + *
    + * public static Supplier TEST_SOUND = CommonSoundRegistryInterface.registerSound(
    + *     "modid",
    + *     "test_sound",
    + *     () -> SoundEvent.createVariableRangeEvent(
    + *         ResourceLocation.fromNamespaceAndPath("modid", "test_sound")
    + *     )
    + * );
      * }
    *

    * In this example: *

    *
      - *
    • registerSound is a method to register a new sound event with the specified mod ID and sound name.
    • + *
    • registerSound is a method to register a new sound event with the specified mod ID and sound + * name.
    • *
    • SoundEvent is used to create a new sound event instance.
    • *
    *

    @@ -39,4 +48,4 @@ public interface CommonSoundRegistryInterface { static Supplier registerSound(String modID, String soundName, Supplier sound) { return Services.COMMON_REGISTRY.registerSound(modID, soundName, sound); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStatusEffectRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStatusEffectRegistryInterface.java index 5f8fecf17..b2b77eb74 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStatusEffectRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStatusEffectRegistryInterface.java @@ -1,25 +1,35 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.core.Holder; import net.minecraft.world.effect.MobEffect; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new Status Effect: *

    * The following code demonstrates how to register a new Status Effect in the game: *

    + * *
    {@code
    - * public static final Holder TEST_EFFECT = CommonStatusEffectRegistryInterface.registerStatusEffect("modid", "effectName", () -> new CustomMobEffect(
    - *             MobEffectCategory.HARMFUL, Color.BLACK.getColor()));
    + *
    + * public static final Holder TEST_EFFECT = CommonStatusEffectRegistryInterface.registerStatusEffect(
    + *     "modid",
    + *     "effectName",
    + *     () -> new CustomMobEffect(
    + *         MobEffectCategory.HARMFUL,
    + *         Color.BLACK.getColor()
    + *     )
    + * );
      * }
    *

    * In this example: *

    *
      - *
    • registerStatusEffect is a method to register a new status effect with the specified mod ID and effect name.
    • + *
    • registerStatusEffect is a method to register a new status effect with the specified mod ID and + * effect name.
    • *
    • MobEffect is the base class for all status effects in the game.
    • *
    • CustomMobEffect is a user-defined class extending MobEffect.
    • *
    • MobEffectCategory.HARMFUL specifies the category of the status effect.
    • @@ -29,7 +39,8 @@ * The {@link net.minecraft.world.effect.MobEffect MobEffect} class represents a status effect in the game. *

      *

      - * The {@link net.minecraft.world.effect.MobEffectCategory MobEffectCategory} class represents the category of a status effect in the game. + * The {@link net.minecraft.world.effect.MobEffectCategory MobEffectCategory} class represents the category of a status + * effect in the game. *

      */ public interface CommonStatusEffectRegistryInterface { @@ -43,7 +54,11 @@ public interface CommonStatusEffectRegistryInterface { * @param The type of the status effect extending from {@link net.minecraft.world.effect.MobEffect}. * @return A holder that provides the registered status effect. */ - static Holder registerStatusEffect(String modID, String effectName, Supplier statusEffect) { + static Holder registerStatusEffect( + String modID, + String effectName, + Supplier statusEffect + ) { return Services.COMMON_REGISTRY.registerStatusEffect(modID, effectName, statusEffect); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStructureRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStructureRegistryInterface.java index 41e439d24..fedfa4b57 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStructureRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStructureRegistryInterface.java @@ -1,25 +1,30 @@ package mod.azure.azurelib.common.api.common.registry; import com.mojang.serialization.MapCodec; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.level.levelgen.structure.StructureType; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new Structure: *

      * The following code demonstrates how to register a new structure in the game: *

      + * *
      {@code
      - * public static final Supplier> TEST = CommonStructureRegistryInterface.registerStructure("modid", "structurename", CustomStructure.CODEC);
      + *
      + * public static final Supplier> TEST = CommonStructureRegistryInterface
      + *     .registerStructure("modid", "structurename", CustomStructure.CODEC);
        * }
      *

      * In this example: *

      *
        - *
      • registerStructure is a method to register a new structure type with the specified mod ID and structure name.
      • + *
      • registerStructure is a method to register a new structure type with the specified mod ID and + * structure name.
      • *
      • "modid" is the identifier for your mod.
      • *
      • "structurename" is the name you want to give to your new structure.
      • *
      • CustomStructure.CODEC is the codec for your custom structure type.
      • @@ -36,7 +41,11 @@ public interface CommonStructureRegistryInterface { * @param The type of the structure. * @return A supplier for the registered structure type. */ - static Supplier> registerStructure(String modID, String structureName, MapCodec structure) { + static Supplier> registerStructure( + String modID, + String structureName, + MapCodec structure + ) { return Services.COMMON_REGISTRY.registerStructure(modID, structureName, structure); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/tags/AzureTags.java b/common/src/main/java/mod/azure/azurelib/common/api/common/tags/AzureTags.java index bba97f5d7..e065f31ba 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/tags/AzureTags.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/tags/AzureTags.java @@ -1,10 +1,11 @@ package mod.azure.azurelib.common.api.common.tags; -import mod.azure.azurelib.common.internal.common.AzureLib; import net.minecraft.core.registries.Registries; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; +import mod.azure.azurelib.common.internal.common.AzureLib; + public final class AzureTags { public static final TagKey GUNS = TagKey.create(Registries.ITEM, AzureLib.modResource("guns")); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/AzureLibClient.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/AzureLibClient.java index 819fc6cb3..2e3140066 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/AzureLibClient.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/AzureLibClient.java @@ -1,10 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ - package mod.azure.azurelib.common.internal.client; +package mod.azure.azurelib.common.internal.client; + +import net.minecraft.client.gui.screens.Screen; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; import mod.azure.azurelib.common.api.common.config.Config; import mod.azure.azurelib.common.internal.client.config.screen.ConfigGroupScreen; @@ -12,11 +16,6 @@ import mod.azure.azurelib.common.internal.common.config.ConfigHolder; import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import net.minecraft.client.gui.screens.Screen; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Map; public final class AzureLibClient { @@ -51,8 +50,8 @@ public static Screen getConfigScreen(Class configClass, Screen previous) { @Nullable public static Screen getConfigScreen(String configId, Screen previous) { return ConfigHolderRegistry.getConfig(configId) - .map(holder -> getConfigScreenForHolder(holder, previous)) - .orElse(null); + .map(holder -> getConfigScreenForHolder(holder, previous)) + .orElse(null); } /** diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java index 5c0352309..5ff882093 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java @@ -1,13 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ - package mod.azure.azurelib.common.internal.client; +package mod.azure.azurelib.common.internal.client; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.mixins.ItemRendererAccessor; import net.minecraft.client.Minecraft; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.Model; @@ -17,14 +13,16 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.mixins.ItemRendererAccessor; + /** * Internal interface for safely providing a custom renderer instances at runtime.
        * This can be safely instantiated as a new anonymous class inside your {@link Item} class */ public interface RenderProvider { - RenderProvider DEFAULT = new RenderProvider() { - }; + RenderProvider DEFAULT = new RenderProvider() {}; static RenderProvider of(ItemStack itemStack) { return of(itemStack.getItem()); @@ -43,16 +41,16 @@ default BlockEntityWithoutLevelRenderer getCustomRenderer() { } default Model getGenericArmorModel( - LivingEntity livingEntity, - ItemStack itemStack, - EquipmentSlot equipmentSlot, - HumanoidModel original + LivingEntity livingEntity, + ItemStack itemStack, + EquipmentSlot equipmentSlot, + HumanoidModel original ) { HumanoidModel replacement = getHumanoidArmorModel( - livingEntity, - itemStack, - equipmentSlot, - original + livingEntity, + itemStack, + equipmentSlot, + original ); if (replacement != original) { @@ -64,10 +62,10 @@ default Model getGenericArmorModel( } default HumanoidModel getHumanoidArmorModel( - LivingEntity livingEntity, - ItemStack itemStack, - EquipmentSlot equipmentSlot, - HumanoidModel original + LivingEntity livingEntity, + ItemStack itemStack, + EquipmentSlot equipmentSlot, + HumanoidModel original ) { return original; } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/ClientErrors.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/ClientErrors.java index 8dcdbc1f9..4504ff1f3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/ClientErrors.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/ClientErrors.java @@ -1,22 +1,21 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config; -import mod.azure.azurelib.common.internal.common.config.value.DecimalValue; -import mod.azure.azurelib.common.internal.common.config.value.IntegerValue; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import java.util.regex.Pattern; +import mod.azure.azurelib.common.internal.common.config.value.DecimalValue; +import mod.azure.azurelib.common.internal.common.config.value.IntegerValue; + public final class ClientErrors { public static final MutableComponent CHAR_VALUE_EMPTY = Component.translatable( - "text.azurelib.error.character_value_empty" + "text.azurelib.error.character_value_empty" ); private static final String KEY_NAN = "text.azurelib.error.nan"; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapter.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapter.java index f3e63dcb1..e671f4811 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapter.java @@ -1,21 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config; -import mod.azure.azurelib.common.internal.client.config.screen.ArrayConfigScreen; -import mod.azure.azurelib.common.internal.client.config.screen.ConfigScreen; -import mod.azure.azurelib.common.internal.client.config.widget.BooleanWidget; -import mod.azure.azurelib.common.internal.client.config.widget.ColorWidget; -import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; -import mod.azure.azurelib.common.internal.client.config.widget.EnumWidget; -import mod.azure.azurelib.common.internal.common.config.ConfigUtils; -import mod.azure.azurelib.common.internal.common.config.Configurable; -import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; -import mod.azure.azurelib.common.internal.common.config.value.*; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; @@ -30,30 +18,41 @@ import java.util.function.BiConsumer; import java.util.regex.Pattern; +import mod.azure.azurelib.common.internal.client.config.screen.ArrayConfigScreen; +import mod.azure.azurelib.common.internal.client.config.screen.ConfigScreen; +import mod.azure.azurelib.common.internal.client.config.widget.BooleanWidget; +import mod.azure.azurelib.common.internal.client.config.widget.ColorWidget; +import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; +import mod.azure.azurelib.common.internal.client.config.widget.EnumWidget; +import mod.azure.azurelib.common.internal.common.config.ConfigUtils; +import mod.azure.azurelib.common.internal.common.config.Configurable; +import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; +import mod.azure.azurelib.common.internal.common.config.value.*; + @FunctionalInterface public interface DisplayAdapter { static DisplayAdapter booleanValue() { return (value, field, container) -> container.addConfigWidget( - (x, y, width, height, configId) -> new BooleanWidget( - getValueX(x, width), - y, - getValueWidth(width), - 20, - (BooleanValue) value - ) + (x, y, width, height, configId) -> new BooleanWidget( + getValueX(x, width), + y, + getValueWidth(width), + 20, + (BooleanValue) value + ) ); } static DisplayAdapter characterValue() { return (value, field, container) -> container.addConfigWidget((x, y, width, height, configId) -> { EditBox widget = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); CharValue charValue = (CharValue) value; char character = charValue.get(); @@ -76,12 +75,12 @@ static DisplayAdapter characterValue() { static DisplayAdapter integerValue() { return (value, field, container) -> container.addConfigWidget((x, y, width, height, configId) -> { EditBox tfw = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); IntValue intValue = (IntValue) value; int num = intValue.get(); @@ -115,12 +114,12 @@ static DisplayAdapter integerValue() { static DisplayAdapter longValue() { return (value, field, container) -> container.addConfigWidget((x, y, width, height, configId) -> { EditBox tfw = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); LongValue longValue = (LongValue) value; long num = longValue.get(); @@ -154,12 +153,12 @@ static DisplayAdapter longValue() { static DisplayAdapter floatValue() { return (value, field, container) -> container.addConfigWidget((x, y, width, height, configId) -> { EditBox tfw = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); FloatValue floatValue = (FloatValue) value; DecimalFormat format = ConfigUtils.getDecimalFormat(field); @@ -194,12 +193,12 @@ static DisplayAdapter floatValue() { static DisplayAdapter doubleValue() { return (value, field, container) -> container.addConfigWidget((x, y, width, height, configId) -> { EditBox tfw = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); DoubleValue doubleValue = (DoubleValue) value; DecimalFormat format = ConfigUtils.getDecimalFormat(field); @@ -237,12 +236,12 @@ static DisplayAdapter stringValue() { StringValue strValue = (StringValue) value; EditBox widget = container.addConfigWidget((x, y, width, height, configId) -> { EditBox tfw = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); String val = strValue.get(); tfw.setValue(val); @@ -252,8 +251,8 @@ static DisplayAdapter stringValue() { if (!pattern.matcher(str).matches()) { String errDescriptor = strValue.getErrorDescriptor(); MutableComponent error = errDescriptor != null - ? Component.translatable(errDescriptor, str, pattern) - : ClientErrors.invalidText(str, pattern); + ? Component.translatable(errDescriptor, str, pattern) + : ClientErrors.invalidText(str, pattern); container.setValidationResult(ValidationResult.error(error)); return; } @@ -287,16 +286,16 @@ static DisplayAdapter booleanArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { boolean[] arr = arrayValue.get(); return new BooleanValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Boolean.TYPE, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Boolean.TYPE, setCallback, i)) ); }); screen.addElement(() -> { @@ -313,9 +312,9 @@ static DisplayAdapter booleanArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } @@ -331,16 +330,16 @@ static DisplayAdapter integerArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { int[] arr = arrayValue.get(); return new IntValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Integer.TYPE, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Integer.TYPE, setCallback, i)) ); }); screen.addElement(() -> { @@ -357,9 +356,9 @@ static DisplayAdapter integerArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } @@ -375,16 +374,16 @@ static DisplayAdapter longArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { long[] arr = arrayValue.get(); return new LongValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Long.TYPE, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Long.TYPE, setCallback, i)) ); }); screen.addElement(() -> { @@ -401,9 +400,9 @@ static DisplayAdapter longArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } @@ -419,16 +418,16 @@ static DisplayAdapter floatArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { float[] arr = arrayValue.get(); return new FloatValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Float.TYPE, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Float.TYPE, setCallback, i)) ); }); screen.addElement(() -> { @@ -445,9 +444,9 @@ static DisplayAdapter floatArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } @@ -463,16 +462,16 @@ static DisplayAdapter doubleArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { double[] arr = arrayValue.get(); return new DoubleValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Double.TYPE, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Double.TYPE, setCallback, i)) ); }); screen.addElement(() -> { @@ -489,9 +488,9 @@ static DisplayAdapter doubleArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } @@ -507,16 +506,16 @@ static DisplayAdapter stringArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { String[] arr = arrayValue.get(); return new StringValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, String.class, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, String.class, setCallback, i)) ); }); screen.addElement(() -> { @@ -533,21 +532,21 @@ static DisplayAdapter stringArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } static DisplayAdapter enumValue() { return (value, field, container) -> container.addConfigWidget( - (x, y, width, height, configId) -> new EnumWidget<>( - getValueX(x, width), - y, - getValueWidth(width), - 20, - (EnumValue) value - ) + (x, y, width, height, configId) -> new EnumWidget<>( + getValueX(x, width), + y, + getValueWidth(width), + 20, + (EnumValue) value + ) ); } @@ -559,17 +558,17 @@ static DisplayAdapter objectValue() { Minecraft client = Minecraft.getInstance(); Screen currentScreen = client.screen; Screen nestedConfigScreen = new ConfigScreen( - container.getComponentName(), - configId, - valueMap, - currentScreen + container.getComponentName(), + configId, + valueMap, + currentScreen ); client.setScreen(nestedConfigScreen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapterManager.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapterManager.java index a8fc773c4..32e8963e4 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapterManager.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapterManager.java @@ -1,17 +1,15 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeMatcher; - import java.util.Comparator; import java.util.HashMap; import java.util.Map; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeMatcher; + public final class DisplayAdapterManager { private static final Map ADAPTER_MAP = new HashMap<>(); @@ -40,12 +38,12 @@ private DisplayAdapterManager() { public static DisplayAdapter forType(Class type) { return ADAPTER_MAP.entrySet() - .stream() - .filter(entry -> entry.getKey().test(type)) - .sorted(Comparator.comparingInt(value -> value.getKey().priority())) - .map(Map.Entry::getValue) - .findFirst() - .orElse(null); + .stream() + .filter(entry -> entry.getKey().test(type)) + .sorted(Comparator.comparingInt(value -> value.getKey().priority())) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null); } public static void registerDisplayAdapter(TypeMatcher matcher, DisplayAdapter adapter) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/IValidationHandler.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/IValidationHandler.java index 61b1a65c5..4a97eaac7 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/IValidationHandler.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/IValidationHandler.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/WidgetAdder.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/WidgetAdder.java index f02760a48..779c284f1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/WidgetAdder.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/WidgetAdder.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/AbstractConfigScreen.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/AbstractConfigScreen.java index ea9840708..8e829c7fa 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/AbstractConfigScreen.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/AbstractConfigScreen.java @@ -1,21 +1,11 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.screen; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; -import mod.azure.azurelib.common.internal.client.config.IValidationHandler; -import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; -import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.config.value.ObjectValue; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; @@ -34,6 +24,15 @@ import java.util.Collection; import java.util.List; +import mod.azure.azurelib.common.internal.client.config.IValidationHandler; +import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; +import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; +import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.config.value.ObjectValue; + public abstract class AbstractConfigScreen extends Screen { public static final int HEADER_HEIGHT = 35; @@ -57,14 +56,14 @@ protected AbstractConfigScreen(Component title, Screen previous, String configId } public static void renderScrollbar( - GuiGraphics graphics, - int x, - int y, - int width, - int height, - int index, - int valueCount, - int paging + GuiGraphics graphics, + int x, + int y, + int width, + int height, + int index, + int valueCount, + int paging ) { if (valueCount <= paging) return; @@ -89,12 +88,26 @@ public void onClose() { protected void addFooter() { int centerY = this.height - FOOTER_HEIGHT + (FOOTER_HEIGHT - 20) / 2; addRenderableWidget( - Button.builder(ConfigEntryWidget.BACK, this::buttonBackClicked).pos(20, centerY).size(50, 20).build()); + Button.builder(ConfigEntryWidget.BACK, this::buttonBackClicked).pos(20, centerY).size(50, 20).build() + ); + addRenderableWidget( + Button.builder(ConfigEntryWidget.REVERT_DEFAULTS, this::buttonRevertToDefaultClicked) + .pos( + 75, + centerY + ) + .size(120, 20) + .build() + ); addRenderableWidget( - Button.builder(ConfigEntryWidget.REVERT_DEFAULTS, this::buttonRevertToDefaultClicked).pos(75, - centerY).size(120, 20).build()); - addRenderableWidget(Button.builder(ConfigEntryWidget.REVERT_CHANGES, this::buttonRevertChangesClicked).pos(200, - centerY).size(120, 20).build()); + Button.builder(ConfigEntryWidget.REVERT_CHANGES, this::buttonRevertChangesClicked) + .pos( + 200, + centerY + ) + .size(120, 20) + .build() + ); } protected void correctScrollingIndex(int count) { @@ -118,9 +131,9 @@ private void buttonBackClicked(Button button) { private void buttonRevertToDefaultClicked(Button button) { DialogScreen dialog = new DialogScreen( - ConfigEntryWidget.REVERT_DEFAULTS, - new Component[]{ConfigEntryWidget.REVERT_DEFAULTS_DIALOG_TEXT}, - this + ConfigEntryWidget.REVERT_DEFAULTS, + new Component[] { ConfigEntryWidget.REVERT_DEFAULTS_DIALOG_TEXT }, + this ); dialog.onConfirmed(screen -> { AzureLib.LOGGER.info(MARKER, "Reverting config {} to default values", this.configId); @@ -135,9 +148,9 @@ private void buttonRevertToDefaultClicked(Button button) { private void buttonRevertChangesClicked(Button button) { DialogScreen dialog = new DialogScreen( - ConfigEntryWidget.REVERT_CHANGES, - new Component[]{ConfigEntryWidget.REVERT_CHANGES_DIALOG_TEXT}, - this + ConfigEntryWidget.REVERT_CHANGES, + new Component[] { ConfigEntryWidget.REVERT_CHANGES_DIALOG_TEXT }, + this ); dialog.onConfirmed(screen -> { ConfigHolderRegistry.getConfig(this.configId).ifPresent(ConfigIO::reloadClientValues); @@ -172,11 +185,11 @@ private void saveConfig(boolean force) { } public void renderNotification( - NotificationSeverity severity, - GuiGraphics graphics, - List texts, - int mouseX, - int mouseY + NotificationSeverity severity, + GuiGraphics graphics, + List texts, + int mouseX, + int mouseY ) { if (!texts.isEmpty()) { int maxTextWidth = 0; @@ -213,24 +226,87 @@ public void renderNotification( int fadeMax = severity.fadeMax; int zIndex = 400; Matrix4f matrix4f = stack.last().pose(); - graphics.fillGradient(startX - 3, startY - 4, startX + maxTextWidth + 3, startY - 3, zIndex, background, - background); - graphics.fillGradient(startX - 3, startY + heightOffset + 3, startX + maxTextWidth + 3, - startY + heightOffset + 4, zIndex, background, background); - graphics.fillGradient(startX - 3, startY - 3, startX + maxTextWidth + 3, startY + heightOffset + 3, zIndex, - background, background); - graphics.fillGradient(startX - 4, startY - 3, startX - 3, startY + heightOffset + 3, zIndex, background, - background); - graphics.fillGradient(startX + maxTextWidth + 3, startY - 3, startX + maxTextWidth + 4, - startY + heightOffset + 3, zIndex, background, background); - graphics.fillGradient(startX - 3, startY - 3 + 1, startX - 3 + 1, startY + heightOffset + 3 - 1, zIndex, - fadeMin, fadeMax); - graphics.fillGradient(startX + maxTextWidth + 2, startY - 3 + 1, startX + maxTextWidth + 3, - startY + heightOffset + 3 - 1, zIndex, fadeMin, fadeMax); - graphics.fillGradient(startX - 3, startY - 3, startX + maxTextWidth + 3, startY - 3 + 1, zIndex, fadeMin, - fadeMin); - graphics.fillGradient(startX - 3, startY + heightOffset + 2, startX + maxTextWidth + 3, - startY + heightOffset + 3, zIndex, fadeMax, fadeMax); + graphics.fillGradient( + startX - 3, + startY - 4, + startX + maxTextWidth + 3, + startY - 3, + zIndex, + background, + background + ); + graphics.fillGradient( + startX - 3, + startY + heightOffset + 3, + startX + maxTextWidth + 3, + startY + heightOffset + 4, + zIndex, + background, + background + ); + graphics.fillGradient( + startX - 3, + startY - 3, + startX + maxTextWidth + 3, + startY + heightOffset + 3, + zIndex, + background, + background + ); + graphics.fillGradient( + startX - 4, + startY - 3, + startX - 3, + startY + heightOffset + 3, + zIndex, + background, + background + ); + graphics.fillGradient( + startX + maxTextWidth + 3, + startY - 3, + startX + maxTextWidth + 4, + startY + heightOffset + 3, + zIndex, + background, + background + ); + graphics.fillGradient( + startX - 3, + startY - 3 + 1, + startX - 3 + 1, + startY + heightOffset + 3 - 1, + zIndex, + fadeMin, + fadeMax + ); + graphics.fillGradient( + startX + maxTextWidth + 2, + startY - 3 + 1, + startX + maxTextWidth + 3, + startY + heightOffset + 3 - 1, + zIndex, + fadeMin, + fadeMax + ); + graphics.fillGradient( + startX - 3, + startY - 3, + startX + maxTextWidth + 3, + startY - 3 + 1, + zIndex, + fadeMin, + fadeMin + ); + graphics.fillGradient( + startX - 3, + startY + heightOffset + 2, + startX + maxTextWidth + 3, + startY + heightOffset + 3, + zIndex, + fadeMax, + fadeMax + ); RenderSystem.enableDepthTest(); RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); @@ -238,8 +314,10 @@ public void renderNotification( if (!severity.isOkStatus()) { Tesselator tessellator = Tesselator.getInstance(); RenderSystem.setShader(GameRenderer::getPositionColorShader); - BufferBuilder bufferbuilder = tessellator.begin(VertexFormat.Mode.QUADS, - DefaultVertexFormat.POSITION_TEX); + BufferBuilder bufferbuilder = tessellator.begin( + VertexFormat.Mode.QUADS, + DefaultVertexFormat.POSITION_TEX + ); ResourceLocation icon = severity.getIcon(); RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, icon); @@ -252,7 +330,6 @@ public void renderNotification( BufferUploader.drawWithShader(bufferbuilder.buildOrThrow()); } - RenderSystem.disableBlend(); MultiBufferSource.BufferSource bufferSource = Minecraft.getInstance().renderBuffers().bufferSource(); stack.translate(0.0D, 0.0D, zIndex); @@ -261,8 +338,18 @@ public void renderNotification( for (int i = 0; i < texts.size(); i++) { FormattedCharSequence textComponent = texts.get(i); if (textComponent != null) { - this.font.drawInBatch(textComponent, (float) startX + textOffset, (float) startY, -1, true, - matrix4f, bufferSource, Font.DisplayMode.NORMAL, 0, 0xf000f0); + this.font.drawInBatch( + textComponent, + (float) startX + textOffset, + (float) startY, + -1, + true, + matrix4f, + bufferSource, + Font.DisplayMode.NORMAL, + 0, + 0xf000f0 + ); } if (i == 0) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ArrayConfigScreen.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ArrayConfigScreen.java index adf03b1f4..dab0e62c5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ArrayConfigScreen.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ArrayConfigScreen.java @@ -1,20 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.screen; -import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; -import mod.azure.azurelib.common.internal.client.config.DisplayAdapterManager; -import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapters; -import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; -import mod.azure.azurelib.common.internal.common.config.value.ArrayValue; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.Button; @@ -27,6 +16,16 @@ import java.util.function.BiConsumer; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; +import mod.azure.azurelib.common.internal.client.config.DisplayAdapterManager; +import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapters; +import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; +import mod.azure.azurelib.common.internal.common.config.value.ArrayValue; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; + public class ArrayConfigScreen & ArrayValue> extends AbstractConfigScreen { public static final Component ADD_ELEMENT = Component.translatable("text.azurelib.value.add_element"); @@ -45,19 +44,19 @@ public class ArrayConfigScreen & ArrayValue> extends public ArrayConfigScreen(String ownerIdentifier, String configId, C array, Screen previous) { super( - Component.translatable(String.format("config.%s.option.%s", configId, ownerIdentifier)), - previous, - configId + Component.translatable(String.format("config.%s.option.%s", configId, ownerIdentifier)), + previous, + configId ); this.array = array; this.fixedSize = array.isFixedSize(); } public static TypeAdapter.AdapterContext callbackCtx( - Field parent, - Class componentType, - BiConsumer callback, - int index + Field parent, + Class componentType, + BiConsumer callback, + int index ) { return new DummyCallbackAdapter<>(componentType, parent, callback, index); } @@ -101,17 +100,23 @@ protected void init() { ConfigValue dummy = valueFactory.create(array.getId(), i); dummy.processFieldData(owner); ConfigEntryWidget widget = addRenderableWidget( - new ConfigEntryWidget(30, viewportMin + 10 + j * 25 + offset, this.width - 60, 20, dummy, - this.configId) + new ConfigEntryWidget( + 30, + viewportMin + 10 + j * 25 + offset, + this.width - 60, + 20, + dummy, + this.configId + ) ); widget.setDescriptionRenderer( - (graphics, widget1, severity, text) -> renderEntryDescription(graphics, widget1, severity, text) + (graphics, widget1, severity, text) -> renderEntryDescription(graphics, widget1, severity, text) ); if (adapter == null) { AzureLib.LOGGER.error( - MARKER, - "Missing display adapter for {} type, will not be displayed in GUI", - compType.getSimpleName() + MARKER, + "Missing display adapter for {} type, will not be displayed in GUI", + compType.getSimpleName() ); continue; } @@ -120,10 +125,10 @@ protected void init() { initializeGuiValue(dummy, widget); } catch (ClassCastException e) { AzureLib.LOGGER.error( - MARKER, - "Unable to create config field for {} type due to error {}", - compType.getSimpleName(), - e + MARKER, + "Unable to create config field for {} type due to error {}", + compType.getSimpleName(), + e ); } if (!fixedSize) { @@ -142,18 +147,18 @@ protected void init() { } private void renderEntryDescription( - GuiGraphics graphics, - AbstractWidget widget, - NotificationSeverity severity, - List text + GuiGraphics graphics, + AbstractWidget widget, + NotificationSeverity severity, + List text ) { if (!severity.isOkStatus()) { this.renderNotification( - severity, - graphics, - text, - widget.getX() + 5, - widget.getY() + widget.getHeight() + 10 + severity, + graphics, + text, + widget.getX() + 5, + widget.getY() + widget.getHeight() + 10 ); } } @@ -163,11 +168,26 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTi renderBackground(graphics, mouseX, mouseY, partialTicks); // HEADER int titleWidth = this.font.width(this.title); - graphics.drawString(font, this.title, (this.width - titleWidth) / 2, (HEADER_HEIGHT - this.font.lineHeight) / 2, 0xFFFFFF); + graphics.drawString( + font, + this.title, + (this.width - titleWidth) / 2, + (HEADER_HEIGHT - this.font.lineHeight) / 2, + 0xFFFFFF + ); graphics.fill(0, 0, width, HEADER_HEIGHT, 0x99 << 24); graphics.fill(0, height - FOOTER_HEIGHT, width, height, 0x99 << 24); graphics.fill(0, HEADER_HEIGHT, width, height - FOOTER_HEIGHT, 0x55 << 24); - renderScrollbar(graphics, width - 5, HEADER_HEIGHT, 5, height - FOOTER_HEIGHT - HEADER_HEIGHT, index, sizeSupplier.get(), pageSize); + renderScrollbar( + graphics, + width - 5, + HEADER_HEIGHT, + 5, + height - FOOTER_HEIGHT - HEADER_HEIGHT, + index, + sizeSupplier.get(), + pageSize + ); renderables.forEach(renderable -> renderable.render(graphics, mouseX, mouseY, partialTicks)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigGroupScreen.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigGroupScreen.java index 338e675b0..6f44d87db 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigGroupScreen.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigGroupScreen.java @@ -1,14 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.screen; -import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; -import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; -import mod.azure.azurelib.common.internal.common.config.ConfigHolder; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractWidget; @@ -19,6 +14,10 @@ import java.util.List; +import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; +import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; +import mod.azure.azurelib.common.internal.common.config.ConfigHolder; + import static mod.azure.azurelib.common.internal.client.config.screen.AbstractConfigScreen.FOOTER_HEIGHT; import static mod.azure.azurelib.common.internal.client.config.screen.AbstractConfigScreen.HEADER_HEIGHT; @@ -62,22 +61,22 @@ protected void init() { int y = viewportMin + 10 + j * 25 + offset; String configId = value.getConfigId(); this.addRenderableWidget( - new LeftAlignedLabel( - posX, - y, - componentWidth, - 20, - Component.translatable("config.screen." + configId), - this.font - ) + new LeftAlignedLabel( + posX, + y, + componentWidth, + 20, + Component.translatable("config.screen." + configId), + this.font + ) ); this.addRenderableWidget(Button.builder(ConfigEntryWidget.EDIT, btn -> { - ConfigScreen screen = new ConfigScreen(configId, configId, value.getValueMap(), this); - minecraft.setScreen(screen); - }) - .pos(DisplayAdapter.getValueX(posX, componentWidth), y) - .size(DisplayAdapter.getValueWidth(componentWidth), 20) - .build()); + ConfigScreen screen = new ConfigScreen(configId, configId, value.getValueMap(), this); + minecraft.setScreen(screen); + }) + .pos(DisplayAdapter.getValueX(posX, componentWidth), y) + .size(DisplayAdapter.getValueWidth(componentWidth), 20) + .build()); } initFooter(); } @@ -87,21 +86,36 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTi renderBackground(graphics, mouseX, mouseY, partialTicks); // HEADER int titleWidth = this.font.width(this.title); - graphics.drawString(font, this.title, (this.width - titleWidth) / 2, (HEADER_HEIGHT - this.font.lineHeight) / 2, 0xFFFFFF); + graphics.drawString( + font, + this.title, + (this.width - titleWidth) / 2, + (HEADER_HEIGHT - this.font.lineHeight) / 2, + 0xFFFFFF + ); graphics.fill(0, 0, width, HEADER_HEIGHT, 0x99 << 24); graphics.fill(0, height - FOOTER_HEIGHT, width, height, 0x99 << 24); graphics.fill(0, HEADER_HEIGHT, width, height - FOOTER_HEIGHT, 0x55 << 24); - AbstractConfigScreen.renderScrollbar(graphics, width - 5, HEADER_HEIGHT, 5, height - FOOTER_HEIGHT - HEADER_HEIGHT, index, configHolders.size(), pageSize); + AbstractConfigScreen.renderScrollbar( + graphics, + width - 5, + HEADER_HEIGHT, + 5, + height - FOOTER_HEIGHT - HEADER_HEIGHT, + index, + configHolders.size(), + pageSize + ); renderables.forEach(renderable -> renderable.render(graphics, mouseX, mouseY, partialTicks)); } protected void initFooter() { int centerY = this.height - FOOTER_HEIGHT + (FOOTER_HEIGHT - 20) / 2; addRenderableWidget( - Button.builder(ConfigEntryWidget.BACK, btn -> minecraft.setScreen(last)) - .pos(20, centerY) - .size(50, 20) - .build() + Button.builder(ConfigEntryWidget.BACK, btn -> minecraft.setScreen(last)) + .pos(20, centerY) + .size(50, 20) + .build() ); } @@ -133,17 +147,16 @@ public LeftAlignedLabel(int x, int y, int width, int height, Component label, Fo } @Override - public void updateWidgetNarration(NarrationElementOutput narrationElementOutput) { - } + public void updateWidgetNarration(NarrationElementOutput narrationElementOutput) {} @Override public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { graphics.drawString( - font, - this.getMessage(), - this.getX(), - this.getY() + (this.height - this.font.lineHeight) / 2, - 0xAAAAAA + font, + this.getMessage(), + this.getX(), + this.getY() + (this.height - this.font.lineHeight) / 2, + 0xAAAAAA ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigScreen.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigScreen.java index 3c2d195af..3182833a9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigScreen.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigScreen.java @@ -1,18 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.screen; -import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; -import mod.azure.azurelib.common.internal.client.config.DisplayAdapterManager; -import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.screens.Screen; @@ -25,15 +16,23 @@ import java.util.List; import java.util.Map; +import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; +import mod.azure.azurelib.common.internal.client.config.DisplayAdapterManager; +import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; + public class ConfigScreen extends AbstractConfigScreen { private final Map> valueMap; public ConfigScreen( - String ownerIdentifier, - String configId, - Map> valueMap, - Screen previous + String ownerIdentifier, + String configId, + Map> valueMap, + Screen previous ) { this(Component.translatable("config.screen." + ownerIdentifier), configId, valueMap, previous); } @@ -45,7 +44,6 @@ public ConfigScreen(Component screenTitle, String configId, Map value = values.get(i); - ConfigEntryWidget widget = addRenderableWidget(new ConfigEntryWidget(30, viewportMin + 10 + j * 25 + offset, this.width - 60, 20, value, this.configId)); - widget.setDescriptionRenderer((graphics, widget1, severity, text) -> renderEntryDescription(graphics, widget1, severity, text)); + ConfigEntryWidget widget = addRenderableWidget( + new ConfigEntryWidget(30, viewportMin + 10 + j * 25 + offset, this.width - 60, 20, value, this.configId) + ); + widget.setDescriptionRenderer( + (graphics, widget1, severity, text) -> renderEntryDescription(graphics, widget1, severity, text) + ); TypeAdapter.AdapterContext context = value.getSerializationContext(); Field field = context.getOwner(); DisplayAdapter adapter = DisplayAdapterManager.forType(field.getType()); if (adapter == null) { AzureLib.LOGGER.error( - MARKER, - "Missing display adapter for {} type, will not be displayed in GUI", - field.getType().getSimpleName() + MARKER, + "Missing display adapter for {} type, will not be displayed in GUI", + field.getType().getSimpleName() ); continue; } @@ -79,10 +81,10 @@ protected void init() { initializeGuiValue(value, widget); } catch (ClassCastException e) { AzureLib.LOGGER.error( - MARKER, - "Unable to create config field for {} type due to error {}", - field.getType().getSimpleName(), - e + MARKER, + "Unable to create config field for {} type due to error {}", + field.getType().getSimpleName(), + e ); } } @@ -90,10 +92,10 @@ protected void init() { } private void renderEntryDescription( - GuiGraphics graphics, - AbstractWidget widget, - NotificationSeverity severity, - List text + GuiGraphics graphics, + AbstractWidget widget, + NotificationSeverity severity, + List text ) { int x = widget.getX() + 5; int y = widget.getY() + widget.getHeight() + 10; @@ -109,12 +111,28 @@ public void render(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float renderBackground(graphics, mouseX, mouseY, partialTicks); // HEADER int titleWidth = this.font.width(this.title); - graphics.drawString(font, this.title, (this.width - titleWidth) / 2, (HEADER_HEIGHT - this.font.lineHeight) / 2, 0xFFFFFF, true); + graphics.drawString( + font, + this.title, + (this.width - titleWidth) / 2, + (HEADER_HEIGHT - this.font.lineHeight) / 2, + 0xFFFFFF, + true + ); graphics.setColor(1.0F, 1.0F, 1.0F, 1.0F); graphics.fill(0, 0, width, HEADER_HEIGHT, 0x99 << 24); graphics.fill(0, height - FOOTER_HEIGHT, width, height, 0x99 << 24); graphics.fill(0, HEADER_HEIGHT, width, height - FOOTER_HEIGHT, 0x55 << 24); - renderScrollbar(graphics, width - 5, HEADER_HEIGHT, 5, height - FOOTER_HEIGHT - HEADER_HEIGHT, index, valueMap.size(), pageSize); + renderScrollbar( + graphics, + width - 5, + HEADER_HEIGHT, + 5, + height - FOOTER_HEIGHT - HEADER_HEIGHT, + index, + valueMap.size(), + pageSize + ); renderables.forEach(renderable -> renderable.render(graphics, mouseX, mouseY, partialTicks)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/DialogScreen.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/DialogScreen.java index 84f01b6f7..2696559ef 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/DialogScreen.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/DialogScreen.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.screen; @@ -20,14 +18,23 @@ public class DialogScreen extends Screen { public static final Component TEXT_CONFIRM = Component.translatable("text.azurelib.screen.dialog.confirm"); public static final Component TEXT_CANCEL = Component.translatable("text.azurelib.screen.dialog.cancel"); + protected final Component[] text; + private final Screen background; + protected int dialogWidth; + protected int dialogHeight; + protected int dialogLeft; + protected int dialogTop; + private DialogRespondEvent onCancel; + private DialogRespondEvent onConfirm; + private List splitText = new ArrayList<>(); public DialogScreen(Component title, Component[] text, Screen background) { @@ -53,9 +60,9 @@ public void setDimensions(int dialogWidth, int dialogHeight) { this.dialogLeft = (this.width - this.dialogWidth) / 2; this.dialogTop = (this.height - this.dialogHeight) / 2; this.splitText = Arrays.stream(this.text) - .map(line -> this.font.split(line, this.dialogWidth - 10)) - .flatMap(Collection::stream) - .toList(); + .map(line -> this.font.split(line, this.dialogWidth - 10)) + .flatMap(Collection::stream) + .toList(); } @Override @@ -71,8 +78,22 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTi this.background.render(graphics, mouseX, mouseY, partialTicks); graphics.pose().pushPose(); graphics.pose().translate(0, 0, 400); - graphics.fillGradient(this.dialogLeft - 1, this.dialogTop - 1, this.dialogLeft + this.dialogWidth + 1, this.dialogTop + this.dialogHeight + 1, 0xFFFFFFFF, 0xFFFFFFFF); - graphics.fillGradient(this.dialogLeft, this.dialogTop, this.dialogLeft + this.dialogWidth, this.dialogTop + this.dialogHeight, backgroundColor, backgroundColor); + graphics.fillGradient( + this.dialogLeft - 1, + this.dialogTop - 1, + this.dialogLeft + this.dialogWidth + 1, + this.dialogTop + this.dialogHeight + 1, + 0xFFFFFFFF, + 0xFFFFFFFF + ); + graphics.fillGradient( + this.dialogLeft, + this.dialogTop, + this.dialogLeft + this.dialogWidth, + this.dialogTop + this.dialogHeight, + backgroundColor, + backgroundColor + ); this.renderForeground(graphics, mouseX, mouseY, partialTicks); renderables.forEach(renderable -> renderable.render(graphics, mouseX, mouseY, partialTicks)); graphics.pose().popPose(); @@ -96,22 +117,22 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { protected void renderForeground(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { int headerWidth = this.font.width(this.title); graphics.drawString( - this.font, - this.title, - (int) (this.dialogLeft + (this.dialogWidth - headerWidth) / 2.0F), - this.dialogTop + 5, - 0xFFFFFF, - true + this.font, + this.title, + (int) (this.dialogLeft + (this.dialogWidth - headerWidth) / 2.0F), + this.dialogTop + 5, + 0xFFFFFF, + true ); int line = 0; for (FormattedCharSequence textLine : this.splitText) { graphics.drawString( - this.font, - textLine, - this.dialogLeft + 5, - this.dialogTop + 20 + line * 10, - 0xFFFFFF, - true + this.font, + textLine, + this.dialogLeft + 5, + this.dialogTop + 20 + line * 10, + 0xFFFFFF, + true ); ++line; } @@ -125,11 +146,16 @@ protected void addDefaultDialogButtons() { int componentY = this.dialogTop + this.dialogHeight - 25; this.addRenderableWidget( - Button.builder(TEXT_CANCEL, btn -> cancel()).pos(cancelX, componentY).size(componentWidth, 20).build() + Button.builder(TEXT_CANCEL, btn -> cancel()).pos(cancelX, componentY).size(componentWidth, 20).build() ); this.addRenderableWidget( - Button.builder(TEXT_CONFIRM, btn -> confirm()).pos(confirmX, componentY).size(componentWidth, - 20).build() + Button.builder(TEXT_CONFIRM, btn -> confirm()) + .pos(confirmX, componentY) + .size( + componentWidth, + 20 + ) + .build() ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/BooleanWidget.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/BooleanWidget.java index fe0778033..3e54bfe1c 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/BooleanWidget.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/BooleanWidget.java @@ -1,13 +1,10 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.widget; import com.mojang.blaze3d.systems.RenderSystem; -import mod.azure.azurelib.common.internal.common.config.value.BooleanValue; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; @@ -21,17 +18,22 @@ import net.minecraft.util.Mth; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.internal.common.config.value.BooleanValue; + public class BooleanWidget extends AbstractWidget { public static final Component TRUE = Component.translatable("text.azurelib.value.true") - .withStyle(ChatFormatting.GREEN); + .withStyle(ChatFormatting.GREEN); + public static final Component FALSE = Component.translatable("text.azurelib.value.false") - .withStyle(ChatFormatting.RED); + .withStyle(ChatFormatting.RED); + private static final WidgetSprites SPRITES = new WidgetSprites( - ResourceLocation.parse("widget/button"), - ResourceLocation.parse("widget/button_disabled"), - ResourceLocation.parse("widget/button_highlighted") + ResourceLocation.parse("widget/button"), + ResourceLocation.parse("widget/button_disabled"), + ResourceLocation.parse("widget/button_highlighted") ); + private final BooleanValue value; public BooleanWidget(int x, int y, int w, int h, BooleanValue value) { @@ -47,11 +49,11 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float par RenderSystem.enableBlend(); RenderSystem.enableDepthTest(); graphics.blitSprite( - SPRITES.get(this.active, this.isHoveredOrFocused()), - this.getX(), - this.getY(), - this.getWidth(), - this.getHeight() + SPRITES.get(this.active, this.isHoveredOrFocused()), + this.getX(), + this.getY(), + this.getWidth(), + this.getHeight() ); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); int i = this.active ? 0xffffff : 0xa0a0a0; @@ -68,8 +70,7 @@ public void onClick(double x, double y) { } @Override - protected void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) { - } + protected void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) {} private void readState() { boolean value = this.value.get(); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ColorWidget.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ColorWidget.java index 0f2aa1842..dc8689969 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ColorWidget.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ColorWidget.java @@ -1,13 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.widget; -import mod.azure.azurelib.common.internal.client.config.screen.DialogScreen; -import mod.azure.azurelib.common.internal.common.config.Configurable; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractSliderButton; @@ -26,6 +22,9 @@ import java.util.function.IntSupplier; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.client.config.screen.DialogScreen; +import mod.azure.azurelib.common.internal.common.config.Configurable; + public final class ColorWidget extends AbstractWidget { public static final Component SELECT_COLOR = Component.translatable("text.azurelib.screen.color_dialog"); @@ -41,13 +40,13 @@ public final class ColorWidget extends AbstractWidget { private final Screen lastScreen; public ColorWidget( - int x, - int y, - int width, - int height, - Configurable.Gui.ColorValue colorOptions, - GetSet colorWidget, - Screen lastScreen + int x, + int y, + int width, + int height, + Configurable.Gui.ColorValue colorOptions, + GetSet colorWidget, + Screen lastScreen ) { super(x, y, width, height, CommonComponents.EMPTY); this.argb = colorOptions.isARGB(); @@ -71,19 +70,19 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float par int providedColor = this.colorSupplier.getAsInt(); int color = this.argb ? providedColor : (0xFF << 24) | providedColor; graphics.fill( - this.getX() - 1, - this.getY() - 1, - this.getX() + this.width + 1, - this.getY() + this.height + 1, - borderColor + this.getX() - 1, + this.getY() - 1, + this.getX() + this.width + 1, + this.getY() + this.height + 1, + borderColor ); graphics.fillGradient( - this.getX(), - this.getY(), - this.getX() + this.width, - this.getY() + this.height, - 0xFFFFFFFF, - 0xFF888888 + this.getX(), + this.getY(), + this.getX() + this.width, + this.getY() + this.height, + 0xFFFFFFFF, + 0xFF888888 ); graphics.fill(this.getX(), this.getY(), this.getX() + this.width, this.getY() + this.height, color); } @@ -96,10 +95,10 @@ protected boolean isValidClickButton(int button) { @Override public void onClick(double mouseX, double mouseY) { ColorSelectorDialog dialog = new ColorSelectorDialog( - SELECT_COLOR, - this.lastScreen, - this.argb, - this.colorSupplier + SELECT_COLOR, + this.lastScreen, + this.argb, + this.colorSupplier ); dialog.onConfirmed(screen -> { int color = dialog.getResultColor(); @@ -111,8 +110,7 @@ public void onClick(double mouseX, double mouseY) { } @Override - public void updateWidgetNarration(@NotNull NarrationElementOutput elementOutput) { - } + public void updateWidgetNarration(@NotNull NarrationElementOutput elementOutput) {} public interface GetSet { @@ -145,10 +143,10 @@ private static final class ColorSelectorDialog extends DialogScreen { private final List sliders = new ArrayList<>(); public ColorSelectorDialog( - Component title, - Screen background, - boolean allowTransparency, - IntSupplier colorProvider + Component title, + Screen background, + boolean allowTransparency, + IntSupplier colorProvider ) { super(title, new Component[0], background); this.argb = allowTransparency; @@ -170,71 +168,70 @@ protected void init() { this.setDimensions(width, height); int color = this.colorProvider.getAsInt(); this.sliders.add( - this.addRenderableWidget( - new ColorSlider( - dialogLeft + 5, - dialogTop + 20, - dialogWidth - rightMargin, - 20, - color, - ColorComponent.RED - ) + this.addRenderableWidget( + new ColorSlider( + dialogLeft + 5, + dialogTop + 20, + dialogWidth - rightMargin, + 20, + color, + ColorComponent.RED ) + ) ); this.sliders.add( - this.addRenderableWidget( - new ColorSlider( - dialogLeft + 5, - dialogTop + 45, - dialogWidth - rightMargin, - 20, - color, - ColorComponent.GREEN - ) + this.addRenderableWidget( + new ColorSlider( + dialogLeft + 5, + dialogTop + 45, + dialogWidth - rightMargin, + 20, + color, + ColorComponent.GREEN ) + ) ); this.sliders.add( - this.addRenderableWidget( - new ColorSlider( - dialogLeft + 5, - dialogTop + 70, - dialogWidth - rightMargin, - 20, - color, - ColorComponent.BLUE - ) + this.addRenderableWidget( + new ColorSlider( + dialogLeft + 5, + dialogTop + 70, + dialogWidth - rightMargin, + 20, + color, + ColorComponent.BLUE ) + ) ); if (this.argb) { this.sliders.add( - this.addRenderableWidget( - new ColorSlider( - dialogLeft + 5, - dialogTop + 95, - dialogWidth - rightMargin, - 20, - color, - ColorComponent.ALPHA - ) + this.addRenderableWidget( + new ColorSlider( + dialogLeft + 5, + dialogTop + 95, + dialogWidth - rightMargin, + 20, + color, + ColorComponent.ALPHA ) + ) ); } this.addRenderableWidget( - new ColorDisplay( - dialogLeft + 5 + dialogWidth - rightMargin + 5, - dialogTop + 20, - rightMargin - 15, - rightMargin - 15, - argb, - this::getResultColor - ) + new ColorDisplay( + dialogLeft + 5 + dialogWidth - rightMargin + 5, + dialogTop + 20, + rightMargin - 15, + rightMargin - 15, + argb, + this::getResultColor + ) ); super.addDefaultDialogButtons(); } @Override - protected void addDefaultDialogButtons() { - } + protected void addDefaultDialogButtons() {} public int getResultColor() { int color = 0; @@ -298,26 +295,26 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float par } int borderColor = 0xffa0a0a0; graphics.fill( - this.getX(), - this.getY(), - this.getX() + this.width, - this.getY() + this.height, - borderColor + this.getX(), + this.getY(), + this.getX() + this.width, + this.getY() + this.height, + borderColor ); graphics.fillGradient( - this.getX() + 1, - this.getY() + 1, - this.getX() + this.width - 1, - this.getY() + this.height - 1, - 0xFFFFFFFF, - 0xFF888888 + this.getX() + 1, + this.getY() + 1, + this.getX() + this.width - 1, + this.getY() + this.height - 1, + 0xFFFFFFFF, + 0xFF888888 ); graphics.fill( - this.getX() + 1, - this.getY() + 1, - this.getX() + this.width - 1, - this.getY() + this.height - 1, - color + this.getX() + 1, + this.getY() + 1, + this.getX() + this.width - 1, + this.getY() + this.height - 1, + color ); } @@ -327,8 +324,7 @@ protected boolean isValidClickButton(int button) { } @Override - public void updateWidgetNarration(NarrationElementOutput p_169152_) { - } + public void updateWidgetNarration(NarrationElementOutput p_169152_) {} } private static final class ColorSlider extends AbstractSliderButton { @@ -348,8 +344,7 @@ protected void updateMessage() { } @Override - protected void applyValue() { - } + protected void applyValue() {} int getColor() { return this.colorComponent.getOffsetColor((int) (0xFF * this.value)); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ConfigEntryWidget.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ConfigEntryWidget.java index 2a8e0846e..c0ba37f64 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ConfigEntryWidget.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ConfigEntryWidget.java @@ -1,15 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.widget; -import mod.azure.azurelib.common.internal.client.config.WidgetAdder; -import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; -import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; @@ -26,6 +20,11 @@ import java.util.List; import java.util.stream.Collectors; +import mod.azure.azurelib.common.internal.client.config.WidgetAdder; +import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; +import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; + public class ConfigEntryWidget extends ContainerWidget implements WidgetAdder { public static final Component EDIT = Component.translatable("text.azurelib.value.edit"); @@ -35,13 +34,13 @@ public class ConfigEntryWidget extends ContainerWidget implements WidgetAdder { public static final Component REVERT_DEFAULTS = Component.translatable("text.azurelib.value.revert.default"); public static final Component REVERT_DEFAULTS_DIALOG_TEXT = Component.translatable( - "text.azurelib.value.revert.default.dialog" + "text.azurelib.value.revert.default.dialog" ); public static final Component REVERT_CHANGES = Component.translatable("text.azurelib.value.revert.changes"); public static final Component REVERT_CHANGES_DIALOG_TEXT = Component.translatable( - "text.azurelib.value.revert.changes.dialog" + "text.azurelib.value.revert.changes.dialog" ); private final String configId; @@ -60,8 +59,8 @@ public ConfigEntryWidget(int x, int y, int w, int h, ConfigValue value, Strin super(x, y, w, h, Component.translatable("config." + configId + ".option." + value.getId())); this.configId = configId; this.description = Arrays.stream(value.getDescription()) - .map(text -> Component.literal(text).withStyle(ChatFormatting.GRAY)) - .collect(Collectors.toList()); + .map(text -> Component.literal(text).withStyle(ChatFormatting.GRAY)) + .collect(Collectors.toList()); } public void setDescriptionRenderer(IDescriptionRenderer renderer) { @@ -74,8 +73,7 @@ public Component getComponentName() { } @Override - public void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) { - } + public void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) {} @Override public void renderWidget(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { @@ -85,12 +83,12 @@ public void renderWidget(@NotNull GuiGraphics graphics, int mouseX, int mouseY, } boolean isError = !this.result.isOk(); graphics.drawString( - font, - this.getMessage(), - this.getX(), - (int) (this.getY() + (this.height - font.lineHeight) / 2.0F), - 0xAAAAAA, - true + font, + this.getMessage(), + this.getX(), + (int) (this.getY() + (this.height - font.lineHeight) / 2.0F), + 0xAAAAAA, + true ); super.renderWidget(graphics, mouseX, mouseY, partialTicks); if ((isError || isHovered) && renderer != null) { @@ -100,8 +98,8 @@ public void renderWidget(@NotNull GuiGraphics graphics, int mouseX, int mouseY, MutableComponent textComponent = this.result.text().withStyle(severity.getExtraFormatting()); List desc = isError ? Collections.singletonList(textComponent) : this.description; List split = desc.stream() - .flatMap(text -> font.split(text, this.width / 2).stream()) - .collect(Collectors.toList()); + .flatMap(text -> font.split(text, this.width / 2).stream()) + .collect(Collectors.toList()); renderer.drawDescription(graphics, this, severity, split); } } @@ -123,10 +121,10 @@ public W addConfigWidget(ToWidgetFunction function public interface IDescriptionRenderer { void drawDescription( - GuiGraphics graphics, - AbstractWidget widget, - NotificationSeverity severity, - List text + GuiGraphics graphics, + AbstractWidget widget, + NotificationSeverity severity, + List text ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ContainerWidget.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ContainerWidget.java index 69524172c..37e19641d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ContainerWidget.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ContainerWidget.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.widget; @@ -75,18 +73,18 @@ public boolean mouseReleased(double p_231048_1_, double p_231048_3_, int p_23104 @Override public boolean mouseDragged( - double p_231045_1_, - double p_231045_3_, - int p_231045_5_, - double p_231045_6_, - double p_231045_8_ + double p_231045_1_, + double p_231045_3_, + int p_231045_5_, + double p_231045_6_, + double p_231045_8_ ) { return ContainerEventHandler.super.mouseDragged( - p_231045_1_, - p_231045_3_, - p_231045_5_, - p_231045_6_, - p_231045_8_ + p_231045_1_, + p_231045_3_, + p_231045_5_, + p_231045_6_, + p_231045_8_ ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/EnumWidget.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/EnumWidget.java index 7a46fac97..c23ecb6f0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/EnumWidget.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/EnumWidget.java @@ -1,13 +1,10 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.widget; import com.mojang.blaze3d.systems.RenderSystem; -import mod.azure.azurelib.common.internal.common.config.value.EnumValue; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; @@ -20,12 +17,14 @@ import net.minecraft.util.Mth; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.internal.common.config.value.EnumValue; + public class EnumWidget> extends AbstractWidget { private static final WidgetSprites SPRITES = new WidgetSprites( - ResourceLocation.parse("widget/button"), - ResourceLocation.parse("widget/button_disabled"), - ResourceLocation.parse("widget/button_highlighted") + ResourceLocation.parse("widget/button"), + ResourceLocation.parse("widget/button_disabled"), + ResourceLocation.parse("widget/button_highlighted") ); private final EnumValue value; @@ -43,11 +42,11 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float par RenderSystem.enableBlend(); RenderSystem.enableDepthTest(); graphics.blitSprite( - SPRITES.get(this.active, this.isHoveredOrFocused()), - this.getX(), - this.getY(), - this.getWidth(), - this.getHeight() + SPRITES.get(this.active, this.isHoveredOrFocused()), + this.getX(), + this.getY(), + this.getWidth(), + this.getHeight() ); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); this.renderString(graphics, minecraft.font, Mth.ceil(this.alpha * 255.0F) << 24); @@ -64,8 +63,7 @@ public void onClick(double p_230982_1_, double p_230982_3_) { } @Override - public void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) { - } + public void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) {} private void nextValue() { E e = this.value.get(); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/model/data/EntityModelData.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/model/data/EntityModelData.java index 3e2a7ee3d..06a0f02de 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/model/data/EntityModelData.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/model/data/EntityModelData.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.client.model.data; @@ -11,9 +9,8 @@ * Container class for various pieces of data relating to a model's current state. */ public record EntityModelData( - boolean isSitting, - boolean isChild, - float netHeadYaw, - float headPitch -) { -} + boolean isSitting, + boolean isChild, + float netHeadYaw, + float headPitch +) {} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java index 8d1844232..59a179e04 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java @@ -1,24 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.client.renderer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; -import mod.azure.azurelib.core.object.Color; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.OverlayTexture; @@ -31,12 +19,24 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; +import mod.azure.azurelib.core.object.Color; + /** * Base interface for all AzureLib renderers.
        * * @deprecated */ public interface GeoRenderer { + /** * Gets the model instance for this renderer */ @@ -63,11 +63,15 @@ default List> getRenderLayers() { /** * Gets the {@link RenderType} to render the given animatable with.
        - * Uses the {@link RenderType#entityCutoutNoCull} {@code RenderType} by default.
        + * Uses the {@link RenderType#entityCutoutNoCull} {@code RenderType} by default.
        * Override this to change the way a model will render (such as translucent models, etc) */ - default RenderType getRenderType(T animatable, ResourceLocation texture, - @Nullable MultiBufferSource bufferSource, float partialTick) { + default RenderType getRenderType( + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ) { return getGeoModel().getRenderType(animatable, texture); } @@ -81,17 +85,16 @@ default Color getRenderColor(T animatable, float partialTick, int packedLight) { /** * Gets a packed overlay coordinate pair for rendering.
        - * Mostly just used for the red tint when an entity is hurt, - * but can be used for other things like the {@link net.minecraft.world.entity.monster.Creeper} - * white tint when exploding. + * Mostly just used for the red tint when an entity is hurt, but can be used for other things like the + * {@link net.minecraft.world.entity.monster.Creeper} white tint when exploding. */ default int getPackedOverlay(T animatable, float u, float partialTick) { return OverlayTexture.NO_OVERLAY; } /** - * Gets the id that represents the current animatable's instance for animation purposes. - * This is mostly useful for things like items, which have a single registered instance for all objects + * Gets the id that represents the current animatable's instance for animation purposes. This is mostly useful for + * things like items, which have a single registered instance for all objects */ default long getInstanceId(T animatable) { return animatable.hashCode(); @@ -101,8 +104,8 @@ default long getInstanceId(T animatable) { * Determines the threshold value before the animatable should be considered moving for animation purposes.
        * The default value and usage for this varies depending on the renderer.
        *
          - *
        • For entities, it represents the averaged lateral velocity of the object.
        • - *
        • For {@link GeoBlockEntity Tile Entities} and {@link GeoItem Items}, it's currently unused
        • + *
        • For entities, it represents the averaged lateral velocity of the object.
        • + *
        • For {@link GeoBlockEntity Tile Entities} and {@link GeoItem Items}, it's currently unused
        • *
        * The lower the value, the more sensitive the {@link AnimationState#isMoving()} check will be.
        * Particularly low values may have adverse effects however @@ -113,10 +116,19 @@ default float getMotionAnimThreshold(T animatable) { /** * Initial access point for rendering. It all begins here.
        - * All AzureLib renderers should immediately defer their respective default {@code render} calls to this, for consistent handling + * All AzureLib renderers should immediately defer their respective default {@code render} calls to this, for + * consistent handling */ - default void defaultRender(PoseStack poseStack, T animatable, MultiBufferSource bufferSource, @Nullable RenderType renderType, @Nullable VertexConsumer buffer, - float yaw, float partialTick, int packedLight) { + default void defaultRender( + PoseStack poseStack, + T animatable, + MultiBufferSource bufferSource, + @Nullable RenderType renderType, + @Nullable VertexConsumer buffer, + float yaw, + float partialTick, + int packedLight + ) { poseStack.pushPose(); int renderColor = getRenderColor(animatable, partialTick, packedLight).argbInt(); @@ -129,131 +141,389 @@ default void defaultRender(PoseStack poseStack, T animatable, MultiBufferSource if (buffer == null) buffer = bufferSource.getBuffer(renderType); - preRender(poseStack, animatable, model, bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); + preRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + false, + partialTick, + packedLight, + packedOverlay, + renderColor + ); if (firePreRenderEvent(poseStack, model, bufferSource, partialTick, packedLight)) { - preApplyRenderLayers(poseStack, animatable, model, renderType, bufferSource, buffer, packedLight, packedLight, packedOverlay); - actuallyRender(poseStack, animatable, model, renderType, - bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); - applyRenderLayers(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); - postRender(poseStack, animatable, model, bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); + preApplyRenderLayers( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + packedLight, + packedLight, + packedOverlay + ); + actuallyRender( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + false, + partialTick, + packedLight, + packedOverlay, + renderColor + ); + applyRenderLayers( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); + postRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + false, + partialTick, + packedLight, + packedOverlay, + renderColor + ); firePostRenderEvent(poseStack, model, bufferSource, partialTick, packedLight); } poseStack.popPose(); - renderFinal(poseStack, animatable, model, bufferSource, buffer, partialTick, packedLight, packedOverlay, renderColor); + renderFinal( + poseStack, + animatable, + model, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + renderColor + ); doPostRenderCleanup(); } /** * Re-renders the provided {@link BakedGeoModel} using the existing {@link GeoRenderer}.
        - * Usually you'd use this for rendering alternate {@link RenderType} layers or for sub-model rendering whilst inside a {@link GeoRenderLayer} or similar + * Usually you'd use this for rendering alternate {@link RenderType} layers or for sub-model rendering whilst inside + * a {@link GeoRenderLayer} or similar */ - default void reRender(BakedGeoModel model, PoseStack poseStack, MultiBufferSource bufferSource, T animatable, - RenderType renderType, VertexConsumer buffer, float partialTick, - int packedLight, int packedOverlay, int colour) { + default void reRender( + BakedGeoModel model, + PoseStack poseStack, + MultiBufferSource bufferSource, + T animatable, + RenderType renderType, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { poseStack.pushPose(); - preRender(poseStack, animatable, model, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); - actuallyRender(poseStack, animatable, model, renderType, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); - postRender(poseStack, animatable, model, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); + preRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + true, + partialTick, + packedLight, + packedOverlay, + colour + ); + actuallyRender( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + true, + partialTick, + packedLight, + packedOverlay, + colour + ); + postRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + true, + partialTick, + packedLight, + packedOverlay, + colour + ); poseStack.popPose(); } /** * The actual render method that sub-type renderers should override to handle their specific rendering tasks.
        - * {@link GeoRenderer#preRender} has already been called by this stage, and {@link GeoRenderer#postRender} will be called directly after + * {@link GeoRenderer#preRender} has already been called by this stage, and {@link GeoRenderer#postRender} will be + * called directly after */ - default void actuallyRender(PoseStack poseStack, T animatable, BakedGeoModel model, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, - int packedLight, int packedOverlay, int colour) { + default void actuallyRender( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { updateAnimatedTextureFrame(animatable); for (GeoBone group : model.getTopLevelBones()) { - renderRecursively(poseStack, animatable, group, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, - packedOverlay, colour); + renderRecursively( + poseStack, + animatable, + group, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour + ); } } /** - * Calls back to the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer for their {@link GeoRenderLayer#preRender pre-render} actions. + * Calls back to the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer for + * their {@link GeoRenderLayer#preRender pre-render} actions. */ - default void preApplyRenderLayers(PoseStack poseStack, T animatable, BakedGeoModel model, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + default void preApplyRenderLayers( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) { for (GeoRenderLayer renderLayer : getRenderLayers()) { - renderLayer.preRender(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + renderLayer.preRender( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); } } /** - * Calls back to the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer for their {@link GeoRenderLayer#renderForBone per-bone} render actions. + * Calls back to the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer for + * their {@link GeoRenderLayer#renderForBone per-bone} render actions. */ - default void applyRenderLayersForBone(PoseStack poseStack, T animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + default void applyRenderLayersForBone( + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) { for (GeoRenderLayer renderLayer : getRenderLayers()) { - renderLayer.renderForBone(poseStack, animatable, bone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + renderLayer.renderForBone( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); } } /** * Render the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer */ - default void applyRenderLayers(PoseStack poseStack, T animatable, BakedGeoModel model, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + default void applyRenderLayers( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) { for (GeoRenderLayer renderLayer : getRenderLayers()) { - renderLayer.render(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + renderLayer.render( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); } } /** - * Called before rendering the model to buffer. Allows for render modifications and preparatory - * work such as scaling and translating.
        + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
        * {@link PoseStack} translations made here are kept until the end of the render process */ - default void preRender(PoseStack poseStack, T animatable, BakedGeoModel model, @Nullable MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, - int packedOverlay, int colour) {} + default void preRender( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + @Nullable MultiBufferSource bufferSource, + @Nullable VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) {} /** * Called after rendering the model to buffer. Post-render modifications should be performed here.
        * {@link PoseStack} transformations will be unused and lost once this method ends */ - default void postRender(PoseStack poseStack, T animatable, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {} + default void postRender( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) {} /** - * Call after all other rendering work has taken place, including reverting the {@link PoseStack}'s state. This method is not called in {@link GeoRenderer#reRender re-render} + * Call after all other rendering work has taken place, including reverting the {@link PoseStack}'s state. This + * method is not called in {@link GeoRenderer#reRender re-render} */ - default void renderFinal(PoseStack poseStack, T animatable, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, - int packedOverlay, int colour) {} + default void renderFinal( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) {} /** * Called after all render operations are completed and the render pass is considered functionally complete. *

        - * Use this method to clean up any leftover persistent objects stored during rendering or any other post-render maintenance tasks as required + * Use this method to clean up any leftover persistent objects stored during rendering or any other post-render + * maintenance tasks as required */ default void doPostRenderCleanup() {} /** * Renders the provided {@link GeoBone} and its associated child bones */ - default void renderRecursively(PoseStack poseStack, T animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, - int packedOverlay, int colour) { + default void renderRecursively( + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { poseStack.pushPose(); RenderUtils.prepMatrixForBone(poseStack, bone); renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (!isReRender) - applyRenderLayersForBone(poseStack, getAnimatable(), bone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); - - renderChildBones(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour); + applyRenderLayersForBone( + poseStack, + getAnimatable(), + bone, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); + + renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour + ); poseStack.popPose(); } /** * Renders the {@link GeoCube GeoCubes} associated with a given {@link GeoBone} */ - default void renderCubesOfBone(PoseStack poseStack, GeoBone bone, VertexConsumer buffer, int packedLight, - int packedOverlay, int colour) { + default void renderCubesOfBone( + PoseStack poseStack, + GeoBone bone, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour + ) { if (bone.isHidden()) return; @@ -266,15 +536,39 @@ default void renderCubesOfBone(PoseStack poseStack, GeoBone bone, VertexConsumer /** * Render the child bones of a given {@link GeoBone}.
        - * Note that this does not render the bone itself. That should be done through {@link GeoRenderer#renderCubesOfBone} separately + * Note that this does not render the bone itself. That should be done through {@link GeoRenderer#renderCubesOfBone} + * separately */ - default void renderChildBones(PoseStack poseStack, T animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, - boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) { + default void renderChildBones( + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { if (bone.isHidingChildren()) return; for (GeoBone childBone : bone.getChildBones()) { - renderRecursively(poseStack, animatable, childBone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour); + renderRecursively( + poseStack, + animatable, + childBone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour + ); } } @@ -282,8 +576,14 @@ default void renderChildBones(PoseStack poseStack, T animatable, GeoBone bone, R * Renders an individual {@link GeoCube}.
        * This tends to be called recursively from something like {@link GeoRenderer#renderCubesOfBone} */ - default void renderCube(PoseStack poseStack, GeoCube cube, VertexConsumer buffer, int packedLight, - int packedOverlay, int colour) { + default void renderCube( + PoseStack poseStack, + GeoCube cube, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour + ) { RenderUtils.translateToPivotPoint(poseStack, cube); RenderUtils.rotateMatrixAroundCube(poseStack, cube); RenderUtils.translateAwayFromPivotPoint(poseStack, cube); @@ -303,16 +603,35 @@ default void renderCube(PoseStack poseStack, GeoCube cube, VertexConsumer buffer } /** - * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for rendering + * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for + * rendering */ - default void createVerticesOfQuad(GeoQuad quad, Matrix4f poseState, Vector3f normal, VertexConsumer buffer, - int packedLight, int packedOverlay, int colour) { + default void createVerticesOfQuad( + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour + ) { for (GeoVertex vertex : quad.vertices()) { Vector3f position = vertex.position(); Vector4f vector4f = poseState.transform(new Vector4f(position.x(), position.y(), position.z(), 1.0f)); - buffer.addVertex(vector4f.x(), vector4f.y(), vector4f.z(), colour, vertex.texU(), - vertex.texV(), packedOverlay, packedLight, normal.x(), normal.y(), normal.z()); + buffer.addVertex( + vector4f.x(), + vector4f.y(), + vector4f.z(), + colour, + vertex.texU(), + vertex.texV(), + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() + ); } } @@ -323,28 +642,55 @@ default void createVerticesOfQuad(GeoQuad quad, Matrix4f poseState, Vector3f nor /** * Create and fire the relevant {@code Pre-Render} event hook for this renderer.
        + * * @return Whether the renderer should proceed based on the cancellation state of the event */ - boolean firePreRenderEvent(PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean firePreRenderEvent( + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Create and fire the relevant {@code Post-Render} event hook for this renderer */ - void firePostRenderEvent(PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void firePostRenderEvent( + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** - * Scales the {@link PoseStack} in preparation for rendering the model, excluding when re-rendering the model as part of a {@link GeoRenderLayer} or external render call.
        - * Override and call super with modified scale values as needed to further modify the scale of the model (E.G. child entities) + * Scales the {@link PoseStack} in preparation for rendering the model, excluding when re-rendering the model as + * part of a {@link GeoRenderLayer} or external render call.
        + * Override and call super with modified scale values as needed to further modify the scale of the model (E.G. child + * entities) */ - default void scaleModelForRender(float widthScale, float heightScale, PoseStack poseStack, T animatable, BakedGeoModel model, boolean isReRender, float partialTick, int packedLight, int packedOverlay) { + default void scaleModelForRender( + float widthScale, + float heightScale, + PoseStack poseStack, + T animatable, + BakedGeoModel model, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay + ) { if (!isReRender && (widthScale != 1 || heightScale != 1)) poseStack.scale(widthScale, heightScale, widthScale); } /** - * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this GeoRenderer.
        + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
        * This should only be called immediately prior to rendering, and only + * * @see AnimatableTexture#setAndUpdate */ void updateAnimatedTextureFrame(T animatable); -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java index db8446df9..d9b24ffba 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java @@ -1,10 +1,8 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ - package mod.azure.azurelib.common.internal.client.util; +package mod.azure.azurelib.common.internal.client.util; import com.mojang.blaze3d.Blaze3D; import com.mojang.blaze3d.platform.NativeImage; @@ -12,16 +10,6 @@ import com.mojang.math.Axis; import it.unimi.dsi.fastutil.ints.IntIntImmutablePair; import it.unimi.dsi.fastutil.ints.IntIntPair; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.api.client.renderer.GeoReplacedEntityRenderer; -import mod.azure.azurelib.common.internal.client.RenderProvider; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; -import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import net.minecraft.client.Minecraft; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; @@ -42,6 +30,17 @@ import org.joml.Quaternionf; import org.joml.Vector3f; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.api.client.renderer.GeoReplacedEntityRenderer; +import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; + /** * Helper class for various methods and functions useful while rendering */ @@ -161,8 +160,8 @@ public static IntIntPair getTextureDimensions(ResourceLocation texture) { try { image = originalTexture instanceof DynamicTexture dynamicTexture - ? dynamicTexture.getPixels() - : NativeImage.read(mc.getResourceManager().getResource(texture).get().open()); + ? dynamicTexture.getPixels() + : NativeImage.read(mc.getResourceManager().getResource(texture).get().open()); } catch (Exception e) { AzureLib.LOGGER.error("Failed to read image for id {}", texture); e.printStackTrace(); @@ -265,8 +264,8 @@ public static GeoAnimatable getReplacedAnimatable(EntityType entityType) { EntityRenderer renderer = Minecraft.getInstance().getEntityRenderDispatcher().renderers.get(entityType); return renderer instanceof GeoReplacedEntityRenderer replacedEntityRenderer - ? replacedEntityRenderer.getAnimatable() - : null; + ? replacedEntityRenderer.getAnimatable() + : null; } /** @@ -314,8 +313,8 @@ public static GeoModel getGeoModelForItem(Item item) { @Nullable public static GeoModel getGeoModelForBlock(BlockEntity blockEntity) { BlockEntityRenderer renderer = Minecraft.getInstance() - .getBlockEntityRenderDispatcher() - .getRenderer(blockEntity); + .getBlockEntityRenderDispatcher() + .getRenderer(blockEntity); return renderer instanceof GeoRenderer geoRenderer ? geoRenderer.getGeoModel() : null; } @@ -332,8 +331,8 @@ public static GeoModel getGeoModelForBlock(BlockEntity blockEntity) { @Nullable public static GeoModel getGeoModelForArmor(ItemStack stack) { if ( - RenderProvider.of(stack) - .getHumanoidArmorModel(null, stack, null, null) instanceof GeoArmorRenderer armorRenderer + RenderProvider.of(stack) + .getHumanoidArmorModel(null, stack, null, null) instanceof GeoArmorRenderer armorRenderer ) return armorRenderer.getGeoModel(); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java index 34809e035..b869debf2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java @@ -1,8 +1,6 @@ package mod.azure.azurelib.common.internal.common; import com.mojang.serialization.Codec; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.core.component.DataComponentType; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.resources.ResourceLocation; @@ -13,6 +11,9 @@ import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.common.platform.Services; + /** * Base class for AzureLib!
        * Hello World!
        @@ -27,10 +28,18 @@ public final class AzureLib { public static final Logger LOGGER = LogManager.getLogger(MOD_ID); public static final Marker MAIN_MARKER = MarkerManager.getMarker("main"); - public static final Supplier> STACK_ANIMATABLE_ID_COMPONENT = Services.PLATFORM.registerDataComponent( - "stack_animatable_id", builder -> builder.persistent(Codec.LONG).networkSynchronized( - ByteBufCodecs.VAR_LONG)); + + public static final Supplier> STACK_ANIMATABLE_ID_COMPONENT = Services.PLATFORM + .registerDataComponent( + "stack_animatable_id", + builder -> builder.persistent(Codec.LONG) + .networkSynchronized( + ByteBufCodecs.VAR_LONG + ) + ); + public static boolean hasInitialized; + public static boolean hasKeyBindsInitialized; private AzureLib() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLibMod.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLibMod.java index c93a2720f..15a86d4a0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLibMod.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLibMod.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common; @@ -37,7 +35,7 @@ public static void initRegistry() { * for example. * @param Config type * @return Config holder containing your config instance. You obtain it by calling - * {@link ConfigHolder#getConfigInstance()} method. + * {@link ConfigHolder#getConfigInstance()} method. */ public static ConfigHolder registerConfig(Class configClass, IConfigFormatHandler formatFactory) { var config = configClass.getAnnotation(Config.class); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/ai/pathing/AzurePathFinder.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/ai/pathing/AzurePathFinder.java index 27a2a7ce6..e487cbfe7 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/ai/pathing/AzurePathFinder.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/ai/pathing/AzurePathFinder.java @@ -26,12 +26,12 @@ public AzurePathFinder(NodeEvaluator processor, int maxVisitedNodes) { @Nullable @Override public Path findPath( - @NotNull PathNavigationRegion regionIn, - @NotNull Mob mob, - @NotNull Set targetPositions, - float maxRange, - int accuracy, - float searchDepthMultiplier + @NotNull PathNavigationRegion regionIn, + @NotNull Mob mob, + @NotNull Set targetPositions, + float maxRange, + int accuracy, + float searchDepthMultiplier ) { Path path = super.findPath(regionIn, mob, targetPositions, maxRange, accuracy, searchDepthMultiplier); return path == null ? null : new PatchedPath(path); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java index bb18cb799..4a57252b1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java @@ -1,12 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.animatable; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Supplier; + import mod.azure.azurelib.common.internal.client.RenderProvider; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; import mod.azure.azurelib.common.internal.common.network.packet.AnimDataSyncPacket; @@ -18,11 +22,6 @@ import mod.azure.azurelib.core.animatable.instance.SingletonAnimatableInstanceCache; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.AnimationController; -import net.minecraft.world.entity.Entity; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; -import java.util.function.Supplier; /** * The {@link GeoAnimatable} interface specific to singleton objects. This primarily applies to armor and items @@ -79,8 +78,8 @@ default void setAnimData(Entity relatedEntity, long instanceId, Serializable */ default void syncAnimData(long instanceId, SerializableDataTicket dataTicket, D data, Entity entityToTrack) { Services.NETWORK.sendToTrackingEntityAndSelf( - new AnimDataSyncPacket<>(getClass().toString(), instanceId, dataTicket, data), - entityToTrack + new AnimDataSyncPacket<>(getClass().toString(), instanceId, dataTicket, data), + entityToTrack ); } @@ -102,8 +101,8 @@ default void triggerAnim(Entity relatedEntity, long instanceId, @Nullable String getAnimatableInstanceCache().getManagerForId(instanceId).tryTriggerAnimation(controllerName, animName); } else { Services.NETWORK.sendToTrackingEntityAndSelf( - new AnimTriggerPacket(getClass().toString(), instanceId, controllerName, animName), - relatedEntity + new AnimTriggerPacket(getClass().toString(), instanceId, controllerName, animName), + relatedEntity ); } } @@ -122,14 +121,14 @@ default void triggerAnim(Entity relatedEntity, long instanceId, @Nullable String * @param packetCallback The packet callback. Used to call a custom network code */ default void triggerAnim( - long instanceId, - @Nullable String controllerName, - String animName, - AzureLibNetwork.IPacketCallback packetCallback + long instanceId, + @Nullable String controllerName, + String animName, + AzureLibNetwork.IPacketCallback packetCallback ) { AzureLibNetwork.sendWithCallback( - new AnimTriggerPacket(getClass().toString(), instanceId, controllerName, animName), - packetCallback + new AnimTriggerPacket(getClass().toString(), instanceId, controllerName, animName), + packetCallback ); } @@ -149,12 +148,12 @@ default void triggerAnim( * *

              * {@code
        -     * @Override
        +     * @Override
              * public void createRenderer(Consumer consumer) {
              * 	consumer.accept(new RenderProvider() {
              * 		private final GeoArmorRenderer renderer = new MyArmorRenderer();
              *
        -     *        @Override
        +     *        @Override
              *        GeoArmorRenderer getRenderer(GeoArmor armor) {
              * 			return this.renderer;
              *        }
        @@ -164,7 +163,7 @@ default void triggerAnim(
              * 
        * * @param consumer a {@link java.util.function.Consumer} that accepts a {@link RenderProvider} - * */ + */ void createRenderer(Consumer consumer); /** diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightBlock.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightBlock.java index 7bf4f3593..eadd076b3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightBlock.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightBlock.java @@ -1,8 +1,6 @@ package mod.azure.azurelib.common.internal.common.blocks; import com.mojang.serialization.MapCodec; -import mod.azure.azurelib.common.internal.common.registry.AzureBlocksEntityRegistry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.core.BlockPos; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; @@ -24,6 +22,8 @@ import java.util.function.ToIntFunction; +import mod.azure.azurelib.common.internal.common.registry.AzureBlocksEntityRegistry; + public class TickingLightBlock extends BaseEntityBlock { public static final MapCodec CODEC = simpleCodec(TickingLightBlock::new); @@ -54,16 +54,20 @@ public BlockEntity newBlockEntity(@NotNull BlockPos pos, @NotNull BlockState sta @Override public @NotNull VoxelShape getShape( - @NotNull BlockState blockState, - @NotNull BlockGetter blockGetter, - @NotNull BlockPos blockPos, - @NotNull CollisionContext collisionContext + @NotNull BlockState blockState, + @NotNull BlockGetter blockGetter, + @NotNull BlockPos blockPos, + @NotNull CollisionContext collisionContext ) { return Shapes.empty(); } @Override - public boolean propagatesSkylightDown(@NotNull BlockState state, @NotNull BlockGetter world, @NotNull BlockPos pos) { + public boolean propagatesSkylightDown( + @NotNull BlockState state, + @NotNull BlockGetter world, + @NotNull BlockPos pos + ) { return true; } @@ -79,9 +83,9 @@ public boolean propagatesSkylightDown(@NotNull BlockState state, @NotNull BlockG @Override public BlockEntityTicker getTicker( - Level world, - BlockState state, - BlockEntityType type + Level world, + BlockState state, + BlockEntityType type ) { return createTickerHelper(type, AzureBlocksEntityRegistry.TICKING_LIGHT_ENTITY.get(), TickingLightEntity::tick); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightEntity.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightEntity.java index 568d99c25..5f75f7942 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightEntity.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightEntity.java @@ -1,13 +1,13 @@ package mod.azure.azurelib.common.internal.common.blocks; -import mod.azure.azurelib.common.internal.common.registry.AzureBlocksEntityRegistry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import mod.azure.azurelib.common.internal.common.registry.AzureBlocksEntityRegistry; + public class TickingLightEntity extends BlockEntity { private int lifespan = 0; @@ -17,10 +17,10 @@ public TickingLightEntity(BlockPos blockPos, BlockState blockState) { } public static void tick( - Level world, - BlockPos blockPos, - BlockState blockState, - TickingLightEntity blockEntity + Level world, + BlockPos blockPos, + BlockState blockState, + TickingLightEntity blockEntity ) { blockEntity.tick(); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java index 7443f81b7..ca6a6066a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java @@ -1,19 +1,18 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache; -import mod.azure.azurelib.core.animatable.instance.SingletonAnimatableInstanceCache; import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.saveddata.SavedData; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.core.animatable.instance.SingletonAnimatableInstanceCache; + /** * Storage class that keeps track of the last animatable id used, and provides new ones on request.
        * Generally only used for {@link net.minecraft.world.item.Item Items}, but any {@link SingletonAnimatableInstanceCache @@ -25,8 +24,7 @@ public final class AnimatableIdCache extends SavedData { private long lastId; - private AnimatableIdCache() { - } + private AnimatableIdCache() {} private AnimatableIdCache(CompoundTag tag, HolderLookup.Provider registryLookup) { this.lastId = tag.getLong("last_id"); @@ -34,9 +32,9 @@ private AnimatableIdCache(CompoundTag tag, HolderLookup.Provider registryLookup) public static SavedData.Factory factory() { return new SavedData.Factory<>( - AnimatableIdCache::new, - AnimatableIdCache::new, - null + AnimatableIdCache::new, + AnimatableIdCache::new, + null ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java index 170b50273..8182ac74d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java @@ -1,26 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.AzureLibException; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.loading.FileLoader; -import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; -import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; -import mod.azure.azurelib.common.internal.common.loading.object.BakedModelFactory; -import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; -import mod.azure.azurelib.core.animatable.model.CoreGeoModel; -import mod.azure.azurelib.core.animation.Animation; -import mod.azure.azurelib.core2.animation.cache.AzBakedAnimationCache; -import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.PreparableReloadListener.PreparationBarrier; @@ -38,6 +24,19 @@ import java.util.function.BiConsumer; import java.util.function.Function; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.AzureLibException; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.loading.FileLoader; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; +import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; +import mod.azure.azurelib.common.internal.common.loading.object.BakedModelFactory; +import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; +import mod.azure.azurelib.core.animatable.model.CoreGeoModel; +import mod.azure.azurelib.core.animation.Animation; +import mod.azure.azurelib.core2.animation.cache.AzBakedAnimationCache; +import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; + /** * Cache class for holding loaded {@link Animation Animations} and {@link CoreGeoModel Models} * @@ -49,13 +48,13 @@ public final class AzureLibCache { * @deprecated */ private static final Set EXCLUDED_NAMESPACES = ObjectOpenHashSet.of( - "moreplayermodels", - "customnpcs", - "creeperoverhaul", - "geckolib", - "gunsrpg", - "born_in_chaos_v1", - "neoforge" + "moreplayermodels", + "customnpcs", + "creeperoverhaul", + "geckolib", + "gunsrpg", + "born_in_chaos_v1", + "neoforge" ); /** @@ -107,47 +106,47 @@ public static void registerReloadListener() { } public static CompletableFuture reload( - PreparationBarrier stage, - ResourceManager resourceManager, - ProfilerFiller preparationsProfiler, - ProfilerFiller reloadProfiler, - Executor backgroundExecutor, - Executor gameExecutor + PreparationBarrier stage, + ResourceManager resourceManager, + ProfilerFiller preparationsProfiler, + ProfilerFiller reloadProfiler, + Executor backgroundExecutor, + Executor gameExecutor ) { // TODO: Remove these. Map animations = new Object2ObjectOpenHashMap<>(); Map models = new Object2ObjectOpenHashMap<>(); return CompletableFuture - .allOf( - // TODO: Remove these. - loadAnimations(backgroundExecutor, resourceManager, animations::put), - loadModels(backgroundExecutor, resourceManager, models::put), - // Forward-support for new cache components - AzBakedAnimationCache.getInstance().loadAnimations(backgroundExecutor, resourceManager), - AzBakedModelCache.getInstance().loadModels(backgroundExecutor, resourceManager) - ) - .thenCompose(stage::wait) - .thenAcceptAsync(empty -> { - AzureLibCache.ANIMATIONS = animations; - AzureLibCache.MODELS = models; - }, gameExecutor); + .allOf( + // TODO: Remove these. + loadAnimations(backgroundExecutor, resourceManager, animations::put), + loadModels(backgroundExecutor, resourceManager, models::put), + // Forward-support for new cache components + AzBakedAnimationCache.getInstance().loadAnimations(backgroundExecutor, resourceManager), + AzBakedModelCache.getInstance().loadModels(backgroundExecutor, resourceManager) + ) + .thenCompose(stage::wait) + .thenAcceptAsync(empty -> { + AzureLibCache.ANIMATIONS = animations; + AzureLibCache.MODELS = models; + }, gameExecutor); } /** * @deprecated */ private static CompletableFuture loadAnimations( - Executor backgroundExecutor, - ResourceManager resourceManager, - BiConsumer elementConsumer + Executor backgroundExecutor, + ResourceManager resourceManager, + BiConsumer elementConsumer ) { return loadResources( - backgroundExecutor, - resourceManager, - "animations", - resource -> FileLoader.loadAnimationsFile(resource, resourceManager), - elementConsumer + backgroundExecutor, + resourceManager, + "animations", + resource -> FileLoader.loadAnimationsFile(resource, resourceManager), + elementConsumer ); } @@ -155,15 +154,15 @@ private static CompletableFuture loadAnimations( * @deprecated */ private static CompletableFuture loadModels( - Executor backgroundExecutor, - ResourceManager resourceManager, - BiConsumer elementConsumer + Executor backgroundExecutor, + ResourceManager resourceManager, + BiConsumer elementConsumer ) { return loadResources(backgroundExecutor, resourceManager, "geo", resource -> { Model model = FileLoader.loadModelFile(resource, resourceManager); return BakedModelFactory.getForNamespace(resource.getNamespace()) - .constructGeoModel(GeometryTree.fromModel(model)); + .constructGeoModel(GeometryTree.fromModel(model)); }, elementConsumer); } @@ -171,30 +170,30 @@ private static CompletableFuture loadModels( * @deprecated */ private static CompletableFuture loadResources( - Executor executor, - ResourceManager resourceManager, - String type, - Function loader, - BiConsumer map + Executor executor, + ResourceManager resourceManager, + String type, + Function loader, + BiConsumer map ) { return CompletableFuture.supplyAsync( () -> resourceManager.listResources(type, fileName -> fileName.toString().endsWith(".json")), executor ) - .thenApplyAsync(resources -> { - Map> tasks = new Object2ObjectOpenHashMap<>(); - - for (ResourceLocation resource : resources.keySet()) { - tasks.put(resource, CompletableFuture.supplyAsync(() -> loader.apply(resource), executor)); - } - - return tasks; - }, executor) - .thenAcceptAsync(tasks -> { - for (Entry> entry : tasks.entrySet()) { - if (!EXCLUDED_NAMESPACES.contains(entry.getKey().getNamespace().toLowerCase(Locale.ROOT))) - map.accept(entry.getKey(), entry.getValue().join()); - } - }, executor); + .thenApplyAsync(resources -> { + Map> tasks = new Object2ObjectOpenHashMap<>(); + + for (ResourceLocation resource : resources.keySet()) { + tasks.put(resource, CompletableFuture.supplyAsync(() -> loader.apply(resource), executor)); + } + + return tasks; + }, executor) + .thenAcceptAsync(tasks -> { + for (Entry> entry : tasks.entrySet()) { + if (!EXCLUDED_NAMESPACES.contains(entry.getKey().getNamespace().toLowerCase(Locale.ROOT))) + map.accept(entry.getKey(), entry.getValue().join()); + } + }, executor); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java index 4c74ef6a5..0e29386f1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java @@ -1,20 +1,18 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.object; -import mod.azure.azurelib.core.animatable.model.CoreBakedGeoModel; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; - import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import mod.azure.azurelib.core.animatable.model.CoreBakedGeoModel; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; + /** * Baked model object for AzureLib models. * diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java index 4df47dba2..47f4f07cd 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java @@ -1,15 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.object; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; -import mod.azure.azurelib.core.state.BoneSnapshot; import org.jetbrains.annotations.Nullable; import org.joml.Matrix3f; import org.joml.Matrix4f; @@ -19,6 +15,9 @@ import java.util.List; import java.util.Objects; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.state.BoneSnapshot; + /** * Mutable bone object representing a set of cubes, as well as child bones.
        * This is the object that is directly modified by animations to handle movement @@ -40,38 +39,60 @@ public class GeoBone implements CoreGeoBone { private final Boolean dontRender; private final Boolean reset; + private final Matrix4f modelSpaceMatrix = new Matrix4f(); + private final Matrix4f localSpaceMatrix = new Matrix4f(); + private final Matrix4f worldSpaceMatrix = new Matrix4f(); + private BoneSnapshot initialSnapshot; + private boolean hidden; + private boolean childrenHidden = false; + private float scaleX = 1; + private float scaleY = 1; + private float scaleZ = 1; + private float positionX; + private float positionY; + private float positionZ; + private float pivotX; + private float pivotY; + private float pivotZ; + private float rotX; + private float rotY; + private float rotZ; + private boolean positionChanged = false; + private boolean rotationChanged = false; + private boolean scaleChanged = false; + private Matrix3f worldSpaceNormal = new Matrix3f(); private boolean trackingMatrices; public GeoBone( - @Nullable GeoBone parent, - String name, - Boolean mirror, - @Nullable Double inflate, - @Nullable Boolean dontRender, - @Nullable Boolean reset + @Nullable GeoBone parent, + String name, + Boolean mirror, + @Nullable Double inflate, + @Nullable Boolean dontRender, + @Nullable Boolean reset ) { this.parent = parent; this.name = name; @@ -399,9 +420,9 @@ public void setModelPosition(Vector3d pos) { // Doesn't work on bones with parent transforms GeoBone parent = getParent(); Matrix4f matrix = (parent == null ? new Matrix4f().identity() : new Matrix4f(parent.getModelSpaceMatrix())) - .invert(); + .invert(); Vector4f vec = matrix.transform( - new Vector4f(-(float) pos.x / 16f, (float) pos.y / 16f, (float) pos.z / 16f, 1) + new Vector4f(-(float) pos.x / 16f, (float) pos.y / 16f, (float) pos.z / 16f, 1) ); updatePosition(-vec.x() * 16f, vec.y() * 16f, vec.z() * 16f); @@ -457,10 +478,10 @@ public boolean equals(Object obj) { @Override public int hashCode() { return Objects.hash( - getName(), - (getParent() != null ? getParent().getName() : 0), - getCubes().size(), - getChildBones().size() + getName(), + (getParent() != null ? getParent().getName() : 0), + getCubes().size(), + getChildBones().size() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java index 5e33092a9..2ca7c7663 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.object; @@ -13,11 +11,10 @@ * Baked cuboid for a {@link GeoBone} */ public record GeoCube( - GeoQuad[] quads, - Vec3 pivot, - Vec3 rotation, - Vec3 size, - double inflate, - boolean mirror -) { -} + GeoQuad[] quads, + Vec3 pivot, + Vec3 rotation, + Vec3 size, + double inflate, + boolean mirror +) {} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java index 0d65f4425..b49294489 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.object; @@ -14,43 +12,43 @@ * Quad data holder */ public record GeoQuad( - GeoVertex[] vertices, - Vector3f normal, - Direction direction + GeoVertex[] vertices, + Vector3f normal, + Direction direction ) { public static GeoQuad build( - GeoVertex[] vertices, - double[] uvCoords, - double[] uvSize, - float texWidth, - float texHeight, - boolean mirror, - Direction direction + GeoVertex[] vertices, + double[] uvCoords, + double[] uvSize, + float texWidth, + float texHeight, + boolean mirror, + Direction direction ) { return build( - vertices, - (float) uvCoords[0], - (float) uvCoords[1], - (float) uvSize[0], - (float) uvSize[1], - texWidth, - texHeight, - mirror, - direction + vertices, + (float) uvCoords[0], + (float) uvCoords[1], + (float) uvSize[0], + (float) uvSize[1], + texWidth, + texHeight, + mirror, + direction ); } public static GeoQuad build( - GeoVertex[] vertices, - float u, - float v, - float uSize, - float vSize, - float texWidth, - float texHeight, - boolean mirror, - Direction direction + GeoVertex[] vertices, + float u, + float v, + float uSize, + float vSize, + float texWidth, + float texHeight, + boolean mirror, + Direction direction ) { float uWidth = (u + uSize) / texWidth; float vHeight = (v + vSize) / texHeight; @@ -62,8 +60,7 @@ public static GeoQuad build( float tempWidth = uWidth; uWidth = u; u = tempWidth; - } - else { + } else { normal.mul(-1, 1, 1); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java index 0bf942552..627f369ec 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.object; @@ -17,9 +15,9 @@ * @param texV The texture V coordinate */ public record GeoVertex( - Vector3f position, - float texU, - float texV + Vector3f position, + float texU, + float texV ) { public GeoVertex(double x, double y, double z) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java index d7d0d9ce9..9c636f4a3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.texture; @@ -14,17 +12,14 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.internal.common.AzureLib; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.SimpleTexture; import net.minecraft.client.resources.metadata.animation.AnimationMetadataSection; import net.minecraft.client.resources.metadata.animation.FrameSize; -import net.minecraft.client.resources.metadata.texture.TextureMetadataSection; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.server.packs.resources.ResourceMetadata; import net.minecraft.util.Mth; import java.io.IOException; @@ -32,12 +27,15 @@ import java.util.Arrays; import java.util.List; +import mod.azure.azurelib.common.internal.common.AzureLib; + /** * Wrapper for {@link SimpleTexture SimpleTexture} implementation allowing for casual use of animated non-atlas textures */ public class AnimatableTexture extends SimpleTexture { private AnimationContents animationContents = null; + private boolean isAnimated = false; public AnimatableTexture(final ResourceLocation location) { @@ -72,7 +70,10 @@ public void load(ResourceManager manager) throws IOException { nativeImage = NativeImage.read(inputstream); } - this.animationContents = resource.metadata().getSection(AnimationMetadataSection.SERIALIZER).map(animMeta -> new AnimationContents(nativeImage, animMeta)).orElse(null); + this.animationContents = resource.metadata() + .getSection(AnimationMetadataSection.SERIALIZER) + .map(animMeta -> new AnimationContents(nativeImage, animMeta)) + .orElse(null); if (this.animationContents != null) { if (!this.animationContents.isValid()) { @@ -84,12 +85,26 @@ public void load(ResourceManager manager) throws IOException { this.isAnimated = true; onRenderThread(() -> { - TextureUtil.prepareImage(getId(), 0, this.animationContents.frameSize.width(), this.animationContents.frameSize.height()); - nativeImage.upload(0, 0, 0, 0, 0, this.animationContents.frameSize.width(), this.animationContents.frameSize.height(), false, false); + TextureUtil.prepareImage( + getId(), + 0, + this.animationContents.frameSize.width(), + this.animationContents.frameSize.height() + ); + nativeImage.upload( + 0, + 0, + 0, + 0, + 0, + this.animationContents.frameSize.width(), + this.animationContents.frameSize.height(), + false, + false + ); }); } - } - catch (RuntimeException exception) { + } catch (RuntimeException exception) { AzureLib.LOGGER.warn("Failed reading metadata of: {}", this.location, exception); } } @@ -125,18 +140,18 @@ private boolean isValid() { private Texture generateAnimatedTexture(NativeImage image, AnimationMetadataSection animMeta) { if ( - !Mth.isMultipleOf(image.getWidth(), this.frameSize.width()) || !Mth.isMultipleOf( - image.getHeight(), - this.frameSize.height() - ) + !Mth.isMultipleOf(image.getWidth(), this.frameSize.width()) || !Mth.isMultipleOf( + image.getHeight(), + this.frameSize.height() + ) ) { AzureLib.LOGGER.error( - "Image {} size {},{} is not multiple of frame size {},{}", - AnimatableTexture.this.location, - image.getWidth(), - image.getHeight(), - this.frameSize.width(), - this.frameSize.height() + "Image {} size {},{} is not multiple of frame size {},{}", + AnimatableTexture.this.location, + image.getWidth(), + image.getHeight(), + this.frameSize.width(), + this.frameSize.height() ); return null; @@ -160,18 +175,18 @@ private Texture generateAnimatedTexture(NativeImage image, AnimationMetadataSect for (Frame frame : frames) { if (frame.time <= 0) { AzureLib.LOGGER.warn( - "Invalid frame duration on sprite {} frame {}: {}", - AnimatableTexture.this.location, - index, - frame.time + "Invalid frame duration on sprite {} frame {}: {}", + AnimatableTexture.this.location, + index, + frame.time ); unusedFrames.add(frame.index); } else if (frame.index < 0 || frame.index >= frameCount) { AzureLib.LOGGER.warn( - "Invalid frame index on sprite {} frame {}: {}", - AnimatableTexture.this.location, - index, - frame.index + "Invalid frame index on sprite {} frame {}: {}", + AnimatableTexture.this.location, + index, + frame.index ); unusedFrames.add(frame.index); } @@ -181,22 +196,21 @@ private Texture generateAnimatedTexture(NativeImage image, AnimationMetadataSect if (!unusedFrames.isEmpty()) AzureLib.LOGGER.warn( - "Unused frames in sprite {}: {}", - AnimatableTexture.this.location, - Arrays.toString(unusedFrames.toArray()) + "Unused frames in sprite {}: {}", + AnimatableTexture.this.location, + Arrays.toString(unusedFrames.toArray()) ); } return frames.size() <= 1 - ? null - : new Texture(image, frames.toArray(new Frame[0]), columns, animMeta.isInterpolatedFrames()); + ? null + : new Texture(image, frames.toArray(new Frame[0]), columns, animMeta.isInterpolatedFrames()); } private record Frame( - int index, - int time - ) { - } + int index, + int time + ) {} private class Texture implements AutoCloseable { @@ -222,12 +236,12 @@ private Texture(NativeImage baseImage, Frame[] frames, int framePanelSize, boole this.framePanelSize = framePanelSize; this.interpolating = interpolating; this.interpolatedFrame = interpolating - ? new NativeImage( + ? new NativeImage( AnimationContents.this.frameSize.width(), AnimationContents.this.frameSize.height(), false - ) - : null; + ) + : null; int time = 0; for (Frame frame : this.frames) { @@ -269,21 +283,21 @@ public void setCurrentFrame(int ticks) { if (this.currentFrame != lastFrame && this.currentSubframe == 0) { onRenderThread(() -> { TextureUtil.prepareImage( - AnimatableTexture.this.getId(), - 0, - AnimationContents.this.frameSize.width(), - AnimationContents.this.frameSize.height() + AnimatableTexture.this.getId(), + 0, + AnimationContents.this.frameSize.width(), + AnimationContents.this.frameSize.height() ); this.baseImage.upload( - 0, - 0, - 0, - getFrameX(this.currentFrame) * AnimationContents.this.frameSize.width(), - getFrameY(this.currentFrame) * AnimationContents.this.frameSize.height(), - AnimationContents.this.frameSize.width(), - AnimationContents.this.frameSize.height(), - false, - false + 0, + 0, + 0, + getFrameX(this.currentFrame) * AnimationContents.this.frameSize.width(), + getFrameY(this.currentFrame) * AnimationContents.this.frameSize.height(), + AnimationContents.this.frameSize.width(), + AnimationContents.this.frameSize.height(), + false, + false ); }); } else if (this.currentSubframe != lastSubframe && this.interpolating) { @@ -302,49 +316,49 @@ private void generateInterpolatedFrame() { int prevFramePixel = getPixel(frame.index, x, y); int nextFramePixel = getPixel(nextFrameIndex, x, y); int blendedRed = interpolate( - frameProgress, - prevFramePixel >> 16 & 255, - nextFramePixel >> 16 & 255 + frameProgress, + prevFramePixel >> 16 & 255, + nextFramePixel >> 16 & 255 ); int blendedGreen = interpolate( - frameProgress, - prevFramePixel >> 8 & 255, - nextFramePixel >> 8 & 255 + frameProgress, + prevFramePixel >> 8 & 255, + nextFramePixel >> 8 & 255 ); int blendedBlue = interpolate(frameProgress, prevFramePixel & 255, nextFramePixel & 255); this.interpolatedFrame.setPixelRGBA( - x, - y, - prevFramePixel & -16777216 | blendedRed << 16 | blendedGreen << 8 | blendedBlue + x, + y, + prevFramePixel & -16777216 | blendedRed << 16 | blendedGreen << 8 | blendedBlue ); } } TextureUtil.prepareImage( - AnimatableTexture.this.getId(), - 0, - AnimationContents.this.frameSize.width(), - AnimationContents.this.frameSize.height() + AnimatableTexture.this.getId(), + 0, + AnimationContents.this.frameSize.width(), + AnimationContents.this.frameSize.height() ); this.interpolatedFrame.upload( - 0, - 0, - 0, - 0, - 0, - AnimationContents.this.frameSize.width(), - AnimationContents.this.frameSize.height(), - false, - false + 0, + 0, + 0, + 0, + 0, + AnimationContents.this.frameSize.width(), + AnimationContents.this.frameSize.height(), + false, + false ); } } private int getPixel(int frameIndex, int x, int y) { return this.baseImage.getPixelRGBA( - x + getFrameX(frameIndex) * AnimationContents.this.frameSize.width(), - y + getFrameY(frameIndex) * AnimationContents.this.frameSize.height() + x + getFrameX(frameIndex) * AnimationContents.this.frameSize.width(), + y + getFrameY(frameIndex) * AnimationContents.this.frameSize.height() ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java index 436eddae0..6d213ad25 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.texture; @@ -30,7 +28,6 @@ import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.function.BiFunction; -import java.util.function.Function; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.platform.Services; @@ -40,26 +37,54 @@ */ public class AutoGlowingTexture extends GeoAbstractTexture { - private static final RenderStateShard.ShaderStateShard SHADER_STATE = new RenderStateShard.ShaderStateShard(GameRenderer::getRendertypeEntityTranslucentEmissiveShader); - private static final RenderStateShard.TransparencyStateShard TRANSPARENCY_STATE = new RenderStateShard.TransparencyStateShard("translucent_transparency", () -> { - RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); - }, () -> { - RenderSystem.disableBlend(); - RenderSystem.defaultBlendFunc(); - }); - private static final RenderStateShard.WriteMaskStateShard WRITE_MASK = new RenderStateShard.WriteMaskStateShard(true, true); - private static final BiFunction GLOWING_RENDER_TYPE = Util.memoize((texture, isGlowing) -> { - RenderStateShard.TextureStateShard textureState = new RenderStateShard.TextureStateShard(texture, false, false); - - return RenderType.create("geo_glowing_layer", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, true, + private static final RenderStateShard.ShaderStateShard SHADER_STATE = new RenderStateShard.ShaderStateShard( + GameRenderer::getRendertypeEntityTranslucentEmissiveShader + ); + + private static final RenderStateShard.TransparencyStateShard TRANSPARENCY_STATE = + new RenderStateShard.TransparencyStateShard("translucent_transparency", () -> { + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate( + GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA + ); + }, () -> { + RenderSystem.disableBlend(); + RenderSystem.defaultBlendFunc(); + }); + + private static final RenderStateShard.WriteMaskStateShard WRITE_MASK = new RenderStateShard.WriteMaskStateShard( + true, + true + ); + + private static final BiFunction GLOWING_RENDER_TYPE = Util.memoize( + (texture, isGlowing) -> { + RenderStateShard.TextureStateShard textureState = new RenderStateShard.TextureStateShard( + texture, + false, + false + ); + + return RenderType.create( + "geo_glowing_layer", + DefaultVertexFormat.NEW_ENTITY, + VertexFormat.Mode.QUADS, + 256, + false, + true, RenderType.CompositeState.builder() - .setShaderState(SHADER_STATE) - .setTextureState(textureState) - .setTransparencyState(TRANSPARENCY_STATE) - .setOverlayState(new RenderStateShard.OverlayStateShard(true)) - .setWriteMaskState(WRITE_MASK).createCompositeState(isGlowing)); - }); + .setShaderState(SHADER_STATE) + .setTextureState(textureState) + .setTransparencyState(TRANSPARENCY_STATE) + .setOverlayState(new RenderStateShard.OverlayStateShard(true)) + .setWriteMaskState(WRITE_MASK) + .createCompositeState(isGlowing) + ); + } + ); private static final String APPENDIX = "_glowmask"; @@ -82,8 +107,8 @@ protected static ResourceLocation getEmissiveResource(ResourceLocation baseResou ResourceLocation path = appendToPath(baseResource, APPENDIX); generateTexture( - path, - textureManager -> textureManager.register(path, new AutoGlowingTexture(baseResource, path)) + path, + textureManager -> textureManager.register(path, new AutoGlowingTexture(baseResource, path)) ); return path; @@ -98,9 +123,9 @@ public static RenderType getRenderType(ResourceLocation texture) { return GLOWING_RENDER_TYPE.apply(getEmissiveResource(texture), false); } - /** - * Return a cached instance of the RenderType for the given texture for AutoGlowingGeoLayer rendering, while the entity has an outline + * Return a cached instance of the RenderType for the given texture for AutoGlowingGeoLayer rendering, while the + * entity has an outline * * @param texture The texture of the resource to apply a glow layer to */ @@ -125,11 +150,11 @@ protected RenderCall loadTexture(ResourceManager resourceManager, Minecraft mc) Resource textureBaseResource = resourceManager.getResource(this.textureBase).get(); NativeImage baseImage = originalTexture instanceof DynamicTexture dynamicTexture - ? dynamicTexture.getPixels() - : NativeImage.read(textureBaseResource.open()); + ? dynamicTexture.getPixels() + : NativeImage.read(textureBaseResource.open()); NativeImage glowImage = null; Optional textureBaseMeta = textureBaseResource.metadata() - .getSection(TextureMetadataSection.SERIALIZER); + .getSection(TextureMetadataSection.SERIALIZER); boolean blur = textureBaseMeta.isPresent() && textureBaseMeta.get().isBlur(); boolean clamp = textureBaseMeta.isPresent() && textureBaseMeta.get().isClamp(); @@ -142,7 +167,7 @@ protected RenderCall loadTexture(ResourceManager resourceManager, Minecraft mc) glowLayerMeta = GeoGlowingTextureMeta.fromExistingImage(glowImage); } else { Optional meta = textureBaseResource.metadata() - .getSection(GeoGlowingTextureMeta.DESERIALIZER); + .getSection(GeoGlowingTextureMeta.DESERIALIZER); if (meta.isPresent()) { glowLayerMeta = meta.get(); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java index 68d8875c1..1503f717b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.texture; @@ -35,21 +33,21 @@ public abstract class GeoAbstractTexture extends AbstractTexture { * Generates the texture instance for the given path with the given appendix if it hasn't already been generated */ protected static void generateTexture( - ResourceLocation texturePath, - Consumer textureManagerConsumer + ResourceLocation texturePath, + Consumer textureManagerConsumer ) { if (!RenderSystem.isOnRenderThreadOrInit()) throw new IllegalThreadStateException( - "Texture loading called outside of the render thread! This should DEFINITELY not be happening." + "Texture loading called outside of the render thread! This should DEFINITELY not be happening." ); TextureManager textureManager = Minecraft.getInstance().getTextureManager(); if ( - !(textureManager.getTexture( - texturePath, - MissingTextureAtlasSprite.getTexture() - ) instanceof GeoAbstractTexture) + !(textureManager.getTexture( + texturePath, + MissingTextureAtlasSprite.getTexture() + ) instanceof GeoAbstractTexture) ) textureManagerConsumer.accept(textureManager); } @@ -66,7 +64,10 @@ public static ResourceLocation appendToPath(ResourceLocation location, String su String path = location.getPath(); int i = path.lastIndexOf('.'); - return ResourceLocation.fromNamespaceAndPath(location.getNamespace(), path.substring(0, i) + suffix + path.substring(i)); + return ResourceLocation.fromNamespaceAndPath( + location.getNamespace(), + path.substring(0, i) + suffix + path.substring(i) + ); } @Override diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java index 095aaa6e2..103b0ac00 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.texture; @@ -13,7 +11,6 @@ import com.google.gson.JsonParseException; import com.mojang.blaze3d.platform.NativeImage; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.api.client.renderer.layer.AutoGlowingGeoLayer; import net.minecraft.server.packs.metadata.MetadataSectionSerializer; import net.minecraft.util.FastColor; import net.minecraft.util.GsonHelper; @@ -21,6 +18,8 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.renderer.layer.AutoGlowingGeoLayer; + /** * Metadata class that stores the data for AzureLib's {@link AutoGlowingGeoLayer emissive texture feature} for a given * texture @@ -28,60 +27,61 @@ public class GeoGlowingTextureMeta { public static final MetadataSectionSerializer DESERIALIZER = - new MetadataSectionSerializer<>() { + new MetadataSectionSerializer<>() { - @Override - public String getMetadataSectionName() { - return "glowsections"; - } + @Override + public String getMetadataSectionName() { + return "glowsections"; + } - @Override - public GeoGlowingTextureMeta fromJson(JsonObject json) { - List pixels = fromSections(GsonHelper.getAsJsonArray(json, "sections", null)); + @Override + public GeoGlowingTextureMeta fromJson(JsonObject json) { + List pixels = fromSections(GsonHelper.getAsJsonArray(json, "sections", null)); - if (pixels.isEmpty()) - throw new JsonParseException( - "Empty glowlayer sections file. Must have at least one glow section!"); + if (pixels.isEmpty()) + throw new JsonParseException( + "Empty glowlayer sections file. Must have at least one glow section!" + ); - return new GeoGlowingTextureMeta(pixels); - } + return new GeoGlowingTextureMeta(pixels); + } - /** - * Generate a {@link Pixel} collection from the "sections" array of the mcmeta file - */ - private List fromSections(@Nullable JsonArray sectionsArray) { - if (sectionsArray == null) - return List.of(); - - List pixels = new ObjectArrayList<>(); - - for (JsonElement element : sectionsArray) { - if (!(element instanceof JsonObject obj)) - throw new JsonParseException( - "Invalid glowsections json format, expected a JsonObject, found: " + element.getClass() - ); - - int x1 = GsonHelper.getAsInt(obj, "x1", GsonHelper.getAsInt(obj, "x", 0)); - int y1 = GsonHelper.getAsInt(obj, "y1", GsonHelper.getAsInt(obj, "y", 0)); - int x2 = GsonHelper.getAsInt(obj, "x2", GsonHelper.getAsInt(obj, "w", 0) + x1); - int y2 = GsonHelper.getAsInt(obj, "y2", GsonHelper.getAsInt(obj, "h", 0) + y1); - int alpha = GsonHelper.getAsInt(obj, "alpha", GsonHelper.getAsInt(obj, "a", 0)); - - if (x1 + y1 + x2 + y2 == 0) - throw new IllegalArgumentException( - "Invalid glowsections section object, section must be at least one pixel in size" - ); - - for (int x = x1; x <= x2; x++) { - for (int y = y1; y <= y2; y++) { - pixels.add(new Pixel(x, y, alpha)); - } + /** + * Generate a {@link Pixel} collection from the "sections" array of the mcmeta file + */ + private List fromSections(@Nullable JsonArray sectionsArray) { + if (sectionsArray == null) + return List.of(); + + List pixels = new ObjectArrayList<>(); + + for (JsonElement element : sectionsArray) { + if (!(element instanceof JsonObject obj)) + throw new JsonParseException( + "Invalid glowsections json format, expected a JsonObject, found: " + element.getClass() + ); + + int x1 = GsonHelper.getAsInt(obj, "x1", GsonHelper.getAsInt(obj, "x", 0)); + int y1 = GsonHelper.getAsInt(obj, "y1", GsonHelper.getAsInt(obj, "y", 0)); + int x2 = GsonHelper.getAsInt(obj, "x2", GsonHelper.getAsInt(obj, "w", 0) + x1); + int y2 = GsonHelper.getAsInt(obj, "y2", GsonHelper.getAsInt(obj, "h", 0) + y1); + int alpha = GsonHelper.getAsInt(obj, "alpha", GsonHelper.getAsInt(obj, "a", 0)); + + if (x1 + y1 + x2 + y2 == 0) + throw new IllegalArgumentException( + "Invalid glowsections section object, section must be at least one pixel in size" + ); + + for (int x = x1; x <= x2; x++) { + for (int y = y1; y <= y2; y++) { + pixels.add(new Pixel(x, y, alpha)); } } - - return pixels; } - }; + + return pixels; + } + }; private final List pixels; @@ -119,10 +119,10 @@ public void createImageMask(NativeImage originalImage, NativeImage newImage) { if (pixel.alpha > 0) color = FastColor.ABGR32.color( - pixel.alpha, - FastColor.ABGR32.blue(color), - FastColor.ABGR32.green(color), - FastColor.ABGR32.red(color) + pixel.alpha, + FastColor.ABGR32.blue(color), + FastColor.ABGR32.green(color), + FastColor.ABGR32.red(color) ); newImage.setPixelRGBA(pixel.x, pixel.y, color); @@ -138,9 +138,8 @@ public void createImageMask(NativeImage originalImage, NativeImage newImage) { * @param alpha The alpha value of the mask */ private record Pixel( - int x, - int y, - int alpha - ) { - } + int x, + int y, + int alpha + ) {} } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolder.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolder.java index 632b9f959..838aac5c9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolder.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolder.java @@ -1,11 +1,15 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; + import mod.azure.azurelib.common.internal.client.config.IValidationHandler; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.AzureLibException; @@ -16,12 +20,6 @@ import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; import mod.azure.azurelib.common.internal.common.config.value.ObjectValue; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.*; - /** * Manages config values and stores some default parameters of your config class. This class also acts as config * registry. @@ -62,11 +60,11 @@ public final class ConfigHolder { private final Object lock = new Object(); public ConfigHolder( - Class cfgClass, - String configId, - String filename, - String group, - IConfigFormatHandler format + Class cfgClass, + String configId, + String filename, + String group, + IConfigFormatHandler format ) { this.configClass = cfgClass; this.configId = configId; @@ -75,7 +73,7 @@ public ConfigHolder( try { this.configInstance = cfgClass.getDeclaredConstructor().newInstance(); } catch ( - NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e + NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e ) { AzureLib.LOGGER.fatal(AzureLib.MAIN_MARKER, "Failed to instantiate config class for {} config", configId); throw new AzureLibException("Config create failed", e); @@ -176,9 +174,9 @@ public Object getLock() { } private Map> serializeType( - Class type, - Object instance, - boolean saveValue + Class type, + Object instance, + boolean saveValue ) throws IllegalAccessException { Map> map = new LinkedHashMap<>(); Field[] fields = type.getFields(); @@ -189,18 +187,18 @@ private Map> serializeType( int modifiers = field.getModifiers(); if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) { AzureLib.LOGGER.warn( - ConfigIO.MARKER, - "Skipping config field {}, only instance non-final types are supported", - field + ConfigIO.MARKER, + "Skipping config field {}, only instance non-final types are supported", + field ); continue; } TypeAdapter adapter = TypeAdapters.forType(field.getType()); if (adapter == null) { AzureLib.LOGGER.warn( - ConfigIO.MARKER, - "Missing adapter for type {}, skipping serialization", - field.getType() + ConfigIO.MARKER, + "Missing adapter for type {}, skipping serialization", + field.getType() ); continue; } @@ -211,39 +209,39 @@ private Map> serializeType( } field.setAccessible(true); ConfigValue cfgValue = adapter.serialize( - field.getName(), - comments, - field.get(instance), - (type1, instance1) -> serializeType(type1, instance1, false), - new TypeAdapter.AdapterContext() { - - @Override - public TypeAdapter getAdapter() { - return adapter; - } + field.getName(), + comments, + field.get(instance), + (type1, instance1) -> serializeType(type1, instance1, false), + new TypeAdapter.AdapterContext() { + + @Override + public TypeAdapter getAdapter() { + return adapter; + } - @Override - public Field getOwner() { - return field; - } + @Override + public Field getOwner() { + return field; + } - @Override - public void setFieldValue(Object value) { - field.setAccessible(true); - try { - adapter.setFieldValue(field, instance, value); - } catch (IllegalAccessException e) { - AzureLib.LOGGER.error( - ConfigIO.MARKER, - "Failed to update config value for field {} from {} to a new value {} due to error {}", - field.getName(), - type, - value, - e - ); - } + @Override + public void setFieldValue(Object value) { + field.setAccessible(true); + try { + adapter.setFieldValue(field, instance, value); + } catch (IllegalAccessException e) { + AzureLib.LOGGER.error( + ConfigIO.MARKER, + "Failed to update config value for field {} from {} to a new value {} due to error {}", + field.getName(), + type, + value, + e + ); } } + } ); Configurable.ValueUpdateCallback callback = field.getAnnotation(Configurable.ValueUpdateCallback.class); if (callback != null) { @@ -259,10 +257,10 @@ public void setFieldValue(Object value) { } private void processCallback( - Configurable.ValueUpdateCallback callback, - Class type, - Object instance, - ConfigValue value + Configurable.ValueUpdateCallback callback, + Class type, + Object instance, + ConfigValue value ) { String methodName = callback.method(); try { @@ -281,24 +279,24 @@ private void processCallback( }; value.setValueValidator(setValueCallback); AzureLib.LOGGER.debug( - ConfigIO.MARKER, - "Attached new value listener method '{}' for config value {}", - methodName, - value.getId() + ConfigIO.MARKER, + "Attached new value listener method '{}' for config value {}", + methodName, + value.getId() ); } catch (NoSuchMethodException e) { AzureLib.LOGGER.error( - ConfigIO.MARKER, - "Unable to map method {} for config value {} due to {}", - methodName, - value.getId(), - e + ConfigIO.MARKER, + "Unable to map method {} for config value {} due to {}", + methodName, + value.getId(), + e ); } catch (Exception e) { AzureLib.LOGGER.fatal( - ConfigIO.MARKER, - "Fatal error occurred while trying to map value listener for {} method", - methodName + ConfigIO.MARKER, + "Fatal error occurred while trying to map value listener for {} method", + methodName ); throw new AzureLibException("Value listener map failed", e); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolderRegistry.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolderRegistry.java index 4be9352d2..9024711cc 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolderRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolderRegistry.java @@ -1,12 +1,12 @@ package mod.azure.azurelib.common.internal.common.config; +import java.util.*; +import java.util.stream.Collectors; + import mod.azure.azurelib.common.internal.common.AzureLibMod; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormatHandler; import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import java.util.*; -import java.util.stream.Collectors; - /** * @author Boston Vanseghi */ @@ -58,9 +58,9 @@ public static Map>> getConfigGroupingByGroup() { */ public static List> getConfigsByGroup(String group) { return REGISTERED_CONFIGS.values() - .stream() - .filter(configHolder -> configHolder.getGroup().equals(group)) - .toList(); + .stream() + .filter(configHolder -> configHolder.getGroup().equals(group)) + .toList(); } /** @@ -70,9 +70,9 @@ public static List> getConfigsByGroup(String group) { */ public static Set getSynchronizedConfigs() { return REGISTERED_CONFIGS.entrySet() - .stream() - .filter(e -> !e.getValue().getNetworkSerializedFields().isEmpty()) - .map(Map.Entry::getKey) - .collect(Collectors.toSet()); + .stream() + .filter(e -> !e.getValue().getNetworkSerializedFields().isEmpty()) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigUtils.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigUtils.java index bf2dc3f8f..3ea974948 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigUtils.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigUtils.java @@ -1,14 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; import net.minecraft.client.gui.components.EditBox; import org.jetbrains.annotations.Nullable; @@ -20,11 +15,15 @@ import java.util.Objects; import java.util.regex.Pattern; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; + public final class ConfigUtils { - public static final char[] INTEGER_CHARS = {'-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + public static final char[] INTEGER_CHARS = { '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; - public static final char[] DECIMAL_CHARS = {'-', '.', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + public static final char[] DECIMAL_CHARS = { '-', '.', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; public static final Pattern INTEGER_PATTERN = Pattern.compile("-?[0-9]+"); @@ -49,21 +48,21 @@ private ConfigUtils() { public static void logCorrectedMessage(String field, @Nullable Object prevValue, Object corrected) { AzureLib.LOGGER.warn( - ConfigIO.MARKER, - "Correcting config value '{}' from '{}' to '{}'", - field, - Objects.toString(prevValue), - corrected + ConfigIO.MARKER, + "Correcting config value '{}' from '{}' to '{}'", + field, + Objects.toString(prevValue), + corrected ); } public static void logArraySizeCorrectedMessage(String field, Object prevValue, Object corrected) { AzureLib.LOGGER.warn( - ConfigIO.MARKER, - "Correcting config array value '{}' due to invalid size from '{}' to '{}'", - field, - prevValue, - corrected + ConfigIO.MARKER, + "Correcting config array value '{}' due to invalid size from '{}' to '{}'", + field, + prevValue, + corrected ); } @@ -113,8 +112,8 @@ public static double[] unboxArray(Double[] values) { } public static > E getEnumConstant( - String value, - Class declaringClass + String value, + Class declaringClass ) throws ConfigValueMissingException { E[] constants = declaringClass.getEnumConstants(); for (E e : constants) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/Configurable.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/Configurable.java index bb5ceb967..3141e7b04 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/Configurable.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/Configurable.java @@ -1,18 +1,16 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config; -import mod.azure.azurelib.common.internal.client.config.IValidationHandler; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import mod.azure.azurelib.common.internal.client.config.IValidationHandler; + /** * Marker annotation for field to config serialization. Only public instance fields are allowed. * @@ -42,8 +40,7 @@ */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) - @interface Synchronized { - } + @interface Synchronized {} /** * Allows you to specify number range for int or long values. This annotation is also applicable to int/long arrays @@ -109,7 +106,7 @@ /** * @return Flags used for {@link java.util.regex.Pattern} object. You can use for example value like - * {@code flags = Pattern.CASE_INSENTITIVE | Pattern.LITERAL} for flag specification + * {@code flags = Pattern.CASE_INSENTITIVE | Pattern.LITERAL} for flag specification */ int flags() default 0; @@ -126,8 +123,7 @@ */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) - @interface FixedSize { - } + @interface FixedSize {} /** * Allows you to map custom listener method to listen for value change. Could be useful for example when validating @@ -151,7 +147,7 @@ * Handles remapping of boxed java types to their primitive values * * @return Whether remapping is allowed, unless specific implementation is provided, this should always be set - * to true + * to true */ boolean allowPrimitivesMapping() default true; } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapter.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapter.java index b7a882724..0ff48c252 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapter.java @@ -1,25 +1,24 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.adapter; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; import net.minecraft.network.FriendlyByteBuf; import java.lang.reflect.Field; import java.util.Map; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; + public abstract class TypeAdapter { public abstract ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException; public abstract void encodeToBuffer(ConfigValue value, FriendlyByteBuf buffer); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapters.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapters.java index 7e49b8ecf..6377fbf10 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapters.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapters.java @@ -1,17 +1,15 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.adapter; -import mod.azure.azurelib.common.internal.common.config.value.*; - import java.util.Comparator; import java.util.HashMap; import java.util.Map; +import mod.azure.azurelib.common.internal.common.config.value.*; + public final class TypeAdapters { private static final Map ADAPTER_MAP = new HashMap<>(); @@ -48,12 +46,12 @@ private TypeAdapters() { public static TypeAdapter forType(Class type) { return ADAPTER_MAP.entrySet() - .stream() - .filter(entry -> entry.getKey().test(type)) - .sorted(Comparator.comparingInt(value -> value.getKey().priority())) - .map(Map.Entry::getValue) - .findFirst() - .orElse(null); + .stream() + .filter(entry -> entry.getKey().test(type)) + .sorted(Comparator.comparingInt(value -> value.getKey().priority())) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null); } public static void registerTypeAdapter(TypeMatcher matcher, TypeAdapter adapter) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeMatcher.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeMatcher.java index 90c84b4f7..210f388b6 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeMatcher.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeMatcher.java @@ -1,17 +1,16 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.adapter; -import mod.azure.azurelib.common.internal.common.AzureLib; import net.minecraft.resources.ResourceLocation; import java.util.Objects; import java.util.function.Predicate; +import mod.azure.azurelib.common.internal.common.AzureLib; + public interface TypeMatcher extends Predicate> { static TypeMatcher matchBoolean() { @@ -76,7 +75,7 @@ static TypeMatcher matchEnumArray() { static TypeMatcher matchObject() { return NamedMatcherImpl.vanilla("object", type -> !type.isArray()) - .withPriority(Integer.MAX_VALUE); + .withPriority(Integer.MAX_VALUE); } ResourceLocation getIdentifier(); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigReadException.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigReadException.java index 4ae6026b3..61abe8869 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigReadException.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigReadException.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.exception; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigValueMissingException.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigValueMissingException.java index 8745a8bfe..700ea4159 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigValueMissingException.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigValueMissingException.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.exception; @@ -13,8 +11,7 @@ public class ConfigValueMissingException extends Exception { */ private static final long serialVersionUID = -6063813873167943417L; - public ConfigValueMissingException() { - } + public ConfigValueMissingException() {} public ConfigValueMissingException(String message) { super(message); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/ConfigFormats.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/ConfigFormats.java index 8df2aa801..3efe91753 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/ConfigFormats.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/ConfigFormats.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/GsonFormat.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/GsonFormat.java index 8a90bffbc..c91276cc0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/GsonFormat.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/GsonFormat.java @@ -1,19 +1,10 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; import com.google.gson.*; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.ConfigUtils; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; import java.io.File; import java.io.FileReader; @@ -27,6 +18,14 @@ import java.util.function.Consumer; import java.util.function.Function; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.ConfigUtils; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; + public final class GsonFormat implements IConfigFormat { private final Gson gson; @@ -294,9 +293,9 @@ private T tryRead(String field, Function function) throws Co } private T[] readArray( - String field, - Function arrayFactory, - Function function + String field, + Function arrayFactory, + Function function ) throws ConfigValueMissingException { JsonElement element = this.root.get(field); if (element == null || !element.isJsonArray()) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormat.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormat.java index 2164bd643..9b985a017 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormat.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormat.java @@ -1,21 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; - import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Map; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; + /** * Handles exporting of data to custom file format * diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormatHandler.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormatHandler.java index 705e0490d..47aaa052f 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormatHandler.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormatHandler.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/PropertiesFormat.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/PropertiesFormat.java index 4960fd248..d45f45141 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/PropertiesFormat.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/PropertiesFormat.java @@ -1,16 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; -import mod.azure.azurelib.common.internal.common.config.ConfigUtils; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; import org.jetbrains.annotations.Nullable; import java.io.*; @@ -19,6 +12,12 @@ import java.util.function.Function; import java.util.stream.Collectors; +import mod.azure.azurelib.common.internal.common.config.ConfigUtils; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; + public final class PropertiesFormat implements IConfigFormat { private final Settings settings; @@ -287,16 +286,16 @@ public void writeMap(String field, Map> value) { @Override public void readMap(String field, Collection> values) throws ConfigValueMissingException { Set validElements = this.parsed.keySet() - .stream() - .filter(key -> { - String[] strings = key.split("\\.", 2); - if (strings.length < 2) { - return false; - } - String prefix = strings[0]; - return prefix.equals(field); - }) - .collect(Collectors.toSet()); + .stream() + .filter(key -> { + String[] strings = key.split("\\.", 2); + if (strings.length < 2) { + return false; + } + String prefix = strings[0]; + return prefix.equals(field); + }) + .collect(Collectors.toSet()); Map parsed = new HashMap<>(); for (String key : validElements) { String s = key.split("\\.", 2)[1]; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/YamlFormat.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/YamlFormat.java index 49528721f..1711aa070 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/YamlFormat.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/YamlFormat.java @@ -1,23 +1,21 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; -import mod.azure.azurelib.common.internal.common.config.ConfigUtils; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; - import java.io.*; import java.lang.reflect.Array; import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; +import mod.azure.azurelib.common.internal.common.config.ConfigUtils; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; + public class YamlFormat implements IConfigFormat { // writing diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/ConfigIO.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/ConfigIO.java index 041715982..bf83b9dfa 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/ConfigIO.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/ConfigIO.java @@ -1,17 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.io; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.AzureLibException; -import mod.azure.azurelib.common.internal.common.config.ConfigHolder; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormatHandler; import net.minecraft.CrashReport; import net.minecraft.ReportedException; import org.apache.logging.log4j.Marker; @@ -20,14 +12,20 @@ import java.io.File; import java.io.IOException; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.AzureLibException; +import mod.azure.azurelib.common.internal.common.config.ConfigHolder; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormatHandler; + public final class ConfigIO { public static final Marker MARKER = MarkerManager.getMarker("IO"); public static final FileWatchManager FILE_WATCH_MANAGER = new FileWatchManager(); - private ConfigIO() { - } + private ConfigIO() {} public static void processConfig(ConfigHolder holder) { AzureLib.LOGGER.debug(MARKER, "Starting processing of config {}", holder.getConfigId()); @@ -38,9 +36,9 @@ public static void processConfig(ConfigHolder holder) { readConfig(holder); } catch (IOException e) { AzureLib.LOGGER.error( - MARKER, - "Config read failed for config ID {}, will create default config file", - holder.getConfigId() + MARKER, + "Config read failed for config ID {}, will create default config file", + holder.getConfigId() ); } } @@ -81,14 +79,16 @@ private static void processSafely(ConfigHolder holder, Runnable action) { } } catch (Exception e) { AzureLib.LOGGER.fatal( - MARKER, - "Error loading config {} due to critical error '{}'. Report this issue to this config's owner!", - holder.getConfigId(), - e.getMessage() + MARKER, + "Error loading config {} due to critical error '{}'. Report this issue to this config's owner!", + holder.getConfigId(), + e.getMessage() ); throw new ReportedException( - CrashReport.forThrowable(e, - "Config " + holder.getConfigId() + " failed. Report issue to config owner") + CrashReport.forThrowable( + e, + "Config " + holder.getConfigId() + " failed. Report issue to config owner" + ) ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/FileWatchManager.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/FileWatchManager.java index 88008753b..5cb03fefe 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/FileWatchManager.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/FileWatchManager.java @@ -1,14 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.io; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.AzureLibException; -import mod.azure.azurelib.common.internal.common.config.ConfigHolder; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; import org.jetbrains.annotations.Nullable; @@ -22,6 +17,10 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.AzureLibException; +import mod.azure.azurelib.common.internal.common.config.ConfigHolder; + public final class FileWatchManager { public static final Marker MARKER = MarkerManager.getMarker("FileWatching"); @@ -43,9 +42,9 @@ public FileWatchManager() { watchService = FileSystems.getDefault().newWatchService(); } catch (IOException e) { AzureLib.LOGGER.error( - MARKER, - "Failed to initialize file watch service due to error, configs won't be automatically refreshed", - e + MARKER, + "Failed to initialize file watch service due to error, configs won't be automatically refreshed", + e ); } finally { this.service = watchService; @@ -108,9 +107,9 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th }, 0L, 1000L, TimeUnit.MILLISECONDS); } catch (IOException e) { AzureLib.LOGGER.error( - MARKER, - "Unable to create watch key for config directory, disabling auto-sync function", - e + MARKER, + "Unable to create watch key for config directory, disabling auto-sync function", + e ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/NotificationSeverity.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/NotificationSeverity.java index 1ffc43253..11cd83e26 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/NotificationSeverity.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/NotificationSeverity.java @@ -1,15 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.validate; -import mod.azure.azurelib.common.internal.common.AzureLib; import net.minecraft.ChatFormatting; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.common.internal.common.AzureLib; + public enum NotificationSeverity { INFO("", ChatFormatting.RESET, 0xF0030319, 0x502493E5, 0x502469E5), @@ -17,9 +16,13 @@ public enum NotificationSeverity { ERROR("error", ChatFormatting.RED, 0xF0270006, 0x50FF0000, 0x50880000); public final int background; + public final int fadeMin; + public final int fadeMax; + private final ResourceLocation icon; + private final ChatFormatting extraFormatting; NotificationSeverity(String iconName, ChatFormatting formatting, int background, int fadeMin, int fadeMax) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/ValidationResult.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/ValidationResult.java index fa07f92e2..64101f19a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/ValidationResult.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/ValidationResult.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.validate; @@ -10,13 +8,13 @@ import net.minecraft.network.chat.MutableComponent; public record ValidationResult( - NotificationSeverity severity, - MutableComponent text + NotificationSeverity severity, + MutableComponent text ) { private static final ValidationResult OK = new ValidationResult( - NotificationSeverity.INFO, - (MutableComponent) CommonComponents.EMPTY + NotificationSeverity.INFO, + (MutableComponent) CommonComponents.EMPTY ); public static ValidationResult ok() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ArrayValue.java index c75dd4489..9418cf1a9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ArrayValue.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanArrayValue.java index 49778b1dc..634b6ccc3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; public class BooleanArrayValue extends ConfigValue implements ArrayValue { @@ -40,9 +39,9 @@ protected boolean[] getCorrectedValue(boolean[] in) { boolean[] defaultArray = this.valueData.getDefaultValue(); if (in.length != defaultArray.length) { ConfigUtils.logArraySizeCorrectedMessage( - this.getId(), - Arrays.toString(in), - Arrays.toString(defaultArray) + this.getId(), + Arrays.toString(in), + Arrays.toString(defaultArray) ); return defaultArray; } @@ -79,11 +78,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new BooleanArrayValue(ValueData.of(name, (boolean[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanValue.java index 0b0be276e..a6e2fff73 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import net.minecraft.network.FriendlyByteBuf; import java.lang.reflect.Field; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; + public final class BooleanValue extends ConfigValue { public BooleanValue(ValueData valueData) { @@ -35,11 +34,11 @@ public static class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) { return new BooleanValue(ValueData.of(name, (boolean) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/CharValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/CharValue.java index 88b52dbff..c81332a16 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/CharValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/CharValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import net.minecraft.network.FriendlyByteBuf; import java.lang.reflect.Field; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; + public final class CharValue extends ConfigValue { public CharValue(ValueData valueData) { @@ -33,11 +32,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new CharValue(ValueData.of(name, (char) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ConfigValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ConfigValue.java index 1529a818f..c501983df 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ConfigValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ConfigValue.java @@ -1,17 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.client.config.IValidationHandler; -import mod.azure.azurelib.common.internal.common.config.ConfigUtils; -import mod.azure.azurelib.common.internal.common.config.Configurable; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; @@ -20,6 +12,13 @@ import java.util.List; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.client.config.IValidationHandler; +import mod.azure.azurelib.common.internal.common.config.ConfigUtils; +import mod.azure.azurelib.common.internal.common.config.Configurable; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; + public abstract class ConfigValue implements Supplier { protected final ValueData valueData; @@ -73,8 +72,7 @@ public final void processFieldData(Field field) { this.readFieldData(field); } - protected void readFieldData(Field field) { - } + protected void readFieldData(Field field) {} protected T getCorrectedValue(T in) { return in; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DecimalValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DecimalValue.java index 6569a47a8..09a05d928 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DecimalValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DecimalValue.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.Configurable; - import java.lang.reflect.Field; import java.util.Objects; +import mod.azure.azurelib.common.internal.common.config.Configurable; + public abstract class DecimalValue extends ConfigValue { protected Range range; @@ -50,8 +48,11 @@ private Range(double min, double max) { public static Range newBoundedRange(double min, double max) { if (min > max) { throw new IllegalArgumentException( - String.format("Invalid number range: Min value (%f) cannot be bigger than max value (%f)", min, - max) + String.format( + "Invalid number range: Min value (%f) cannot be bigger than max value (%f)", + min, + max + ) ); } return new Range(min, max); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleArrayValue.java index 9b3ff8953..9e1cefdab 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; public class DoubleArrayValue extends ConfigValue implements ArrayValue { @@ -36,8 +35,8 @@ protected void readFieldData(Field field) { this.fixedSize = field.getAnnotation(Configurable.FixedSize.class) != null; Configurable.DecimalRange decimalRange = field.getAnnotation(Configurable.DecimalRange.class); this.range = decimalRange != null - ? DecimalValue.Range.newBoundedRange(decimalRange.min(), decimalRange.max()) - : DecimalValue.Range.unboundedDouble(); + ? DecimalValue.Range.newBoundedRange(decimalRange.min(), decimalRange.max()) + : DecimalValue.Range.unboundedDouble(); } @Override @@ -46,9 +45,9 @@ protected double[] getCorrectedValue(double[] in) { double[] defaultArray = this.valueData.getDefaultValue(); if (in.length != defaultArray.length) { ConfigUtils.logArraySizeCorrectedMessage( - this.getId(), - Arrays.toString(in), - Arrays.toString(defaultArray) + this.getId(), + Arrays.toString(in), + Arrays.toString(defaultArray) ); in = defaultArray; } @@ -117,11 +116,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new DoubleArrayValue(ValueData.of(name, (double[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleValue.java index fa3fd2603..a2bc2ee01 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; public class DoubleValue extends DecimalValue { @@ -46,11 +45,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new DoubleValue(ValueData.of(name, (double) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumArrayValue.java index 680f228e2..4e11af2c7 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.Configurable; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import net.minecraft.network.FriendlyByteBuf; import java.lang.reflect.Array; import java.lang.reflect.Field; +import mod.azure.azurelib.common.internal.common.config.Configurable; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; + public class EnumArrayValue> extends ConfigValue implements ArrayValue { private boolean fixedSize; @@ -50,11 +49,11 @@ public static final class Adapter> extends TypeAdapter { @SuppressWarnings("unchecked") @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new EnumArrayValue<>(ValueData.of(name, (E[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumValue.java index 65ec420a7..4dd39de09 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumValue.java @@ -1,15 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; public class EnumValue> extends ConfigValue { @@ -32,11 +31,11 @@ public static final class Adapter> extends TypeAdapter { @SuppressWarnings("unchecked") @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new EnumValue<>(ValueData.of(name, (E) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatArrayValue.java index 73f6fd3fd..59a3310a2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; public class FloatArrayValue extends ConfigValue implements ArrayValue { @@ -36,8 +35,8 @@ protected void readFieldData(Field field) { this.fixedSize = field.getAnnotation(Configurable.FixedSize.class) != null; Configurable.DecimalRange decimalRange = field.getAnnotation(Configurable.DecimalRange.class); this.range = decimalRange != null - ? DecimalValue.Range.newBoundedRange(decimalRange.min(), decimalRange.max()) - : DecimalValue.Range.unboundedFloat(); + ? DecimalValue.Range.newBoundedRange(decimalRange.min(), decimalRange.max()) + : DecimalValue.Range.unboundedFloat(); } @Override @@ -46,9 +45,9 @@ protected float[] getCorrectedValue(float[] in) { float[] defaultArray = this.valueData.getDefaultValue(); if (in.length != defaultArray.length) { ConfigUtils.logArraySizeCorrectedMessage( - this.getId(), - Arrays.toString(in), - Arrays.toString(defaultArray) + this.getId(), + Arrays.toString(in), + Arrays.toString(defaultArray) ); in = defaultArray; } @@ -117,11 +116,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new FloatArrayValue(ValueData.of(name, (float[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatValue.java index 3254d79ee..da8be4e84 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; public class FloatValue extends DecimalValue { @@ -46,11 +45,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new FloatValue(ValueData.of(name, (float) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IDescriptionProvider.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IDescriptionProvider.java index df025e7c2..44e007fae 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IDescriptionProvider.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IDescriptionProvider.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntArrayValue.java index 9d83ce3f8..2950341a0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; public class IntArrayValue extends ConfigValue implements ArrayValue { @@ -36,8 +35,8 @@ protected void readFieldData(Field field) { this.fixedSize = field.getAnnotation(Configurable.FixedSize.class) != null; Configurable.Range intRange = field.getAnnotation(Configurable.Range.class); this.range = intRange != null - ? IntegerValue.Range.newBoundedRange(intRange.min(), intRange.max()) - : IntegerValue.Range.unboundedInt(); + ? IntegerValue.Range.newBoundedRange(intRange.min(), intRange.max()) + : IntegerValue.Range.unboundedInt(); } @Override @@ -46,9 +45,9 @@ protected int[] getCorrectedValue(int[] in) { int[] defaultArray = this.valueData.getDefaultValue(); if (in.length != defaultArray.length) { ConfigUtils.logArraySizeCorrectedMessage( - this.getId(), - Arrays.toString(in), - Arrays.toString(defaultArray) + this.getId(), + Arrays.toString(in), + Arrays.toString(defaultArray) ); in = defaultArray; } @@ -117,11 +116,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new IntArrayValue(ValueData.of(name, (int[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntValue.java index 489414954..91e98fcd2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; public final class IntValue extends IntegerValue { @@ -46,11 +45,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) { return new IntValue(ValueData.of(name, (int) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntegerValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntegerValue.java index 7fb3774a7..21012ba30 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntegerValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntegerValue.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.Configurable; - import java.lang.reflect.Field; import java.util.Objects; +import mod.azure.azurelib.common.internal.common.config.Configurable; + public abstract class IntegerValue extends ConfigValue { protected Range range; @@ -48,8 +46,11 @@ private Range(long min, long max) { public static Range newBoundedRange(long min, long max) { if (min > max) { throw new IllegalArgumentException( - String.format("Invalid number range: Min value (%d) cannot be bigger than max value (%d)", min, - max) + String.format( + "Invalid number range: Min value (%d) cannot be bigger than max value (%d)", + min, + max + ) ); } return new Range(min, max); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongArrayValue.java index 919af962a..f74f001a0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; public class LongArrayValue extends ConfigValue implements ArrayValue { @@ -36,8 +35,8 @@ protected void readFieldData(Field field) { this.fixedSize = field.getAnnotation(Configurable.FixedSize.class) != null; Configurable.Range intRange = field.getAnnotation(Configurable.Range.class); this.range = intRange != null - ? IntegerValue.Range.newBoundedRange(intRange.min(), intRange.max()) - : IntegerValue.Range.unboundedLong(); + ? IntegerValue.Range.newBoundedRange(intRange.min(), intRange.max()) + : IntegerValue.Range.unboundedLong(); } @Override @@ -46,9 +45,9 @@ protected long[] getCorrectedValue(long[] in) { long[] defaultArray = this.valueData.getDefaultValue(); if (in.length != defaultArray.length) { ConfigUtils.logArraySizeCorrectedMessage( - this.getId(), - Arrays.toString(in), - Arrays.toString(defaultArray) + this.getId(), + Arrays.toString(in), + Arrays.toString(defaultArray) ); in = defaultArray; } @@ -117,11 +116,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new LongArrayValue(ValueData.of(name, (long[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongValue.java index 989d6b869..696b54778 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; public class LongValue extends IntegerValue { @@ -46,11 +45,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new LongValue(ValueData.of(name, (long) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ObjectValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ObjectValue.java index 5adf7cd65..e60894d91 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ObjectValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ObjectValue.java @@ -1,19 +1,18 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import net.minecraft.network.FriendlyByteBuf; import java.lang.reflect.Field; import java.util.Map; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; + public class ObjectValue extends ConfigValue>> { public ObjectValue(ValueData>> valueData) { @@ -40,11 +39,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { Class type = value.getClass(); Map> map = serializer.serialize(type, value); @@ -52,8 +51,7 @@ public ConfigValue serialize( } @Override - public void encodeToBuffer(ConfigValue value, FriendlyByteBuf buffer) { - } + public void encodeToBuffer(ConfigValue value, FriendlyByteBuf buffer) {} @Override public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringArrayValue.java index 26031b908..f5f910f17 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringArrayValue.java @@ -1,11 +1,15 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.regex.Pattern; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; @@ -13,11 +17,6 @@ import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.regex.Pattern; public class StringArrayValue extends ConfigValue implements ArrayValue { @@ -47,20 +46,20 @@ protected void readFieldData(Field field) { this.pattern = Pattern.compile(value, stringPattern.flags()); } catch (IllegalArgumentException e) { AzureLib.LOGGER.error( - ConfigIO.MARKER, - "Invalid @StringPattern value for {} field - {}", - this.getId(), - e + ConfigIO.MARKER, + "Invalid @StringPattern value for {} field - {}", + this.getId(), + e ); } if (this.pattern != null && !this.pattern.matcher(this.defaultElementValue).matches()) { throw new IllegalArgumentException( - String.format( - "Invalid config default value '%s' for field '%s' - does not match required pattern \\%s\\", - this.defaultElementValue, - this.getId(), - this.pattern.toString() - ) + String.format( + "Invalid config default value '%s' for field '%s' - does not match required pattern \\%s\\", + this.defaultElementValue, + this.getId(), + this.pattern.toString() + ) ); } } @@ -136,11 +135,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new StringArrayValue(ValueData.of(name, (String[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringValue.java index cfc14b7eb..7c93dbb83 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringValue.java @@ -1,11 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.regex.Pattern; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; @@ -13,10 +16,6 @@ import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.regex.Pattern; public class StringValue extends ConfigValue { @@ -38,10 +37,10 @@ protected void readFieldData(Field field) { this.pattern = Pattern.compile(value, stringPattern.flags()); } catch (IllegalArgumentException e) { AzureLib.LOGGER.error( - ConfigIO.MARKER, - "Invalid @StringPattern value for {} field - {}", - this.getId(), - e + ConfigIO.MARKER, + "Invalid @StringPattern value for {} field - {}", + this.getId(), + e ); } } @@ -53,12 +52,12 @@ protected String getCorrectedValue(String in) { String defaultValue = this.valueData.getDefaultValue(); if (!this.pattern.matcher(defaultValue).matches()) { throw new IllegalArgumentException( - String.format( - "Invalid config default value '%s' for field '%s' - does not match required pattern \\%s\\", - defaultValue, - this.getId(), - this.pattern.toString() - ) + String.format( + "Invalid config default value '%s' for field '%s' - does not match required pattern \\%s\\", + defaultValue, + this.getId(), + this.pattern.toString() + ) ); } ConfigUtils.logCorrectedMessage(this.getId(), in, defaultValue); @@ -99,11 +98,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new StringValue(ValueData.of(name, (String) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ValueData.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ValueData.java index dcedfb150..3181981d1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ValueData.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ValueData.java @@ -1,16 +1,15 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import org.jetbrains.annotations.Nullable; import java.util.Objects; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; + public final class ValueData implements IDescriptionProvider { private final String id; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java index ad8ed3f07..a5e615949 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java @@ -1,17 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.constant; -import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; -import mod.azure.azurelib.core.object.DataTicket; import net.minecraft.core.Direction; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; @@ -23,6 +16,12 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.core.object.DataTicket; + /** * Stores the default (builtin) {@link DataTicket DataTickets} used in AzureLib.
        * Additionally handles registration of {@link SerializableDataTicket SerializableDataTickets} @@ -32,51 +31,59 @@ public final class DataTickets { // Builtin tickets // These tickets are used by AzureLib by default, usually added in by the GeoRenderer for use in animations public static final DataTicket BLOCK_ENTITY = new DataTicket<>("block_entity", BlockEntity.class); + public static final DataTicket ITEMSTACK = new DataTicket<>("itemstack", ItemStack.class); + public static final DataTicket ENTITY = new DataTicket<>("entity", Entity.class); + public static final DataTicket EQUIPMENT_SLOT = new DataTicket<>( - "equipment_slot", - EquipmentSlot.class + "equipment_slot", + EquipmentSlot.class ); + public static final DataTicket ENTITY_MODEL_DATA = new DataTicket<>( - "entity_model_data", - EntityModelData.class + "entity_model_data", + EntityModelData.class ); + public static final DataTicket TICK = new DataTicket<>("tick", Double.class); + public static final DataTicket ITEM_RENDER_PERSPECTIVE = new DataTicket<>( - "item_render_perspective", - ItemDisplayContext.class + "item_render_perspective", + ItemDisplayContext.class ); + private static final Map> SERIALIZABLE_TICKETS = new ConcurrentHashMap<>(); + // Builtin serializable tickets // These are not used anywhere by default, but are provided as examples // and for ease of use public static final SerializableDataTicket ANIM_STATE = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofInt(AzureLib.modResource("anim_state")) + SerializableDataTicket.ofInt(AzureLib.modResource("anim_state")) ); public static final SerializableDataTicket ANIM = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofString(AzureLib.modResource("anim")) + SerializableDataTicket.ofString(AzureLib.modResource("anim")) ); public static final SerializableDataTicket USE_TICKS = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofInt(AzureLib.modResource("use_ticks")) + SerializableDataTicket.ofInt(AzureLib.modResource("use_ticks")) ); public static final SerializableDataTicket ACTIVE = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofBoolean(AzureLib.modResource("active")) + SerializableDataTicket.ofBoolean(AzureLib.modResource("active")) ); public static final SerializableDataTicket OPEN = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofBoolean(AzureLib.modResource("open")) + SerializableDataTicket.ofBoolean(AzureLib.modResource("open")) ); public static final SerializableDataTicket CLOSED = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofBoolean(AzureLib.modResource("closed")) + SerializableDataTicket.ofBoolean(AzureLib.modResource("closed")) ); public static final SerializableDataTicket DIRECTION = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofEnum(AzureLib.modResource("direction"), Direction.class) + SerializableDataTicket.ofEnum(AzureLib.modResource("direction"), Direction.class) ); private DataTickets() { @@ -100,9 +107,9 @@ public static SerializableDataTicket registerSerializable(SerializableDat if (existingTicket != null) AzureLib.LOGGER.error( - "Duplicate SerializableDataTicket registered! This will cause issues. Existing: {}, New: {}", - existingTicket.id(), - ticket.id() + "Duplicate SerializableDataTicket registered! This will cause issues. Existing: {}, New: {}", + existingTicket.id(), + ticket.id() ); return ticket; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java index 1e318bf3c..1c7ef1c47 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java @@ -1,12 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.constant; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; + +import java.util.function.BiPredicate; +import java.util.function.Function; + import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; import mod.azure.azurelib.common.api.common.animatable.GeoEntity; import mod.azure.azurelib.common.api.common.animatable.GeoItem; @@ -16,12 +20,6 @@ import mod.azure.azurelib.core.animation.AnimationState; import mod.azure.azurelib.core.animation.RawAnimation; import mod.azure.azurelib.core.object.PlayState; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; - -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.Function; /** * Optionally usable class that holds constants for recommended animation paths.
        @@ -101,10 +99,10 @@ public record DefaultAnimations() { *
    */ public static AnimationController basicPredicateController( - T animatable, - RawAnimation optionA, - RawAnimation optionB, - BiPredicate> predicate + T animatable, + RawAnimation optionA, + RawAnimation optionB, + BiPredicate> predicate ) { return new AnimationController<>(animatable, "Generic", 10, state -> { var result = predicate.test(animatable, state); @@ -148,9 +146,9 @@ public static AnimationController genericIdleContro * animation will no longer play */ public static AnimationController getSpawnController( - T animatable, - Function, Object> objectSupplier, - int ticks + T animatable, + Function, Object> objectSupplier, + int ticks ) { return new AnimationController<>(animatable, "Spawn", 0, state -> { if (animatable.getTick(objectSupplier.apply(state)) <= ticks) @@ -183,8 +181,8 @@ public static AnimationController genericWalkContro * @return A new {@link AnimationController} instance to use */ public static AnimationController genericAttackAnimation( - T animatable, - RawAnimation attackAnimation + T animatable, + RawAnimation attackAnimation ) { return new AnimationController<>(animatable, "Attack", 5, state -> { if (animatable.swinging) @@ -202,10 +200,10 @@ public static AnimationController ge */ public static AnimationController genericWalkIdleController(T animatable) { return new AnimationController<>( - animatable, - "Walk/Idle", - 0, - state -> state.setAndContinue(state.isMoving() ? WALK : IDLE) + animatable, + "Walk/Idle", + 0, + state -> state.setAndContinue(state.isMoving() ? WALK : IDLE) ); } @@ -228,10 +226,10 @@ public static AnimationController genericSwimContro */ public static AnimationController genericSwimIdleController(T animatable) { return new AnimationController<>( - animatable, - "Swim/Idle", - 0, - state -> state.setAndContinue(state.isMoving() ? SWIM : IDLE) + animatable, + "Swim/Idle", + 0, + state -> state.setAndContinue(state.isMoving() ? SWIM : IDLE) ); } @@ -249,10 +247,10 @@ public static AnimationController genericFlyControl */ public static AnimationController genericFlyIdleController(T animatable) { return new AnimationController<>( - animatable, - "Fly/Idle", - 0, - state -> state.setAndContinue(state.isMoving() ? FLY : IDLE) + animatable, + "Fly/Idle", + 0, + state -> state.setAndContinue(state.isMoving() ? FLY : IDLE) ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java index 2d85017a6..08512a2ed 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java @@ -1,13 +1,19 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading; import com.google.gson.JsonObject; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.util.GsonHelper; +import org.apache.commons.io.IOUtils; + +import java.io.InputStream; +import java.nio.charset.Charset; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.AzureLibException; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; @@ -17,13 +23,6 @@ import mod.azure.azurelib.core.animation.Animation; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.util.GsonHelper; -import org.apache.commons.io.IOUtils; - -import java.io.InputStream; -import java.nio.charset.Charset; /** * Extracts raw information from given files, and other similar functions @@ -39,7 +38,6 @@ private FileLoader() { * * @param location The resource path of the animations file * @param manager The Minecraft {@code ResourceManager} responsible for maintaining in-memory resource access - * * @deprecated */ public static BakedAnimations loadAnimationsFile(ResourceLocation location, ResourceManager manager) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/FormatVersion.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/FormatVersion.java index 243f36a24..deb137f94 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/FormatVersion.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/FormatVersion.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java index ca3a924be..f6526d4e2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java @@ -1,22 +1,20 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializer; -import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; import java.util.Map; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for cube information, only used in deserialization at startup */ diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Cube.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Cube.java index 7ad2f8f12..25f9cc484 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Cube.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Cube.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,21 +8,22 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for cube information, only used in deserialization at startup */ public record Cube( - @Nullable Double inflate, - @Nullable Boolean mirror, - double[] origin, - double[] pivot, - double[] rotation, - double[] size, - UVUnion uv + @Nullable Double inflate, + @Nullable Boolean mirror, + double[] origin, + double[] pivot, + double[] rotation, + double[] size, + UVUnion uv ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java index dc3ab49bd..a62ec79ef 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,17 +8,18 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for face UV information, only used in deserialization at startup */ public record FaceUV( - @Nullable String materialInstance, - double[] uv, - double[] uvSize + @Nullable String materialInstance, + double[] uv, + double[] uvSize ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorClass.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorClass.java index 1f5dd9d7a..cc2ed2a60 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorClass.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorClass.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,17 +8,18 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for locator class information, only used in deserialization at startup */ public record LocatorClass( - @Nullable Boolean ignoreInheritedScale, - double[] offset, - double[] rotation + @Nullable Boolean ignoreInheritedScale, + double[] offset, + double[] rotation ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorValue.java index 49a1e9563..c157b72b9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorValue.java @@ -1,23 +1,22 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; import com.google.gson.JsonDeserializer; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for locator value information, only used in deserialization at startup */ public record LocatorValue( - @Nullable LocatorClass locatorClass, - double[] values + @Nullable LocatorClass locatorClass, + double[] values ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/MinecraftGeometry.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/MinecraftGeometry.java index 5ee7cc69e..27f01af2a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/MinecraftGeometry.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/MinecraftGeometry.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -11,34 +9,35 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for generic geometry information, only used in deserialization at startup */ public record MinecraftGeometry( - Bone[] bones, - @Nullable String cape, - @Nullable ModelProperties modelProperties + Bone[] bones, + @Nullable String cape, + @Nullable ModelProperties modelProperties ) { public static JsonDeserializer deserializer() throws JsonParseException { return (json, type, context) -> { JsonObject obj = json.getAsJsonObject(); Bone[] bones = JsonUtil.jsonArrayToObjectArray( - GsonHelper.getAsJsonArray(obj, "bones", new JsonArray(0)), - context, - Bone.class + GsonHelper.getAsJsonArray(obj, "bones", new JsonArray(0)), + context, + Bone.class ); String cape = GsonHelper.getAsString(obj, "cape", null); ModelProperties modelProperties = GsonHelper.getAsObject( - obj, - "description", - null, - context, - ModelProperties.class + obj, + "description", + null, + context, + ModelProperties.class ); return new MinecraftGeometry(bones, cape, modelProperties); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Model.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Model.java index 4528960c5..d8f870f70 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Model.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Model.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -11,17 +9,18 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.loading.json.FormatVersion; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.loading.json.FormatVersion; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for model information, only used in deserialization at startup */ public record Model( - @Nullable FormatVersion formatVersion, - MinecraftGeometry[] minecraftGeometry + @Nullable FormatVersion formatVersion, + MinecraftGeometry[] minecraftGeometry ) { public static JsonDeserializer deserializer() throws JsonParseException { @@ -29,9 +28,9 @@ public static JsonDeserializer deserializer() throws JsonParseException { JsonObject obj = json.getAsJsonObject(); FormatVersion formatVersion = context.deserialize(obj.get("format_version"), FormatVersion.class); MinecraftGeometry[] minecraftGeometry = JsonUtil.jsonArrayToObjectArray( - GsonHelper.getAsJsonArray(obj, "minecraft:geometry", new JsonArray(0)), - context, - MinecraftGeometry.class + GsonHelper.getAsJsonArray(obj, "minecraft:geometry", new JsonArray(0)), + context, + MinecraftGeometry.class ); return new Model(formatVersion, minecraftGeometry); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/ModelProperties.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/ModelProperties.java index a70691b53..c9fe245cb 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/ModelProperties.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/ModelProperties.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,31 +8,32 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for model property information, only used in deserialization at startup */ public record ModelProperties( - @Nullable Boolean animationArmsDown, - @Nullable Boolean animationArmsOutFront, - @Nullable Boolean animationDontShowArmor, - @Nullable Boolean animationInvertedCrouch, - @Nullable Boolean animationNoHeadBob, - @Nullable Boolean animationSingleArmAnimation, - @Nullable Boolean animationSingleLegAnimation, - @Nullable Boolean animationStationaryLegs, - @Nullable Boolean animationStatueOfLibertyArms, - @Nullable Boolean animationUpsideDown, - @Nullable String identifier, - @Nullable Boolean preserveModelPose, - double textureHeight, - double textureWidth, - @Nullable Double visibleBoundsHeight, - double[] visibleBoundsOffset, - @Nullable Double visibleBoundsWidth + @Nullable Boolean animationArmsDown, + @Nullable Boolean animationArmsOutFront, + @Nullable Boolean animationDontShowArmor, + @Nullable Boolean animationInvertedCrouch, + @Nullable Boolean animationNoHeadBob, + @Nullable Boolean animationSingleArmAnimation, + @Nullable Boolean animationSingleLegAnimation, + @Nullable Boolean animationStationaryLegs, + @Nullable Boolean animationStatueOfLibertyArms, + @Nullable Boolean animationUpsideDown, + @Nullable String identifier, + @Nullable Boolean preserveModelPose, + double textureHeight, + double textureWidth, + @Nullable Double visibleBoundsHeight, + double[] visibleBoundsOffset, + @Nullable Double visibleBoundsWidth ) { public static JsonDeserializer deserializer() throws JsonParseException { @@ -56,28 +55,28 @@ public static JsonDeserializer deserializer() throws JsonParseE double textureWidth = GsonHelper.getAsDouble(obj, "texture_width"); Double visibleBoundsHeight = JsonUtil.getOptionalDouble(obj, "visible_bounds_height"); double[] visibleBoundsOffset = JsonUtil.jsonArrayToDoubleArray( - GsonHelper.getAsJsonArray(obj, "visible_bounds_offset", null) + GsonHelper.getAsJsonArray(obj, "visible_bounds_offset", null) ); Double visibleBoundsWidth = JsonUtil.getOptionalDouble(obj, "visible_bounds_width"); return new ModelProperties( - animationArmsDown, - animationArmsOutFront, - animationDontShowArmor, - animationInvertedCrouch, - animationNoHeadBob, - animationSingleArmAnimation, - animationSingleLegAnimation, - animationStationaryLegs, - animationStatueOfLibertyArms, - animationUpsideDown, - identifier, - preserveModelPose, - textureHeight, - textureWidth, - visibleBoundsHeight, - visibleBoundsOffset, - visibleBoundsWidth + animationArmsDown, + animationArmsOutFront, + animationDontShowArmor, + animationInvertedCrouch, + animationNoHeadBob, + animationSingleArmAnimation, + animationSingleLegAnimation, + animationStationaryLegs, + animationStatueOfLibertyArms, + animationUpsideDown, + identifier, + preserveModelPose, + textureHeight, + textureWidth, + visibleBoundsHeight, + visibleBoundsOffset, + visibleBoundsWidth ); }; } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolyMesh.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolyMesh.java index ee62603e2..59d7adcf4 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolyMesh.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolyMesh.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,19 +8,20 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for poly mesh information, only used in deserialization at startup */ public record PolyMesh( - @Nullable Boolean normalizedUVs, - double[] normals, - @Nullable PolysUnion polysUnion, - double[] positions, - double[] uvs + @Nullable Boolean normalizedUVs, + double[] normals, + @Nullable PolysUnion polysUnion, + double[] positions, + double[] uvs ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolysUnion.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolysUnion.java index e93250519..a1446027d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolysUnion.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolysUnion.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -11,15 +9,16 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonParseException; import com.google.gson.annotations.SerializedName; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for poly union information, only used in deserialization at startup */ public record PolysUnion( - double[][][] union, - @Nullable Type type + double[][][] union, + @Nullable Type type ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/TextureMesh.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/TextureMesh.java index b6c3fc8f1..2b3d783f5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/TextureMesh.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/TextureMesh.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,19 +8,20 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for texture mesh information, only used in deserialization at startup */ public record TextureMesh( - double[] localPivot, - double[] position, - double[] rotation, - double[] scale, - @Nullable String texture + double[] localPivot, + double[] position, + double[] rotation, + double[] scale, + @Nullable String texture ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVFaces.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVFaces.java index c01cd4764..081325cfb 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVFaces.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVFaces.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -17,12 +15,12 @@ * Container class for UV face information, only used in deserialization at startup */ public record UVFaces( - @Nullable FaceUV north, - @Nullable FaceUV south, - @Nullable FaceUV east, - @Nullable FaceUV west, - @Nullable FaceUV up, - @Nullable FaceUV down + @Nullable FaceUV north, + @Nullable FaceUV south, + @Nullable FaceUV east, + @Nullable FaceUV west, + @Nullable FaceUV up, + @Nullable FaceUV down ) { public static JsonDeserializer deserializer() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVUnion.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVUnion.java index 9f6331edb..9b6545be1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVUnion.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVUnion.java @@ -1,24 +1,23 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; import com.google.gson.JsonDeserializer; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for UV information, only used in deserialization at startup */ public record UVUnion( - double[] boxUVCoords, - @Nullable UVFaces faceUV, - boolean isBoxUV + double[] boxUVCoords, + @Nullable UVFaces faceUV, + boolean isBoxUV ) { public static JsonDeserializer deserializer() throws JsonParseException { @@ -29,7 +28,7 @@ public static JsonDeserializer deserializer() throws JsonParseException return new UVUnion(JsonUtil.jsonArrayToDoubleArray(json.getAsJsonArray()), null, true); } else { throw new JsonParseException( - "Invalid format provided for UVUnion, must be either double array or UVFaces collection" + "Invalid format provided for UVUnion, must be either double array or UVFaces collection" ); } }; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/BakedAnimationsAdapter.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/BakedAnimationsAdapter.java index bb34bdb0e..1a192181d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/BakedAnimationsAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/BakedAnimationsAdapter.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.typeadapter; @@ -11,6 +9,14 @@ import com.mojang.datafixers.util.Pair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import org.apache.commons.lang3.math.NumberUtils; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; import mod.azure.azurelib.common.internal.common.util.JsonUtil; @@ -24,13 +30,6 @@ import mod.azure.azurelib.core.molang.MolangException; import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.expressions.MolangValue; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.GsonHelper; -import org.apache.commons.lang3.math.NumberUtils; - -import java.lang.reflect.Type; -import java.util.List; -import java.util.Map; /** * {@link com.google.gson.Gson} {@link JsonDeserializer} for {@link BakedAnimations}.
    @@ -79,11 +78,14 @@ private static Pair getTripletObjBedrock(String timestamp, if (keyframe.has("pre")) { JsonElement pre = keyframe.get("pre"); - keyframeValues = pre.isJsonArray() ? pre.getAsJsonArray() : GsonHelper.getAsJsonArray(pre.getAsJsonObject(), "vector"); - } - else if (keyframe.has("post")) { + keyframeValues = pre.isJsonArray() + ? pre.getAsJsonArray() + : GsonHelper.getAsJsonArray(pre.getAsJsonObject(), "vector"); + } else if (keyframe.has("post")) { JsonElement post = keyframe.get("post"); - keyframeValues = post.isJsonArray() ? post.getAsJsonArray() : GsonHelper.getAsJsonArray(post.getAsJsonObject(), "vector"); + keyframeValues = post.isJsonArray() + ? post.getAsJsonArray() + : GsonHelper.getAsJsonArray(post.getAsJsonObject(), "vector"); } if (keyframeValues != null) @@ -106,9 +108,9 @@ private static double calculateAnimationLength(BoneAnimation[] boneAnimations) { @Override public BakedAnimations deserialize( - JsonElement json, - Type type, - JsonDeserializationContext context + JsonElement json, + Type type, + JsonDeserializationContext context ) throws JsonParseException { JsonObject jsonObj = json.getAsJsonObject(); @@ -124,10 +126,10 @@ public BakedAnimations deserialize( String ani = animName.getAsString(); if (includes.containsKey(ani)) { AzureLib.LOGGER.warn( - "Animation {} is already included! File already including: {} File trying to include from again: {}", - ani, - includes.get(ani), - fileId + "Animation {} is already included! File already including: {} File trying to include from again: {}", + ani, + includes.get(ani), + fileId ); } else { includes.put(ani, fileId); @@ -141,8 +143,8 @@ public BakedAnimations deserialize( for (Map.Entry entry : animationJsonList.entrySet()) { try { animations.put( - entry.getKey(), - bakeAnimation(entry.getKey(), entry.getValue().getAsJsonObject(), context) + entry.getKey(), + bakeAnimation(entry.getKey(), entry.getValue().getAsJsonObject(), context) ); } catch (MolangException ex) { AzureLib.LOGGER.error("Unable to parse animation: {}", entry.getKey()); @@ -154,16 +156,16 @@ public BakedAnimations deserialize( } private Animation bakeAnimation( - String name, - JsonObject animationObj, - JsonDeserializationContext context + String name, + JsonObject animationObj, + JsonDeserializationContext context ) throws MolangException { double length = animationObj.has("animation_length") - ? GsonHelper.getAsDouble(animationObj, "animation_length") * 20d - : -1; + ? GsonHelper.getAsDouble(animationObj, "animation_length") * 20d + : -1; Animation.LoopType loopType = Animation.LoopType.fromJson(animationObj.get("loop")); BoneAnimation[] boneAnimations = bakeBoneAnimations( - GsonHelper.getAsJsonObject(animationObj, "bones", new JsonObject()) + GsonHelper.getAsJsonObject(animationObj, "bones", new JsonObject()) ); Animation.Keyframes keyframes = context.deserialize(animationObj, Animation.Keyframes.class); @@ -180,16 +182,16 @@ private BoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangExc for (Map.Entry entry : bonesObj.entrySet()) { JsonObject entryObj = entry.getValue().getAsJsonObject(); KeyframeStack> scaleFrames = buildKeyframeStack( - getTripletObj(entryObj.get("scale")), - false + getTripletObj(entryObj.get("scale")), + false ); KeyframeStack> positionFrames = buildKeyframeStack( - getTripletObj(entryObj.get("position")), - false + getTripletObj(entryObj.get("position")), + false ); KeyframeStack> rotationFrames = buildKeyframeStack( - getTripletObj(entryObj.get("rotation")), - true + getTripletObj(entryObj.get("rotation")), + true ); animations[index] = new BoneAnimation(entry.getKey(), rotationFrames, positionFrames, scaleFrames); @@ -200,8 +202,8 @@ private BoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangExc } private KeyframeStack> buildKeyframeStack( - List> entries, - boolean isForRotation + List> entries, + boolean isForRotation ) throws MolangException { if (entries.isEmpty()) return new KeyframeStack<>(); @@ -227,40 +229,40 @@ private KeyframeStack> buildKeyframeStack( double timeDelta = curTime - prevTime; JsonArray keyFrameVector = element instanceof JsonArray array - ? array - : GsonHelper.getAsJsonArray(element.getAsJsonObject(), "vector"); + ? array + : GsonHelper.getAsJsonArray(element.getAsJsonObject(), "vector"); MolangValue rawXValue = MolangParser.parseJson(keyFrameVector.get(0)); MolangValue rawYValue = MolangParser.parseJson(keyFrameVector.get(1)); MolangValue rawZValue = MolangParser.parseJson(keyFrameVector.get(2)); IValue xValue = isForRotation && rawXValue.isConstant() - ? new Constant(Math.toRadians(-rawXValue.get())) - : rawXValue; + ? new Constant(Math.toRadians(-rawXValue.get())) + : rawXValue; IValue yValue = isForRotation && rawYValue.isConstant() - ? new Constant(Math.toRadians(-rawYValue.get())) - : rawYValue; + ? new Constant(Math.toRadians(-rawYValue.get())) + : rawYValue; IValue zValue = isForRotation && rawZValue.isConstant() - ? new Constant(Math.toRadians(rawZValue.get())) - : rawZValue; + ? new Constant(Math.toRadians(rawZValue.get())) + : rawZValue; JsonObject entryObj = element instanceof JsonObject obj ? obj : null; EasingType easingType = entryObj != null && entryObj.has("easing") - ? EasingType.fromJson(entryObj.get("easing")) - : EasingType.LINEAR; + ? EasingType.fromJson(entryObj.get("easing")) + : EasingType.LINEAR; List easingArgs = entryObj != null && entryObj.has("easingArgs") - ? JsonUtil.jsonArrayToList( + ? JsonUtil.jsonArrayToList( GsonHelper.getAsJsonArray(entryObj, "easingArgs"), ele -> new Constant(ele.getAsDouble()) - ) - : new ObjectArrayList<>(); + ) + : new ObjectArrayList<>(); xFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) ); yFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) ); zFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) ); xPrev = xValue; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/KeyFramesAdapter.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/KeyFramesAdapter.java index 00e22b14d..571859db1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/KeyFramesAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/KeyFramesAdapter.java @@ -1,23 +1,22 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.typeadapter; import com.google.gson.*; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.util.GsonHelper; + +import java.lang.reflect.Type; +import java.util.Map; + import mod.azure.azurelib.common.internal.common.util.JsonUtil; import mod.azure.azurelib.core.animation.Animation; import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; -import net.minecraft.util.GsonHelper; - -import java.lang.reflect.Type; -import java.util.Map; /** * {@link Gson} {@link JsonDeserializer} for {@link Animation.Keyframes}.
    @@ -32,8 +31,8 @@ private static SoundKeyframeData[] buildSoundFrameData(JsonObject rootObj) { for (Map.Entry entry : soundsObj.entrySet()) { sounds[index] = new SoundKeyframeData( - Double.parseDouble(entry.getKey()) * 20d, - GsonHelper.getAsString(entry.getValue().getAsJsonObject(), "effect") + Double.parseDouble(entry.getKey()) * 20d, + GsonHelper.getAsString(entry.getValue().getAsJsonObject(), "effect") ); index++; } @@ -53,10 +52,10 @@ private static ParticleKeyframeData[] buildParticleFrameData(JsonObject rootObj) String script = GsonHelper.getAsString(obj, "pre_effect_script", ""); particles[index] = new ParticleKeyframeData( - Double.parseDouble(entry.getKey()) * 20d, - effect, - locator, - script + Double.parseDouble(entry.getKey()) * 20d, + effect, + locator, + script ); index++; } @@ -67,7 +66,7 @@ private static ParticleKeyframeData[] buildParticleFrameData(JsonObject rootObj) private static CustomInstructionKeyframeData[] buildCustomFrameData(JsonObject rootObj) { JsonObject customInstructionsObj = GsonHelper.getAsJsonObject(rootObj, "timeline", new JsonObject()); CustomInstructionKeyframeData[] customInstructions = new CustomInstructionKeyframeData[customInstructionsObj - .size()]; + .size()]; int index = 0; for (Map.Entry entry : customInstructionsObj.entrySet()) { @@ -80,8 +79,8 @@ private static CustomInstructionKeyframeData[] buildCustomFrameData(JsonObject r } customInstructions[index] = new CustomInstructionKeyframeData( - Double.parseDouble(entry.getKey()) * 20d, - instructions + Double.parseDouble(entry.getKey()) * 20d, + instructions ); index++; } @@ -91,9 +90,9 @@ private static CustomInstructionKeyframeData[] buildCustomFrameData(JsonObject r @Override public Animation.Keyframes deserialize( - JsonElement json, - Type type, - JsonDeserializationContext context + JsonElement json, + Type type, + JsonDeserializationContext context ) throws JsonParseException { JsonObject obj = json.getAsJsonObject(); SoundKeyframeData[] sounds = buildSoundFrameData(obj); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedAnimations.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedAnimations.java index c42b2c95c..a6834e440 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedAnimations.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedAnimations.java @@ -1,26 +1,25 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.object; -import mod.azure.azurelib.core.animation.Animation; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; import java.util.Map; +import mod.azure.azurelib.core.animation.Animation; + /** * Container object that holds a deserialized map of {@link Animation Animations}.
    * Kept as a unique object so that it can be registered as a {@link com.google.gson.JsonDeserializer deserializer} for * {@link com.google.gson.Gson Gson} */ public record BakedAnimations( - Map animations, - Map includes + Map animations, + Map includes ) { /** diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java index 53fa77ea5..bea1c1372 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java @@ -1,18 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.object; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.common.internal.common.loading.json.raw.*; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; import net.minecraft.core.Direction; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; @@ -20,6 +14,11 @@ import java.util.List; import java.util.Map; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.common.internal.common.loading.json.raw.*; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; + /** * Base interface for a factory of {@link BakedGeoModel} objects. Handled by default by AzureLib, but custom * implementations may be added by other mods for special needs @@ -77,12 +76,12 @@ static void register(String namespace, BakedModelFactory factory) { * Vertices have already been mirrored here if {@code mirror} is true */ default GeoQuad[] buildQuads( - UVUnion uvUnion, - VertexSet vertices, - Cube cube, - float textureWidth, - float textureHeight, - boolean mirror + UVUnion uvUnion, + VertexSet vertices, + Cube cube, + float textureWidth, + float textureHeight, + boolean mirror ) { GeoQuad[] quads = new GeoQuad[6]; @@ -100,13 +99,13 @@ default GeoQuad[] buildQuads( * Build an individual quad */ default GeoQuad buildQuad( - VertexSet vertices, - Cube cube, - UVUnion uvUnion, - float textureWidth, - float textureHeight, - boolean mirror, - Direction direction + VertexSet vertices, + Cube cube, + UVUnion uvUnion, + float textureWidth, + float textureHeight, + boolean mirror, + Direction direction ) { if (!uvUnion.isBoxUV()) { FaceUV faceUV = uvUnion.faceUV().fromDirection(direction); @@ -115,13 +114,13 @@ default GeoQuad buildQuad( return null; return GeoQuad.build( - vertices.verticesForQuad(direction, false, mirror || cube.mirror() == Boolean.TRUE), - faceUV.uv(), - faceUV.uvSize(), - textureWidth, - textureHeight, - mirror, - direction + vertices.verticesForQuad(direction, false, mirror || cube.mirror() == Boolean.TRUE), + faceUV.uv(), + faceUV.uvSize(), + textureWidth, + textureHeight, + mirror, + direction ); } @@ -129,40 +128,40 @@ default GeoQuad buildQuad( double[] uvSize = cube.size(); Vec3 uvSizeVec = new Vec3(Math.floor(uvSize[0]), Math.floor(uvSize[1]), Math.floor(uvSize[2])); double[][] uvData = switch (direction) { - case WEST -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.z, uvSizeVec.y} + case WEST -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.z, uvSizeVec.y } }; - case EAST -> new double[][]{ - new double[]{uv[0], uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.z, uvSizeVec.y} + case EAST -> new double[][] { + new double[] { uv[0], uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.z, uvSizeVec.y } }; - case NORTH -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.x, uvSizeVec.y} + case NORTH -> new double[][] { + new double[] { uv[0] + uvSizeVec.z, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, uvSizeVec.y } }; - case SOUTH -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x + uvSizeVec.z, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.x, uvSizeVec.y} + case SOUTH -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x + uvSizeVec.z, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, uvSizeVec.y } }; - case UP -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z, uv[1]}, - new double[]{uvSizeVec.x, uvSizeVec.z} + case UP -> new double[][] { + new double[] { uv[0] + uvSizeVec.z, uv[1] }, + new double[] { uvSizeVec.x, uvSizeVec.z } }; - case DOWN -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.x, -uvSizeVec.z} + case DOWN -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, -uvSizeVec.z } }; }; return GeoQuad.build( - vertices.verticesForQuad(direction, true, mirror || cube.mirror() == Boolean.TRUE), - uvData[0], - uvData[1], - textureWidth, - textureHeight, - mirror, - direction + vertices.verticesForQuad(direction, true, mirror || cube.mirror() == Boolean.TRUE), + uvData[0], + uvData[1], + textureWidth, + textureHeight, + mirror, + direction ); } @@ -183,20 +182,20 @@ public BakedGeoModel constructGeoModel(GeometryTree geometryTree) { public GeoBone constructBone(BoneStructure boneStructure, ModelProperties properties, GeoBone parent) { Bone bone = boneStructure.self(); GeoBone newBone = new GeoBone( - parent, - bone.name(), - bone.mirror(), - bone.inflate(), - bone.neverRender(), - bone.reset() + parent, + bone.name(), + bone.mirror(), + bone.inflate(), + bone.neverRender(), + bone.reset() ); Vec3 rotation = RenderUtils.arrayToVec(bone.rotation()); Vec3 pivot = RenderUtils.arrayToVec(bone.pivot()); newBone.updateRotation( - (float) Math.toRadians(-rotation.x), - (float) Math.toRadians(-rotation.y), - (float) Math.toRadians(rotation.z) + (float) Math.toRadians(-rotation.x), + (float) Math.toRadians(-rotation.y), + (float) Math.toRadians(rotation.z) ); newBone.updatePivot((float) -pivot.x, (float) pivot.y, (float) pivot.z); @@ -215,8 +214,8 @@ public GeoBone constructBone(BoneStructure boneStructure, ModelProperties proper public GeoCube constructCube(Cube cube, ModelProperties properties, GeoBone bone) { boolean mirror = cube.mirror() == Boolean.TRUE; double inflate = cube.inflate() != null - ? cube.inflate() / 16f - : (bone.getInflate() == null ? 0 : bone.getInflate() / 16f); + ? cube.inflate() / 16f + : (bone.getInflate() == null ? 0 : bone.getInflate() / 16f); Vec3 size = RenderUtils.arrayToVec(cube.size()); Vec3 origin = RenderUtils.arrayToVec(cube.origin()); Vec3 rotation = RenderUtils.arrayToVec(cube.rotation()); @@ -227,12 +226,12 @@ public GeoCube constructCube(Cube cube, ModelProperties properties, GeoBone bone pivot = pivot.multiply(-1, 1, 1); rotation = new Vec3(Math.toRadians(-rotation.x), Math.toRadians(-rotation.y), Math.toRadians(rotation.z)); GeoQuad[] quads = buildQuads( - cube.uv(), - new VertexSet(origin, vertexSize, inflate), - cube, - (float) properties.textureWidth(), - (float) properties.textureHeight(), - mirror + cube.uv(), + new VertexSet(origin, vertexSize, inflate), + cube, + (float) properties.textureWidth(), + (float) properties.textureHeight(), + mirror ); return new GeoCube(quads, pivot, rotation, size, inflate, mirror); @@ -243,42 +242,42 @@ public GeoCube constructCube(Cube cube, ModelProperties properties, GeoBone bone * Holder class to make it easier to store and refer to vertices for a given cube */ record VertexSet( - GeoVertex bottomLeftBack, - GeoVertex bottomRightBack, - GeoVertex topLeftBack, - GeoVertex topRightBack, - GeoVertex topLeftFront, - GeoVertex topRightFront, - GeoVertex bottomLeftFront, - GeoVertex bottomRightFront + GeoVertex bottomLeftBack, + GeoVertex bottomRightBack, + GeoVertex topLeftBack, + GeoVertex topRightBack, + GeoVertex topLeftFront, + GeoVertex topRightFront, + GeoVertex bottomLeftFront, + GeoVertex bottomRightFront ) { public VertexSet(Vec3 origin, Vec3 vertexSize, double inflation) { this( - new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z - inflation), - new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z + vertexSize.z + inflation), - new GeoVertex(origin.x - inflation, origin.y + vertexSize.y + inflation, origin.z - inflation), - new GeoVertex( - origin.x - inflation, - origin.y + vertexSize.y + inflation, - origin.z + vertexSize.z + inflation - ), - new GeoVertex( - origin.x + vertexSize.x + inflation, - origin.y + vertexSize.y + inflation, - origin.z - inflation - ), - new GeoVertex( - origin.x + vertexSize.x + inflation, - origin.y + vertexSize.y + inflation, - origin.z + vertexSize.z + inflation - ), - new GeoVertex(origin.x + vertexSize.x + inflation, origin.y - inflation, origin.z - inflation), - new GeoVertex( - origin.x + vertexSize.x + inflation, - origin.y - inflation, - origin.z + vertexSize.z + inflation - ) + new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z - inflation), + new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z + vertexSize.z + inflation), + new GeoVertex(origin.x - inflation, origin.y + vertexSize.y + inflation, origin.z - inflation), + new GeoVertex( + origin.x - inflation, + origin.y + vertexSize.y + inflation, + origin.z + vertexSize.z + inflation + ), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y + vertexSize.y + inflation, + origin.z - inflation + ), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y + vertexSize.y + inflation, + origin.z + vertexSize.z + inflation + ), + new GeoVertex(origin.x + vertexSize.x + inflation, origin.y - inflation, origin.z - inflation), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y - inflation, + origin.z + vertexSize.z + inflation + ) ); } @@ -286,54 +285,54 @@ public VertexSet(Vec3 origin, Vec3 vertexSize, double inflation) { * Returns the normal vertex array for a west-facing quad */ public GeoVertex[] quadWest() { - return new GeoVertex[]{this.topRightBack, this.topLeftBack, this.bottomLeftBack, this.bottomRightBack}; + return new GeoVertex[] { this.topRightBack, this.topLeftBack, this.bottomLeftBack, this.bottomRightBack }; } /** * Returns the normal vertex array for an east-facing quad */ public GeoVertex[] quadEast() { - return new GeoVertex[]{ - this.topLeftFront, - this.topRightFront, - this.bottomRightFront, - this.bottomLeftFront}; + return new GeoVertex[] { + this.topLeftFront, + this.topRightFront, + this.bottomRightFront, + this.bottomLeftFront }; } /** * Returns the normal vertex array for a north-facing quad */ public GeoVertex[] quadNorth() { - return new GeoVertex[]{this.topLeftBack, this.topLeftFront, this.bottomLeftFront, this.bottomLeftBack}; + return new GeoVertex[] { this.topLeftBack, this.topLeftFront, this.bottomLeftFront, this.bottomLeftBack }; } /** * Returns the normal vertex array for a south-facing quad */ public GeoVertex[] quadSouth() { - return new GeoVertex[]{ - this.topRightFront, - this.topRightBack, - this.bottomRightBack, - this.bottomRightFront}; + return new GeoVertex[] { + this.topRightFront, + this.topRightBack, + this.bottomRightBack, + this.bottomRightFront }; } /** * Returns the normal vertex array for a top-facing quad */ public GeoVertex[] quadUp() { - return new GeoVertex[]{this.topRightBack, this.topRightFront, this.topLeftFront, this.topLeftBack}; + return new GeoVertex[] { this.topRightBack, this.topRightFront, this.topLeftFront, this.topLeftBack }; } /** * Returns the normal vertex array for a bottom-facing quad */ public GeoVertex[] quadDown() { - return new GeoVertex[]{ - this.bottomLeftBack, - this.bottomLeftFront, - this.bottomRightFront, - this.bottomRightBack}; + return new GeoVertex[] { + this.bottomLeftBack, + this.bottomLeftFront, + this.bottomRightFront, + this.bottomRightBack }; } /** diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BoneStructure.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BoneStructure.java index 631c8fc3d..cf24a6a14 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BoneStructure.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BoneStructure.java @@ -1,23 +1,22 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.object; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.internal.common.loading.json.raw.Bone; import java.util.Map; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Bone; + /** * Container class for holding a {@link Bone} structure. Used at startup in deserialization */ public record BoneStructure( - Bone self, - Map children + Bone self, + Map children ) { public BoneStructure(Bone self) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/GeometryTree.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/GeometryTree.java index db382b860..a2c94c1eb 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/GeometryTree.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/GeometryTree.java @@ -1,28 +1,27 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.object; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +import java.util.List; +import java.util.Map; + import mod.azure.azurelib.common.internal.common.loading.json.raw.Bone; import mod.azure.azurelib.common.internal.common.loading.json.raw.MinecraftGeometry; import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; import mod.azure.azurelib.common.internal.common.loading.json.raw.ModelProperties; -import java.util.List; -import java.util.Map; - /** * Container class for a {@link Bone} structure, used at startup during deserialization */ public record GeometryTree( - Map topLevelBones, - ModelProperties properties + Map topLevelBones, + ModelProperties properties ) { public static GeometryTree fromModel(Model model) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/AbstractPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/AbstractPacket.java index 2ed3c85c5..0aa84f979 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/AbstractPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/AbstractPacket.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java index 047713e9b..6952e0c03 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java @@ -1,29 +1,30 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.core.object.DataTicket; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.core.object.DataTicket; + /** * Network-compatible {@link DataTicket} implementation. Used for sending data from server -> client in an easy manner */ public abstract class SerializableDataTicket extends DataTicket { - public static final StreamCodec> STREAM_CODEC = StreamCodec.composite( + public static final StreamCodec> STREAM_CODEC = StreamCodec + .composite( ByteBufCodecs.STRING_UTF8, SerializableDataTicket::id, - DataTickets::byName); + DataTickets::byName + ); protected SerializableDataTicket(String id, Class objectType) { super(id, objectType); @@ -36,6 +37,7 @@ protected SerializableDataTicket(String id, Class objectType) { */ public static SerializableDataTicket ofDouble(ResourceLocation id) { return new SerializableDataTicket<>(id.toString(), Double.class) { + @Override public StreamCodec streamCodec() { return ByteBufCodecs.DOUBLE; @@ -52,6 +54,7 @@ public StreamCodec streamCodec() { */ public static SerializableDataTicket ofFloat(ResourceLocation id) { return new SerializableDataTicket<>(id.toString(), Float.class) { + @Override public StreamCodec streamCodec() { return ByteBufCodecs.FLOAT; @@ -66,6 +69,7 @@ public StreamCodec streamCodec() { */ public static SerializableDataTicket ofBoolean(ResourceLocation id) { return new SerializableDataTicket<>(id.toString(), Boolean.class) { + @Override public StreamCodec streamCodec() { return ByteBufCodecs.BOOL; @@ -80,6 +84,7 @@ public StreamCodec streamCodec() { */ public static SerializableDataTicket ofInt(ResourceLocation id) { return new SerializableDataTicket<>(id.toString(), Integer.class) { + @Override public StreamCodec streamCodec() { return ByteBufCodecs.VAR_INT; @@ -94,6 +99,7 @@ public StreamCodec streamCodec() { */ public static SerializableDataTicket ofString(ResourceLocation id) { return new SerializableDataTicket<>(id.toString(), String.class) { + @Override public StreamCodec streamCodec() { return ByteBufCodecs.STRING_UTF8; @@ -108,8 +114,10 @@ public StreamCodec streamCodec() { */ public static > SerializableDataTicket ofEnum(ResourceLocation id, Class enumClass) { return new SerializableDataTicket<>(id.toString(), enumClass) { + public StreamCodec streamCodec() { return new StreamCodec<>() { + @Override public @NotNull E decode(@NotNull RegistryFriendlyByteBuf buf) { return Enum.valueOf(enumClass, buf.readUtf()); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java index 79b9a6bce..c991aa3fa 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java @@ -1,43 +1,54 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import org.jetbrains.annotations.NotNull; + import mod.azure.azurelib.common.api.client.helper.ClientUtils; import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; import mod.azure.azurelib.common.internal.common.network.AbstractPacket; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import mod.azure.azurelib.core.animatable.GeoAnimatable; -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import org.jetbrains.annotations.NotNull; /** * Packet for syncing user-definable animation data for {@link SingletonGeoAnimatable} instances */ -public record AnimDataSyncPacket(String syncableId, long instanceId, SerializableDataTicket dataTicket, - D data) implements AbstractPacket { +public record AnimDataSyncPacket( + String syncableId, + long instanceId, + SerializableDataTicket dataTicket, + D data +) implements AbstractPacket { public static final CustomPacketPayload.Type> TYPE = new Type<>( - AzureLibNetwork.ANIM_DATA_SYNC_PACKET_ID); + AzureLibNetwork.ANIM_DATA_SYNC_PACKET_ID + ); + public static final StreamCodec> CODEC = StreamCodec.of( - (buf, packet) -> { - SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); - buf.writeUtf(packet.syncableId); - buf.writeVarLong(packet.instanceId); - ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); - }, buf -> { - final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); - - return new AnimDataSyncPacket<>(buf.readUtf(), buf.readVarLong(), dataTicket, - dataTicket.streamCodec().decode(buf)); - }); + (buf, packet) -> { + SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); + buf.writeUtf(packet.syncableId); + buf.writeVarLong(packet.instanceId); + ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); + }, + buf -> { + final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); + + return new AnimDataSyncPacket<>( + buf.readUtf(), + buf.readVarLong(), + dataTicket, + dataTicket.streamCodec().decode(buf) + ); + } + ); @Override public void handle() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java index 35660559c..07ed0b95f 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java @@ -1,33 +1,46 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimatableManager; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimatableManager; + /** * Packet for syncing user-definable animations that can be triggered from the server */ -public record AnimTriggerPacket(String syncableId, long instanceId, String controllerName, - String animName) implements AbstractPacket { +public record AnimTriggerPacket( + String syncableId, + long instanceId, + String controllerName, + String animName +) implements AbstractPacket { + public static final CustomPacketPayload.Type TYPE = new Type<>( - AzureLibNetwork.ANIM_TRIGGER_SYNC_PACKET_ID); + AzureLibNetwork.ANIM_TRIGGER_SYNC_PACKET_ID + ); + public static final StreamCodec CODEC = StreamCodec.composite( - ByteBufCodecs.STRING_UTF8, AnimTriggerPacket::syncableId, ByteBufCodecs.VAR_LONG, - AnimTriggerPacket::instanceId, ByteBufCodecs.STRING_UTF8, AnimTriggerPacket::controllerName, - ByteBufCodecs.STRING_UTF8, AnimTriggerPacket::animName, AnimTriggerPacket::new); + ByteBufCodecs.STRING_UTF8, + AnimTriggerPacket::syncableId, + ByteBufCodecs.VAR_LONG, + AnimTriggerPacket::instanceId, + ByteBufCodecs.STRING_UTF8, + AnimTriggerPacket::controllerName, + ByteBufCodecs.STRING_UTF8, + AnimTriggerPacket::animName, + AnimTriggerPacket::new + ); @Override public void handle() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java index 4f6cf0436..c89a11c36 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java @@ -1,17 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; -import mod.azure.azurelib.common.api.client.helper.ClientUtils; -import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.minecraft.core.BlockPos; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; @@ -19,24 +12,41 @@ import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + /** * Packet for syncing user-definable animation data for {@link BlockEntity BlockEntities} */ -public record BlockEntityAnimDataSyncPacket(BlockPos blockPos, SerializableDataTicket dataTicket, - D data) implements AbstractPacket { +public record BlockEntityAnimDataSyncPacket( + BlockPos blockPos, + SerializableDataTicket dataTicket, + D data +) implements AbstractPacket { + public static final CustomPacketPayload.Type> TYPE = new Type<>( - AzureLibNetwork.BLOCK_ENTITY_ANIM_DATA_SYNC_PACKET_ID); + AzureLibNetwork.BLOCK_ENTITY_ANIM_DATA_SYNC_PACKET_ID + ); + public static final StreamCodec> CODEC = StreamCodec.of( - (buf, packet) -> { - SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); - buf.writeBlockPos(packet.blockPos); - ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); - }, buf -> { - final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); - - return new BlockEntityAnimDataSyncPacket<>(buf.readBlockPos(), dataTicket, - dataTicket.streamCodec().decode(buf)); - }); + (buf, packet) -> { + SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); + buf.writeBlockPos(packet.blockPos); + ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); + }, + buf -> { + final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); + + return new BlockEntityAnimDataSyncPacket<>( + buf.readBlockPos(), + dataTicket, + dataTicket.streamCodec().decode(buf) + ); + } + ); @Override public void handle() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java index eb7e9da42..0643f2cfe 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java @@ -1,16 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; -import mod.azure.azurelib.common.api.client.helper.ClientUtils; -import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; @@ -20,22 +14,34 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + /** * Packet for syncing user-definable animations that can be triggered from the server for * {@link net.minecraft.world.level.block.entity.BlockEntity BlockEntities} */ -public record BlockEntityAnimTriggerPacket(BlockPos blockPos, @Nullable String controllerName, - String animName) implements AbstractPacket { +public record BlockEntityAnimTriggerPacket( + BlockPos blockPos, + @Nullable String controllerName, + String animName +) implements AbstractPacket { + public static final CustomPacketPayload.Type TYPE = new Type<>( - AzureLibNetwork.BLOCK_ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID); + AzureLibNetwork.BLOCK_ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID + ); + public static final StreamCodec CODEC = StreamCodec.composite( - BlockPos.STREAM_CODEC, - BlockEntityAnimTriggerPacket::blockPos, - ByteBufCodecs.STRING_UTF8, - BlockEntityAnimTriggerPacket::controllerName, - ByteBufCodecs.STRING_UTF8, - BlockEntityAnimTriggerPacket::animName, - BlockEntityAnimTriggerPacket::new); + BlockPos.STREAM_CODEC, + BlockEntityAnimTriggerPacket::blockPos, + ByteBufCodecs.STRING_UTF8, + BlockEntityAnimTriggerPacket::controllerName, + ByteBufCodecs.STRING_UTF8, + BlockEntityAnimTriggerPacket::animName, + BlockEntityAnimTriggerPacket::new + ); @Override public void handle() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java index a8f425e2c..8dfe07ef8 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java @@ -1,12 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.NotNull; + import mod.azure.azurelib.common.api.client.helper.ClientUtils; import mod.azure.azurelib.common.api.common.animatable.GeoEntity; import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; @@ -14,38 +18,48 @@ import mod.azure.azurelib.common.internal.common.network.AbstractPacket; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; import mod.azure.azurelib.common.platform.services.AzureLibNetwork; -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.world.entity.Entity; -import org.jetbrains.annotations.NotNull; /** * Packet for syncing user-definable animation data for {@link net.minecraft.world.entity.Entity Entities} */ -public record EntityAnimDataSyncPacket(int entityId, boolean isReplacedEntity, SerializableDataTicket dataTicket, - D data) implements AbstractPacket { +public record EntityAnimDataSyncPacket( + int entityId, + boolean isReplacedEntity, + SerializableDataTicket dataTicket, + D data +) implements AbstractPacket { + public static final CustomPacketPayload.Type> TYPE = new Type<>( - AzureLibNetwork.ENTITY_ANIM_DATA_SYNC_PACKET_ID); + AzureLibNetwork.ENTITY_ANIM_DATA_SYNC_PACKET_ID + ); + public static final StreamCodec> CODEC = StreamCodec.of( - (buf, packet) -> { - SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); - buf.writeVarInt(packet.entityId); - buf.writeBoolean(packet.isReplacedEntity); - ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); - }, buf -> { - final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); - - return new EntityAnimDataSyncPacket<>(buf.readVarInt(), buf.readBoolean(), dataTicket, - dataTicket.streamCodec().decode(buf)); - }); + (buf, packet) -> { + SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); + buf.writeVarInt(packet.entityId); + buf.writeBoolean(packet.isReplacedEntity); + ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); + }, + buf -> { + final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); + + return new EntityAnimDataSyncPacket<>( + buf.readVarInt(), + buf.readBoolean(), + dataTicket, + dataTicket.streamCodec().decode(buf) + ); + } + ); @Override public void handle() { Entity entity = ClientUtils.getLevel().getEntity(this.entityId); - if (entity == null) return; + if (entity == null) + return; if (!this.isReplacedEntity) { - if (entity instanceof GeoEntity geoEntity) geoEntity.setAnimData(this.dataTicket, this.data); + if (entity instanceof GeoEntity geoEntity) + geoEntity.setAnimData(this.dataTicket, this.data); return; } if (RenderUtils.getReplacedAnimatable(entity.getType()) instanceof GeoReplacedEntity replacedEntity) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java index fd6d32d11..344237cd9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java @@ -1,18 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; -import mod.azure.azurelib.common.api.client.helper.ClientUtils; -import mod.azure.azurelib.common.api.common.animatable.GeoEntity; -import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; @@ -20,24 +12,39 @@ import net.minecraft.world.entity.Entity; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.api.common.animatable.GeoEntity; +import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + /** * Packet for syncing user-definable animations that can be triggered from the server for * {@link net.minecraft.world.entity.Entity Entities} */ -public record EntityAnimTriggerPacket(int entityId, boolean isReplacedEntity, String controllerName, - String animName) implements AbstractPacket { +public record EntityAnimTriggerPacket( + int entityId, + boolean isReplacedEntity, + String controllerName, + String animName +) implements AbstractPacket { + public static final CustomPacketPayload.Type TYPE = new Type<>( - AzureLibNetwork.ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID); + AzureLibNetwork.ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID + ); + public static final StreamCodec CODEC = StreamCodec.composite( - ByteBufCodecs.VAR_INT, - EntityAnimTriggerPacket::entityId, - ByteBufCodecs.BOOL, - EntityAnimTriggerPacket::isReplacedEntity, - ByteBufCodecs.STRING_UTF8, - EntityAnimTriggerPacket::controllerName, - ByteBufCodecs.STRING_UTF8, - EntityAnimTriggerPacket::animName, - EntityAnimTriggerPacket::new); + ByteBufCodecs.VAR_INT, + EntityAnimTriggerPacket::entityId, + ByteBufCodecs.BOOL, + EntityAnimTriggerPacket::isReplacedEntity, + ByteBufCodecs.STRING_UTF8, + EntityAnimTriggerPacket::controllerName, + ByteBufCodecs.STRING_UTF8, + EntityAnimTriggerPacket::animName, + EntityAnimTriggerPacket::new + ); public void handle() { Entity entity = ClientUtils.getLevel().getEntity(this.entityId); @@ -49,8 +56,11 @@ public void handle() { return; } if (RenderUtils.getReplacedAnimatable(entity.getType()) instanceof GeoReplacedEntity replacedEntity) - replacedEntity.triggerAnim(entity, this.controllerName.isEmpty() ? null : this.controllerName, - this.animName); + replacedEntity.triggerAnim( + entity, + this.controllerName.isEmpty() ? null : this.controllerName, + this.animName + ); } @Override diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/SendConfigDataPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/SendConfigDataPacket.java index d8e2f345c..35557242b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/SendConfigDataPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/SendConfigDataPacket.java @@ -1,18 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ - package mod.azure.azurelib.common.internal.common.network.packet; +package mod.azure.azurelib.common.internal.common.network.packet; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.AzureLibException; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; @@ -23,42 +14,55 @@ import java.util.Map; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.AzureLibException; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + public record SendConfigDataPacket(String config) implements AbstractPacket { public static final Marker MARKER = MarkerManager.getMarker("Network"); + public static final Type TYPE = new Type<>( - AzureLibNetwork.CONFIG_PACKET_ID); + AzureLibNetwork.CONFIG_PACKET_ID + ); + public static final StreamCodec CODEC = StreamCodec.of( - (buf, packet) -> { - buf.writeUtf(packet.config); - ConfigHolderRegistry.getConfig(packet.config).ifPresent(data -> { - Map> serialized = data.getNetworkSerializedFields(); - buf.writeInt(serialized.size()); - for (Map.Entry> entry : serialized.entrySet()) { - String id = entry.getKey(); - ConfigValue value = entry.getValue(); - TypeAdapter adapter = value.getAdapter(); - buf.writeUtf(id); - adapter.encodeToBuffer(value, buf); - } - }); - }, buf -> { - String config = buf.readUtf(); - int i = buf.readInt(); - ConfigHolderRegistry.getConfig(config).ifPresent(data -> { - Map> serialized = data.getNetworkSerializedFields(); - for (int j = 0; j < i; j++) { - String fieldId = buf.readUtf(); - ConfigValue value = serialized.get(fieldId); - if (value == null) { - AzureLib.LOGGER.fatal(MARKER, "Received unknown config value " + fieldId); - throw new AzureLibException("Unknown config field: " + fieldId); - } - setValue(value, buf); + (buf, packet) -> { + buf.writeUtf(packet.config); + ConfigHolderRegistry.getConfig(packet.config).ifPresent(data -> { + Map> serialized = data.getNetworkSerializedFields(); + buf.writeInt(serialized.size()); + for (Map.Entry> entry : serialized.entrySet()) { + String id = entry.getKey(); + ConfigValue value = entry.getValue(); + TypeAdapter adapter = value.getAdapter(); + buf.writeUtf(id); + adapter.encodeToBuffer(value, buf); + } + }); + }, + buf -> { + String config = buf.readUtf(); + int i = buf.readInt(); + ConfigHolderRegistry.getConfig(config).ifPresent(data -> { + Map> serialized = data.getNetworkSerializedFields(); + for (int j = 0; j < i; j++) { + String fieldId = buf.readUtf(); + ConfigValue value = serialized.get(fieldId); + if (value == null) { + AzureLib.LOGGER.fatal(MARKER, "Received unknown config value " + fieldId); + throw new AzureLibException("Unknown config field: " + fieldId); } - }); - return new SendConfigDataPacket(config); + setValue(value, buf); + } }); + return new SendConfigDataPacket(config); + } + ); @SuppressWarnings("unchecked") private static void setValue(ConfigValue value, FriendlyByteBuf buffer) { @@ -73,7 +77,5 @@ private static void setValue(ConfigValue value, FriendlyByteBuf buffer) { } @Override - public void handle() { - - } + public void handle() {} } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksEntityRegistry.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksEntityRegistry.java index 25a2f3609..db085c85f 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksEntityRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksEntityRegistry.java @@ -1,24 +1,22 @@ package mod.azure.azurelib.common.internal.common.registry; -import mod.azure.azurelib.common.api.common.registry.CommonBlockEntityRegistryInterface; -import mod.azure.azurelib.common.api.common.registry.CommonBlockRegistryInterface; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.material.PushReaction; import java.util.function.Supplier; +import mod.azure.azurelib.common.api.common.registry.CommonBlockEntityRegistryInterface; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; + public class AzureBlocksEntityRegistry implements CommonBlockEntityRegistryInterface { - public static final Supplier> TICKING_LIGHT_ENTITY = CommonBlockEntityRegistryInterface.registerBlockEntity( + public static final Supplier> TICKING_LIGHT_ENTITY = + CommonBlockEntityRegistryInterface.registerBlockEntity( AzureLib.MOD_ID, "lightblock", - () -> BlockEntityType.Builder.of(TickingLightEntity::new, AzureBlocksRegistry.TICKING_LIGHT_BLOCK.get()).build(null)); + () -> BlockEntityType.Builder.of(TickingLightEntity::new, AzureBlocksRegistry.TICKING_LIGHT_BLOCK.get()) + .build(null) + ); - public static void init() { - } + public static void init() {} } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksRegistry.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksRegistry.java index c4af24904..2871a0f0c 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksRegistry.java @@ -1,24 +1,28 @@ package mod.azure.azurelib.common.internal.common.registry; -import mod.azure.azurelib.common.api.common.registry.CommonBlockRegistryInterface; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.material.PushReaction; import java.util.function.Supplier; +import mod.azure.azurelib.common.api.common.registry.CommonBlockRegistryInterface; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; + public class AzureBlocksRegistry implements CommonBlockRegistryInterface { - public static final Supplier TICKING_LIGHT_BLOCK = CommonBlockRegistryInterface.registerBlock(AzureLib.MOD_ID, "lightblock", () -> new TickingLightBlock( + public static final Supplier TICKING_LIGHT_BLOCK = CommonBlockRegistryInterface.registerBlock( + AzureLib.MOD_ID, + "lightblock", + () -> new TickingLightBlock( BlockBehaviour.Properties.of() - .sound(SoundType.CANDLE) - .lightLevel(TickingLightBlock.litBlockEmission(15)) - .pushReaction(PushReaction.DESTROY) - .noOcclusion() - )); + .sound(SoundType.CANDLE) + .lightLevel(TickingLightBlock.litBlockEmission(15)) + .pushReaction(PushReaction.DESTROY) + .noOcclusion() + ) + ); - public static void init() { - } + public static void init() {} } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java index e4ceda8f0..398544576 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java @@ -1,17 +1,19 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.util; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; + import mod.azure.azurelib.common.internal.common.constant.DataTickets; import mod.azure.azurelib.common.internal.common.loading.object.BakedModelFactory; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; import mod.azure.azurelib.common.internal.common.registry.AzureBlocksRegistry; -import mod.azure.azurelib.common.platform.Services; import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; import mod.azure.azurelib.core.animatable.instance.InstancedAnimatableInstanceCache; @@ -19,11 +21,6 @@ import mod.azure.azurelib.core.animation.Animation; import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core.object.DataTicket; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; /** * Helper class for various AzureLib-specific functions. @@ -39,11 +36,11 @@ public static AnimatableInstanceCache createInstanceCache(GeoAnimatable animatab AnimatableInstanceCache cache = animatable.animatableCacheOverride(); return cache != null - ? cache - : createInstanceCache( + ? cache + : createInstanceCache( animatable, !(animatable instanceof Entity) && !(animatable instanceof BlockEntity) - ); + ); } /** @@ -61,10 +58,10 @@ public static AnimatableInstanceCache createInstanceCache(GeoAnimatable animatab return cache; return singletonObject - ? new SingletonAnimatableInstanceCache( + ? new SingletonAnimatableInstanceCache( animatable - ) - : new InstancedAnimatableInstanceCache(animatable); + ) + : new InstancedAnimatableInstanceCache(animatable); } /** @@ -116,9 +113,9 @@ public static synchronized SerializableDataTicket addDataTicket(Serializa public static boolean checkDistance(BlockPos blockPosA, BlockPos blockPosB, int distance) { return Math.abs(blockPosA.getX() - blockPosB.getX()) <= distance && Math.abs( - blockPosA.getY() - blockPosB.getY() + blockPosA.getY() - blockPosB.getY() ) <= distance && Math.abs( - blockPosA.getZ() - blockPosB.getZ() + blockPosA.getZ() - blockPosB.getZ() ) <= distance; } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java index 68ea14402..bf8cfcd13 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.util; @@ -10,6 +8,14 @@ import com.google.gson.*; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.util.GsonHelper; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Array; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + import mod.azure.azurelib.common.internal.common.loading.json.raw.*; import mod.azure.azurelib.common.internal.common.loading.json.typeadapter.BakedAnimationsAdapter; import mod.azure.azurelib.common.internal.common.loading.json.typeadapter.KeyFramesAdapter; @@ -19,13 +25,6 @@ import mod.azure.azurelib.core2.animation.parse.AzKeyFramesAdapter; import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; import mod.azure.azurelib.core2.animation.primitive.AzKeyframes; -import net.minecraft.util.GsonHelper; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Array; -import java.util.List; -import java.util.Map; -import java.util.function.Function; /** * Json helper class for various json functions @@ -81,9 +80,9 @@ public static double[] jsonArrayToDoubleArray(@Nullable JsonArray array) throws * @param objectClass The object type that the array contains */ public static T[] jsonArrayToObjectArray( - JsonArray array, - JsonDeserializationContext context, - Class objectClass + JsonArray array, + JsonDeserializationContext context, + Class objectClass ) { T[] objArray = (T[]) Array.newInstance(objectClass, array.size()); @@ -122,9 +121,9 @@ public static List jsonArrayToList(@Nullable JsonArray array, Function Map jsonObjToMap( - JsonObject obj, - JsonDeserializationContext context, - Class objectType + JsonObject obj, + JsonDeserializationContext context, + Class objectType ) { Map map = new Object2ObjectOpenHashMap<>(obj.size()); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java index d2d6f564a..b0bc24077 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java @@ -1,12 +1,13 @@ package mod.azure.azurelib.common.internal.mixins; -import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import net.minecraft.world.entity.Entity; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; + @Mixin(Entity.class) public abstract class EntityMixin_AzEntityAnimatorCache implements AzAnimatorAccessor { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemRendererAccessor.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemRendererAccessor.java index af03e289b..dd7e653cd 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemRendererAccessor.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemRendererAccessor.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.mixins; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MinecraftMixin.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MinecraftMixin.java index c0f67ffc0..d1a420092 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MinecraftMixin.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MinecraftMixin.java @@ -1,14 +1,10 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.mixins; import com.mojang.blaze3d.platform.WindowEventHandler; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; -import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import net.minecraft.util.thread.ReentrantBlockableEventLoop; @@ -19,6 +15,9 @@ import java.util.Optional; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; +import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; + @Mixin(Minecraft.class) public abstract class MinecraftMixin extends ReentrantBlockableEventLoop implements WindowEventHandler { @@ -26,12 +25,17 @@ public MinecraftMixin(String p_i50401_1_) { super(p_i50401_1_); } - @Inject(method = "clearClientLevel(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;resetData()V")) + @Inject( + method = "clearClientLevel(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At( + value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;resetData()V" + ) + ) private void configuration_reloadClientConfigs(Screen screen, CallbackInfo ci) { - ConfigHolderRegistry.getSynchronizedConfigs().stream() - .map(ConfigHolderRegistry::getConfig) - .filter(Optional::isPresent) - .map(Optional::get) - .forEach(ConfigIO::reloadClientValues); + ConfigHolderRegistry.getSynchronizedConfigs() + .stream() + .map(ConfigHolderRegistry::getConfig) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(ConfigIO::reloadClientValues); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java index 46262ee9f..f061a9ece 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.mixins; @@ -11,9 +9,6 @@ import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalRef; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.Model; import net.minecraft.client.renderer.MultiBufferSource; @@ -30,35 +25,68 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; + @Mixin(HumanoidArmorLayer.class) public abstract class MixinHumanoidArmorLayer> { @ModifyExpressionValue( - method = "renderArmorPiece", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/entity/LivingEntity;getItemBySlot(Lnet/minecraft/world/entity/EquipmentSlot;)Lnet/minecraft/world/item/ItemStack;" - ) + method = "renderArmorPiece", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;getItemBySlot(Lnet/minecraft/world/entity/EquipmentSlot;)Lnet/minecraft/world/item/ItemStack;" + ) ) - private ItemStack azurelib$captureItemBySlot(ItemStack original, @Share("item_by_slot") LocalRef itemBySlotRef) { + private ItemStack azurelib$captureItemBySlot( + ItemStack original, + @Share("item_by_slot") LocalRef itemBySlotRef + ) { itemBySlotRef.set(original); return original; } - @Inject(method = "renderArmorPiece", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;usesInnerModel(Lnet/minecraft/world/entity/EquipmentSlot;)Z"), cancellable = true) - public void azurelib$renderAzurelibModel(PoseStack poseStack, MultiBufferSource bufferSource, T entity, EquipmentSlot equipmentSlot, int packedLight, A baseModel, CallbackInfo ci, @Share("item_by_slot") LocalRef itemBySlotRef) { + @Inject( + method = "renderArmorPiece", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;usesInnerModel(Lnet/minecraft/world/entity/EquipmentSlot;)Z" + ), cancellable = true + ) + public void azurelib$renderAzurelibModel( + PoseStack poseStack, + MultiBufferSource bufferSource, + T entity, + EquipmentSlot equipmentSlot, + int packedLight, + A baseModel, + CallbackInfo ci, + @Share("item_by_slot") LocalRef itemBySlotRef + ) { final ItemStack stack = itemBySlotRef.get(); - final Model geckolibModel = RenderProvider.of(stack).getGenericArmorModel(entity, stack, equipmentSlot, - (HumanoidModel) baseModel); + final Model geckolibModel = RenderProvider.of(stack) + .getGenericArmorModel( + entity, + stack, + equipmentSlot, + (HumanoidModel) baseModel + ); if (geckolibModel != null && stack.getItem() instanceof GeoItem) { if (geckolibModel instanceof GeoArmorRenderer geoArmorRenderer) geoArmorRenderer.prepForRender(entity, stack, equipmentSlot, baseModel); baseModel.copyPropertiesTo((A) geckolibModel); - geckolibModel.renderToBuffer(poseStack, null, packedLight, OverlayTexture.NO_OVERLAY, stack.is( - ItemTags.DYEABLE) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(stack, -6265536)) : -1); + geckolibModel.renderToBuffer( + poseStack, + null, + packedLight, + OverlayTexture.NO_OVERLAY, + stack.is( + ItemTags.DYEABLE + ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(stack, -6265536)) : -1 + ); ci.cancel(); } } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java index 1ce904dd0..d132a132a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java @@ -1,15 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.mixins; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.resources.model.BakedModel; @@ -20,6 +16,9 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; + /** * Render hook to inject AzureLib's ISTER rendering callback */ @@ -27,25 +26,25 @@ public class MixinItemRenderer { @Inject( - method = "render", at = @At( + method = "render", at = @At( value = "INVOKE", target = "Lnet/minecraft/client/renderer/BlockEntityWithoutLevelRenderer;renderByItem(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemDisplayContext;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;II)V" - ), cancellable = true + ), cancellable = true ) public void itemModelHook( - ItemStack itemStack, - ItemDisplayContext transformType, - boolean bl, - PoseStack poseStack, - MultiBufferSource multiBufferSource, - int i, - int j, - BakedModel bakedModel, - CallbackInfo ci + ItemStack itemStack, + ItemDisplayContext transformType, + boolean bl, + PoseStack poseStack, + MultiBufferSource multiBufferSource, + int i, + int j, + BakedModel bakedModel, + CallbackInfo ci ) { if (itemStack.getItem() instanceof GeoItem) RenderProvider.of(itemStack) - .getCustomRenderer() - .renderByItem(itemStack, transformType, poseStack, multiBufferSource, i, j); + .getCustomRenderer() + .renderByItem(itemStack, transformType, poseStack, multiBufferSource, i, j); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/PlayerListMixin.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/PlayerListMixin.java index 7f570b5d9..67360ad68 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/PlayerListMixin.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/PlayerListMixin.java @@ -1,13 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.mixins; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.network.Connection; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; @@ -19,15 +15,18 @@ import java.util.Set; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; +import mod.azure.azurelib.common.platform.Services; + @Mixin(PlayerList.class) public abstract class PlayerListMixin { @Inject(method = "placeNewPlayer", at = @At("TAIL")) private void configuration_sendServerConfigs( - Connection connection, - ServerPlayer player, - CommonListenerCookie commonListenerCookie, - CallbackInfo ci + Connection connection, + ServerPlayer player, + CommonListenerCookie commonListenerCookie, + CallbackInfo ci ) { Set set = ConfigHolderRegistry.getSynchronizedConfigs(); set.forEach(id -> Services.NETWORK.sendClientPacket(player, id)); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java index f62300c24..dfe740c71 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java @@ -1,13 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.mixins; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.resources.ResourceLocation; @@ -20,6 +17,8 @@ import java.util.Map; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; + @Mixin(TextureManager.class) public abstract class TextureManagerMixin { @@ -31,8 +30,8 @@ public abstract class TextureManagerMixin { public abstract void register(ResourceLocation resourceLocation, AbstractTexture abstractTexture); @Inject( - method = "getTexture(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/renderer/texture/AbstractTexture;", - at = @At("HEAD") + method = "getTexture(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/renderer/texture/AbstractTexture;", + at = @At("HEAD") ) private void wrapAnimatableTexture(ResourceLocation path, CallbackInfoReturnable callback) { AbstractTexture existing = this.byPath.get(path); diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/Services.java b/common/src/main/java/mod/azure/azurelib/common/platform/Services.java index 0b4c83fb4..f3ee93951 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/Services.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/Services.java @@ -1,10 +1,9 @@ package mod.azure.azurelib.common.platform; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.platform.services.*; - import java.util.ServiceLoader; +import mod.azure.azurelib.common.platform.services.*; + public final class Services { public static final AzureEvents GEO_RENDER_PHASE_EVENT_FACTORY = load(AzureEvents.class); @@ -23,7 +22,7 @@ private Services() { public static T load(Class clazz) { return ServiceLoader.load(clazz) - .findFirst() - .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); + .findFirst() + .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AccessWidener.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AccessWidener.java index a11c1dee0..aa737aa0f 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AccessWidener.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AccessWidener.java @@ -1,4 +1,3 @@ package mod.azure.azurelib.common.platform.services; -public interface AccessWidener { -} +public interface AccessWidener {} diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureEvents.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureEvents.java index bcea2d28c..44c88e8c1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureEvents.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureEvents.java @@ -1,86 +1,184 @@ package mod.azure.azurelib.common.platform.services; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; + import mod.azure.azurelib.common.api.client.renderer.*; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import net.minecraft.client.renderer.MultiBufferSource; public interface AzureEvents { + /** * Fire the Block.CompileRenderLayers event */ void fireCompileBlockRenderLayers(GeoBlockRenderer renderer); + /** * Fire the Block.Pre event */ - boolean fireBlockPreRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireBlockPreRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the Block.Post event */ - void fireBlockPostRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireBlockPostRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Fire the Armor.CompileRenderLayers event */ void fireCompileArmorRenderLayers(GeoArmorRenderer renderer); + /** * Fire the Armor.Pre event */ - boolean fireArmorPreRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireArmorPreRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the Armor.Post event */ - void fireArmorPostRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireArmorPostRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Fire the Entity.CompileRenderLayers event */ void fireCompileEntityRenderLayers(GeoEntityRenderer renderer); + /** * Fire the Entity.Pre event */ - boolean fireEntityPreRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireEntityPreRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the Entity.Post event */ - void fireEntityPostRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireEntityPostRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Fire the ReplacedEntity.CompileRenderLayers event */ void fireCompileReplacedEntityRenderLayers(GeoReplacedEntityRenderer renderer); + /** * Fire the ReplacedEntity.Pre event */ - boolean fireReplacedEntityPreRender(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireReplacedEntityPreRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the ReplacedEntity.Post event */ - void fireReplacedEntityPostRender(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireReplacedEntityPostRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Fire the Item.CompileRenderLayers event */ void fireCompileItemRenderLayers(GeoItemRenderer renderer); + /** * Fire the Item.Pre event */ - boolean fireItemPreRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireItemPreRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the Item.Post event */ - void fireItemPostRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireItemPostRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Fire the Object.CompileRenderLayers event */ void fireCompileObjectRenderLayers(GeoObjectRenderer renderer); + /** * Fire the Object.Pre event */ - boolean fireObjectPreRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireObjectPreRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the Object.Post event */ - void fireObjectPostRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireObjectPostRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java index 8a57ef2c1..033f891f8 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java @@ -1,10 +1,6 @@ package mod.azure.azurelib.common.platform.services; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; @@ -17,6 +13,11 @@ import java.util.Map; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + public interface AzureLibNetwork { ResourceLocation ANIM_DATA_SYNC_PACKET_ID = AzureLib.modResource("anim_data_sync"); @@ -54,7 +55,11 @@ static GeoAnimatable getSyncedAnimatable(String className) { return animatable; } - void registerPacketInternal(CustomPacketPayload.Type

    payloadType, StreamCodec codec, boolean isClientBound); + void registerPacketInternal( + CustomPacketPayload.Type

    payloadType, + StreamCodec codec, + boolean isClientBound + ); /** * Registers a synced {@link GeoAnimatable} object for networking support.
    diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/CommonRegistry.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/CommonRegistry.java index 1ccfde3a3..eccdc9b9e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/CommonRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/CommonRegistry.java @@ -24,11 +24,19 @@ public interface CommonRegistry { - Supplier> registerBlockEntity(String modID, String blockEntityName, Supplier> blockEntityType); + Supplier> registerBlockEntity( + String modID, + String blockEntityName, + Supplier> blockEntityType + ); Supplier registerBlock(String modID, String blockName, Supplier block); - Supplier> registerEntity(String modID, String entityName, Supplier> entity); + Supplier> registerEntity( + String modID, + String entityName, + Supplier> entity + ); Holder registerArmorMaterial(String modID, String matName, Supplier armorMaterial); @@ -38,13 +46,21 @@ public interface CommonRegistry { > Supplier registerScreen(String modID, String screenName, Supplier menuType); - Supplier> registerStructure(String modID, String structureName, MapCodec structure); + Supplier> registerStructure( + String modID, + String structureName, + MapCodec structure + ); > Supplier registerParticle(String modID, String particleName, Supplier particle); Supplier registerCreativeModeTab(String modID, String tabName, Supplier tab); - default Holder registerStatusEffect(String modID, String effectName, Supplier statusEffect) { + default Holder registerStatusEffect( + String modID, + String effectName, + Supplier statusEffect + ) { return null; } @@ -52,7 +68,12 @@ default Supplier registerFluid(String modID, String fluidNa return null; } - Supplier makeSpawnEggFor(Supplier> entityType, int primaryEggColour, int secondaryEggColour, Item.Properties itemProperties); + Supplier makeSpawnEggFor( + Supplier> entityType, + int primaryEggColour, + int secondaryEggColour, + Item.Properties itemProperties + ); CreativeModeTab.Builder newCreativeTabBuilder(); } diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/IPlatformHelper.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/IPlatformHelper.java index d78bf008d..49253aa73 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/IPlatformHelper.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/IPlatformHelper.java @@ -1,10 +1,6 @@ package mod.azure.azurelib.common.platform.services; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; import net.minecraft.core.component.DataComponentType; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.level.block.entity.BlockEntityType; import java.nio.file.Path; import java.util.function.Supplier; @@ -22,5 +18,8 @@ public interface IPlatformHelper { boolean isEnvironmentClient(); - Supplier> registerDataComponent(String id, UnaryOperator> builder); + Supplier> registerDataComponent( + String id, + UnaryOperator> builder + ); } diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java b/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java index c6a32c50c..09679873d 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable; +import org.jetbrains.annotations.Nullable; + import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.AnimationController; import mod.azure.azurelib.core.animation.AnimationProcessor; -import org.jetbrains.annotations.Nullable; /** * This is the root interface for all animatable objects in AzureLib. Generally speaking you should use one of the diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java index 8cbdb1f0f..3bf1a0fb1 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java @@ -1,13 +1,15 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.instance; import com.google.common.base.Suppliers; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + import mod.azure.azurelib.common.internal.client.RenderProvider; import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; import mod.azure.azurelib.common.platform.Services; @@ -15,9 +17,6 @@ import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.object.DataTicket; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; - /** * The base cache class responsible for returning the {@link AnimatableManager} for a given instanceof of a * {@link GeoAnimatable}. This class is abstracted and not intended for direct use. See either @@ -28,12 +27,16 @@ public abstract class AnimatableInstanceCache { protected final GeoAnimatable animatable; + protected final Supplier renderProvider; protected AnimatableInstanceCache(GeoAnimatable animatable) { this.animatable = animatable; this.renderProvider = Suppliers.memoize(() -> { - if (!(this.animatable instanceof SingletonGeoAnimatable singleton) || !Services.PLATFORM.isEnvironmentClient()) + if ( + !(this.animatable instanceof SingletonGeoAnimatable singleton) || !Services.PLATFORM + .isEnvironmentClient() + ) return null; final AtomicReference consumer = new AtomicReference<>(RenderProvider.DEFAULT); @@ -77,7 +80,8 @@ public D getDataPoint(long uniqueId, DataTicket dataTicket) { /** * Get the {@link RenderProvider} for this animatable *

    - * Because only {@link SingletonGeoAnimatable}s use this functionality, it this method should not be used and will always return null for anything other than a SingletonGeoAnimatable + * Because only {@link SingletonGeoAnimatable}s use this functionality, it this method should not be used and will + * always return null for anything other than a SingletonGeoAnimatable *

    * The returned object is upcast to Object for side-safety * diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java index c67b2a313..011f1ddf4 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.instance; diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java index f23562202..4c1c16e5d 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java @@ -1,14 +1,13 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.instance; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; + import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimatableManager; diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java index f3ae33a46..72bd6139a 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.model; diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java index d6c3f2eb6..7ee553f15 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.model; -import mod.azure.azurelib.core.state.BoneSnapshot; - import java.util.List; +import mod.azure.azurelib.core.state.BoneSnapshot; + /** * Base class for AzureLib {@link CoreGeoModel model} bones.
    * Mostly a placeholder to allow for splitting up core (non-Minecraft) libraries diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java index 112501422..64cf4262d 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java @@ -1,20 +1,18 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.model; +import java.util.Optional; + import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.Animation; import mod.azure.azurelib.core.animation.AnimationProcessor; import mod.azure.azurelib.core.animation.AnimationState; -import java.util.Optional; - /** * Base class for AzureLib models.
    * Mostly an internal placeholder to allow for splitting up core (non-Minecraft) libraries @@ -72,8 +70,7 @@ default Optional getBone(String name) { * @param animationState An {@link AnimationState} instance created to hold animation data for the * {@code animatable} for this method call */ - default void setCustomAnimations(E animatable, long instanceId, AnimationState animationState) { - } + default void setCustomAnimations(E animatable, long instanceId, AnimationState animationState) {} /** * This method is called once per render frame for each {@link GeoAnimatable} being rendered.
    @@ -83,6 +80,5 @@ default void setCustomAnimations(E animatable, long instanceId, AnimationState * Generally speaking, a single working-instance of an {@link GeoAnimatable Animatable} will have a single instance of @@ -182,7 +181,7 @@ public ControllerRegistrar remove(String name) { private Object2ObjectArrayMap> build() { Object2ObjectArrayMap> map = new Object2ObjectArrayMap<>( - this.controllers.size() + this.controllers.size() ); this.controllers.forEach(controller -> map.put(controller.getName(), controller)); diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java index ca22625a9..ccedc9cc5 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java @@ -1,23 +1,22 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.keyframe.BoneAnimation; import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - /** * A compiled animation instance for use by the {@link AnimationController}
    * Modifications or extensions of a compiled Animation are not supported, and therefore an instance of @@ -26,21 +25,24 @@ * @deprecated */ public record Animation( - String name, - double length, - LoopType loopType, - BoneAnimation[] boneAnimations, - Keyframes keyFrames + String name, + double length, + LoopType loopType, + BoneAnimation[] boneAnimations, + Keyframes keyFrames ) { public static Animation generateWaitAnimation(double length) { return new Animation( - RawAnimation.Stage.WAIT, - length, - LoopType.PLAY_ONCE, - new BoneAnimation[0], - new Keyframes(new SoundKeyframeData[0], new ParticleKeyframeData[0], - new CustomInstructionKeyframeData[0]) + RawAnimation.Stage.WAIT, + length, + LoopType.PLAY_ONCE, + new BoneAnimation[0], + new Keyframes( + new SoundKeyframeData[0], + new ParticleKeyframeData[0], + new CustomInstructionKeyframeData[0] + ) ); } @@ -55,11 +57,11 @@ public interface LoopType { final Map LOOP_TYPES = new ConcurrentHashMap<>(4); LoopType DEFAULT = (animatable, controller, currentAnimation) -> currentAnimation.loopType() - .shouldPlayAgain(animatable, controller, currentAnimation); + .shouldPlayAgain(animatable, controller, currentAnimation); LoopType PLAY_ONCE = register( - "play_once", - register("false", (animatable, controller, currentAnimation) -> false) + "play_once", + register("false", (animatable, controller, currentAnimation) -> false) ); LoopType HOLD_ON_LAST_FRAME = register("hold_on_last_frame", (animatable, controller, currentAnimation) -> { @@ -122,16 +124,15 @@ static LoopType register(String name, LoopType loopType) { * @return Whether the animation should play again, or stop */ boolean shouldPlayAgain( - GeoAnimatable animatable, - AnimationController controller, - Animation currentAnimation + GeoAnimatable animatable, + AnimationController controller, + Animation currentAnimation ); } public record Keyframes( - SoundKeyframeData[] sounds, - ParticleKeyframeData[] particles, - CustomInstructionKeyframeData[] customInstructions - ) { - } + SoundKeyframeData[] sounds, + ParticleKeyframeData[] particles, + CustomInstructionKeyframeData[] customInstructions + ) {} } diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java index fd70a6aec..45a693d28 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java @@ -1,14 +1,19 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; + import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animatable.model.CoreGeoModel; @@ -27,17 +32,12 @@ import mod.azure.azurelib.core.object.Axis; import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.core.state.BoneSnapshot; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; -import java.util.function.Function; -import java.util.function.ToDoubleFunction; /** * The actual controller that handles the playing and usage of animations, including their various keyframes and * instruction markers. Each controller can only play a single animation at a time - for example you may have one * controller to animate walking, one to control attacks, one to control size, etc. + * * @deprecated */ public class AnimationController { @@ -53,16 +53,27 @@ public class AnimationController { protected final Map boneAnimationQueues = new Object2ObjectOpenHashMap<>(); protected final Map boneSnapshots = new Object2ObjectOpenHashMap<>(); + protected final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); + protected final Set executedKeyFrames = new ObjectOpenHashSet<>(); + protected Queue animationQueue = new LinkedList<>(); + protected boolean isJustStarting = false; + protected boolean needsAnimationReload = false; + protected boolean shouldResetTick = false; + protected boolean justStartedTransition = false; + protected SoundKeyframeHandler soundKeyframeHandler = null; + protected ParticleKeyframeHandler particleKeyframeHandler = null; + protected CustomKeyframeHandler customKeyframeHandler = null; + protected RawAnimation triggeredAnimation = null; protected boolean handlingTriggeredAnimations = false; @@ -80,7 +91,9 @@ public class AnimationController { protected ToDoubleFunction animationSpeedModifier = obj -> 1d; protected Function overrideEasingTypeFunction = obj -> null; + protected CoreGeoModel lastModel; + protected boolean justStopped = true; /** @@ -133,10 +146,10 @@ public AnimationController(T animatable, int transitionTickTime, AnimationStateH * which animations to play */ public AnimationController( - T animatable, - String name, - int transitionTickTime, - AnimationStateHandler animationHandler + T animatable, + String name, + int transitionTickTime, + AnimationStateHandler animationHandler ) { this.animatable = animatable; this.name = name; @@ -175,7 +188,7 @@ public AnimationController setParticleKeyframeHandler(ParticleKeyframeHandler * @return this */ public AnimationController setCustomInstructionKeyframeHandler( - CustomKeyframeHandler customInstructionHandler + CustomKeyframeHandler customInstructionHandler ) { this.customKeyframeHandler = customInstructionHandler; @@ -388,7 +401,7 @@ public void setAnimation(RawAnimation rawAnimation) { if (this.needsAnimationReload || !rawAnimation.equals(this.currentRawAnimation)) { if (this.lastModel != null) { Queue animations = this.lastModel.getAnimationProcessor() - .buildAnimationQueue(this.animatable, rawAnimation); + .buildAnimationQueue(this.animatable, rawAnimation); if (animations != null) { this.animationQueue = animations; @@ -441,9 +454,9 @@ protected PlayState handleAnimationState(AnimationState state) { setAnimation(this.triggeredAnimation); if ( - !hasAnimationFinished() && (!this.handlingTriggeredAnimations || this.stateHandler.handle( - state - ) == PlayState.CONTINUE) + !hasAnimationFinished() && (!this.handlingTriggeredAnimations || this.stateHandler.handle( + state + ) == PlayState.CONTINUE) ) return PlayState.CONTINUE; @@ -467,12 +480,12 @@ protected PlayState handleAnimationState(AnimationState state) { * bones */ public void process( - CoreGeoModel model, - AnimationState state, - Map bones, - Map snapshots, - final double seekTime, - boolean crashWhenCantFindBone + CoreGeoModel model, + AnimationState state, + Map bones, + Map snapshots, + final double seekTime, + boolean crashWhenCantFindBone ) { double adjustedTick = adjustTick(seekTime); this.lastModel = model; @@ -546,38 +559,38 @@ public void process( if (!rotationKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addNextRotation( - null, - adjustedTick, - this.transitionLength, - boneSnapshot, - bone.getInitialSnapshot(), - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) + null, + adjustedTick, + this.transitionLength, + boneSnapshot, + bone.getInitialSnapshot(), + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) ); } if (!positionKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addNextPosition( - null, - adjustedTick, - this.transitionLength, - boneSnapshot, - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) + null, + adjustedTick, + this.transitionLength, + boneSnapshot, + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) ); } if (!scaleKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addNextScale( - null, - adjustedTick, - this.transitionLength, - boneSnapshot, - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) + null, + adjustedTick, + this.transitionLength, + boneSnapshot, + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) ); } } @@ -596,8 +609,8 @@ public void process( protected void processCurrentAnimation(double adjustedTick, double seekTime, boolean crashWhenCantFindBone) { if (adjustedTick >= this.currentAnimation.animation().length()) { if ( - this.currentAnimation.loopType() - .shouldPlayAgain(this.animatable, this, this.currentAnimation.animation()) + this.currentAnimation.loopType() + .shouldPlayAgain(this.animatable, this, this.currentAnimation.animation()) ) { if (this.animationState != State.PAUSED) { this.shouldResetTick = true; @@ -642,25 +655,25 @@ protected void processCurrentAnimation(double adjustedTick, double seekTime, boo if (!rotationKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addRotations( - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) ); } if (!positionKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addPositions( - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) ); } if (!scaleKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addScales( - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) ); } } @@ -671,15 +684,15 @@ protected void processCurrentAnimation(double adjustedTick, double seekTime, boo if (adjustedTick >= keyframeData.getStartTick() && this.executedKeyFrames.add(keyframeData)) { if (this.soundKeyframeHandler == null) { LOGGER.warn( - "Sound Keyframe found for {} -> {}, but no keyframe handler registered", - this.animatable.getClass().getSimpleName(), - getName() + "Sound Keyframe found for {} -> {}, but no keyframe handler registered", + this.animatable.getClass().getSimpleName(), + getName() ); break; } this.soundKeyframeHandler.handle( - new SoundKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) + new SoundKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) ); } } @@ -688,36 +701,36 @@ protected void processCurrentAnimation(double adjustedTick, double seekTime, boo if (adjustedTick >= keyframeData.getStartTick() && this.executedKeyFrames.add(keyframeData)) { if (this.particleKeyframeHandler == null) { LOGGER.warn( - "Particle Keyframe found for {} -> {}, but no keyframe handler registered", - this.animatable.getClass().getSimpleName(), - getName() + "Particle Keyframe found for {} -> {}, but no keyframe handler registered", + this.animatable.getClass().getSimpleName(), + getName() ); break; } this.particleKeyframeHandler.handle( - new ParticleKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) + new ParticleKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) ); } } for ( - CustomInstructionKeyframeData keyframeData : this.currentAnimation.animation() + CustomInstructionKeyframeData keyframeData : this.currentAnimation.animation() .keyFrames() .customInstructions() ) { if (adjustedTick >= keyframeData.getStartTick() && this.executedKeyFrames.add(keyframeData)) { if (this.customKeyframeHandler == null) { LOGGER.warn( - "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", - this.animatable.getClass().getSimpleName(), - getName() + "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", + this.animatable.getClass().getSimpleName(), + getName() ); break; } this.customKeyframeHandler.handle( - new CustomInstructionKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) + new CustomInstructionKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) ); } } @@ -748,8 +761,8 @@ protected void createInitialQueues(Collection modelRendererList) { * @param snapshots The master snapshot collection to pull filter from */ protected void saveSnapshotsForAnimation( - AnimationProcessor.QueuedAnimation animation, - Map snapshots + AnimationProcessor.QueuedAnimation animation, + Map snapshots ) { if (animation.animation().boneAnimations() == null) { return; @@ -771,7 +784,7 @@ protected void saveSnapshotsForAnimation( * * @param tick The currently used tick value * @return 0 if {@link AnimationController#shouldResetTick} is set to false, or a - * {@link AnimationController#animationSpeedModifier} modified value otherwise + * {@link AnimationController#animationSpeedModifier} modified value otherwise */ protected double adjustTick(double tick) { if (!this.shouldResetTick) @@ -789,10 +802,10 @@ protected double adjustTick(double tick) { * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} */ protected AnimationPoint getAnimationPointAtTick( - List> frames, - double tick, - boolean isRotation, - Axis axis + List> frames, + double tick, + boolean isRotation, + Axis axis ) { KeyframeLocation> location = getCurrentKeyFrameLocation(frames, tick); Keyframe currentFrame = location.keyframe(); @@ -826,8 +839,8 @@ protected AnimationPoint getAnimationPointAtTick( * @return A new {@code KeyFrameLocation} containing the current {@code KeyFrame} and the tick time used to find it */ protected KeyframeLocation> getCurrentKeyFrameLocation( - List> frames, - double ageInTicks + List> frames, + double ageInTicks ) { double totalFrameTime = 0; diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java index 7a77ff1e6..9be9afc62 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java @@ -1,13 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animatable.model.CoreBakedGeoModel; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; @@ -16,10 +19,6 @@ import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core.utils.Interpolations; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; /** * @deprecated @@ -59,9 +58,9 @@ public Queue buildAnimationQueue(T animatable, RawAnimation raw if (animation == null) { LOGGER.warn( - "Unable to find animation: {} for {}", - stage.animationName(), - animatable.getClass().getSimpleName() + "Unable to find animation: {} for {}", + stage.animationName(), + animatable.getClass().getSimpleName() ); return null; } else { @@ -84,12 +83,12 @@ public Queue buildAnimationQueue(T animatable, RawAnimation raw * remaining bones */ public void tickAnimation( - T animatable, - CoreGeoModel model, - AnimatableManager animatableManager, - double animTime, - AnimationState event, - boolean crashWhenCantFindBone + T animatable, + CoreGeoModel model, + AnimatableManager animatableManager, + double animTime, + AnimationState event, + boolean crashWhenCantFindBone ) { Map boneSnapshots = updateBoneSnapshots(animatableManager.getBoneSnapshotCollection()); @@ -122,13 +121,13 @@ public void tickAnimation( if (rotXPoint != null && rotYPoint != null && rotZPoint != null) { bone.setRotX( - (float) EasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() + (float) EasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() ); bone.setRotY( - (float) EasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() + (float) EasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() ); bone.setRotZ( - (float) EasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() + (float) EasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() ); snapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); snapshot.startRotAnim(); @@ -167,18 +166,18 @@ public void tickAnimation( saveSnapshot.stopRotAnim(animTime); double percentageReset = Math.min( - (animTime - saveSnapshot.getLastResetRotationTick()) / resetTickLength, - 1 + (animTime - saveSnapshot.getLastResetRotationTick()) / resetTickLength, + 1 ); bone.setRotX( - (float) Interpolations.lerp(saveSnapshot.getRotX(), initialSnapshot.getRotX(), percentageReset) + (float) Interpolations.lerp(saveSnapshot.getRotX(), initialSnapshot.getRotX(), percentageReset) ); bone.setRotY( - (float) Interpolations.lerp(saveSnapshot.getRotY(), initialSnapshot.getRotY(), percentageReset) + (float) Interpolations.lerp(saveSnapshot.getRotY(), initialSnapshot.getRotY(), percentageReset) ); bone.setRotZ( - (float) Interpolations.lerp(saveSnapshot.getRotZ(), initialSnapshot.getRotZ(), percentageReset) + (float) Interpolations.lerp(saveSnapshot.getRotZ(), initialSnapshot.getRotZ(), percentageReset) ); if (percentageReset >= 1) @@ -193,30 +192,30 @@ public void tickAnimation( saveSnapshot.stopPosAnim(animTime); double percentageReset = Math.min( - (animTime - saveSnapshot.getLastResetPositionTick()) / resetTickLength, - 1 + (animTime - saveSnapshot.getLastResetPositionTick()) / resetTickLength, + 1 ); bone.setPosX( - (float) Interpolations.lerp( - saveSnapshot.getOffsetX(), - initialSnapshot.getOffsetX(), - percentageReset - ) + (float) Interpolations.lerp( + saveSnapshot.getOffsetX(), + initialSnapshot.getOffsetX(), + percentageReset + ) ); bone.setPosY( - (float) Interpolations.lerp( - saveSnapshot.getOffsetY(), - initialSnapshot.getOffsetY(), - percentageReset - ) + (float) Interpolations.lerp( + saveSnapshot.getOffsetY(), + initialSnapshot.getOffsetY(), + percentageReset + ) ); bone.setPosZ( - (float) Interpolations.lerp( - saveSnapshot.getOffsetZ(), - initialSnapshot.getOffsetZ(), - percentageReset - ) + (float) Interpolations.lerp( + saveSnapshot.getOffsetZ(), + initialSnapshot.getOffsetZ(), + percentageReset + ) ); if (percentageReset >= 1) @@ -231,21 +230,30 @@ public void tickAnimation( saveSnapshot.stopScaleAnim(animTime); double percentageReset = Math.min( - (animTime - saveSnapshot.getLastResetScaleTick()) / resetTickLength, - 1 + (animTime - saveSnapshot.getLastResetScaleTick()) / resetTickLength, + 1 ); bone.setScaleX( - (float) Interpolations.lerp(saveSnapshot.getScaleX(), initialSnapshot.getScaleX(), - percentageReset) + (float) Interpolations.lerp( + saveSnapshot.getScaleX(), + initialSnapshot.getScaleX(), + percentageReset + ) ); bone.setScaleY( - (float) Interpolations.lerp(saveSnapshot.getScaleY(), initialSnapshot.getScaleY(), - percentageReset) + (float) Interpolations.lerp( + saveSnapshot.getScaleY(), + initialSnapshot.getScaleY(), + percentageReset + ) ); bone.setScaleZ( - (float) Interpolations.lerp(saveSnapshot.getScaleZ(), initialSnapshot.getScaleZ(), - percentageReset) + (float) Interpolations.lerp( + saveSnapshot.getScaleZ(), + initialSnapshot.getScaleZ(), + percentageReset + ) ); if (percentageReset >= 1) @@ -330,8 +338,7 @@ public void preAnimationSetup(T animatable, double animTime) { * {@link GeoAnimatable} */ public record QueuedAnimation( - Animation animation, - Animation.LoopType loopType - ) { - } + Animation animation, + Animation.LoopType loopType + ) {} } diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java index 9766fdb93..55e577be7 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.object.DataTicket; -import mod.azure.azurelib.core.object.PlayState; import java.util.Map; import java.util.Objects; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.object.DataTicket; +import mod.azure.azurelib.core.object.PlayState; + /** * Animation state handler for end-users.
    * This is where users would set their selected animation to play, stop the controller, or any number of other @@ -35,7 +34,9 @@ public class AnimationState { private final boolean isMoving; private final Map, Object> extraData = new Object2ObjectOpenHashMap<>(); + public double animationTick; + protected AnimationController controller; public AnimationState(T animatable, float limbSwing, float limbSwingAmount, float partialTick, boolean isMoving) { @@ -176,9 +177,9 @@ public boolean isCurrentAnimation(RawAnimation animation) { */ public boolean isCurrentAnimationStage(String name) { return getController().getCurrentAnimation() != null && getController().getCurrentAnimation() - .animation() - .name() - .equals(name); + .animation() + .name() + .equals(name); } /** diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java b/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java index 2e2d6d5f7..756274fd6 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java @@ -1,19 +1,18 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.object.DataTicket; -import mod.azure.azurelib.core.state.BoneSnapshot; import org.jetbrains.annotations.Nullable; import java.util.Map; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.object.DataTicket; +import mod.azure.azurelib.core.state.BoneSnapshot; + /** * Context-aware wrapper for {@link AnimatableManager}.
    * This can be used for things like perspective-dependent animation handling and other similar functionality.
    diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java b/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java index b6f5475dd..4f5ba381b 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; @@ -10,14 +8,15 @@ import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; -import mod.azure.azurelib.core.keyframe.AnimationPoint; -import mod.azure.azurelib.core.keyframe.Keyframe; -import mod.azure.azurelib.core.utils.Interpolations; import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import mod.azure.azurelib.core.keyframe.AnimationPoint; +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.utils.Interpolations; + /** * Functional interface defining an easing function.
    * {@code value} is the easing value provided from the keyframe's {@link Keyframe#easingArgs()}
    @@ -160,8 +159,8 @@ static Double2DoubleFunction linear(Double2DoubleFunction function) { */ static double catmullRom(double n) { return (0.5f * (2.0f * (n + 1) + ((n + 2) - n) * 1 - + (2.0f * n - 5.0f * (n + 1) + 4.0f * (n + 2) - (n + 3)) * 1 - + (3.0f * (n + 1) - n - 3.0f * (n + 2) + (n + 3)) * 1)); + + (2.0f * n - 5.0f * (n + 1) + 4.0f * (n + 2) - (n + 3)) * 1 + + (3.0f * (n + 1) - n - 3.0f * (n + 2) + (n + 3)) * 1)); } /** @@ -395,9 +394,9 @@ default double apply(AnimationPoint animationPoint, Double easingValue, double l return (float) animationPoint.animationEndValue(); return Interpolations.lerp( - animationPoint.animationStartValue(), - animationPoint.animationEndValue(), - buildTransformer(easingValue).apply(lerpValue) + animationPoint.animationStartValue(), + animationPoint.animationEndValue(), + buildTransformer(easingValue).apply(lerpValue) ); } } diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java index c571cdff6..ce55c0510 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; @@ -33,8 +31,7 @@ public final class RawAnimation { private final List animationList = new ObjectArrayList<>(); // Private constructor to force usage of factory for logical operations - private RawAnimation() { - } + private RawAnimation() {} /** * Start a new RawAnimation instance. This is the start point for creating an animation chain. @@ -157,9 +154,9 @@ public int hashCode() { * This is an entry object representing a single animation stage of the final compiled animation. */ public record Stage( - String animationName, - Animation.LoopType loopType, - int additionalTicks + String animationName, + Animation.LoopType loopType, + int additionalTicks ) { public static final String WAIT = "internal.wait"; diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPoint.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPoint.java index 2ebd53460..12ff3ae33 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPoint.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPoint.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; @@ -17,18 +15,18 @@ * @param keyFrame The {@code Nullable} Keyframe */ public record AnimationPoint( - Keyframe keyFrame, - double currentTick, - double transitionLength, - double animationStartValue, - double animationEndValue + Keyframe keyFrame, + double currentTick, + double transitionLength, + double animationStartValue, + double animationEndValue ) { @Override public String toString() { return "Tick: " + this.currentTick + - " | Transition Length: " + this.transitionLength + - " | Start Value: " + this.animationStartValue + - " | End Value: " + this.animationEndValue; + " | Transition Length: " + this.transitionLength + + " | Start Value: " + this.animationStartValue + + " | End Value: " + this.animationEndValue; } } diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPointQueue.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPointQueue.java index be0d1fe8b..847468036 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPointQueue.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPointQueue.java @@ -1,17 +1,15 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; -import mod.azure.azurelib.core.animation.AnimationController; - import java.io.Serial; import java.util.LinkedList; +import mod.azure.azurelib.core.animation.AnimationController; + /** * An {@link AnimationPoint} queue holds a queue of {@code AnimationPoints} which are used in the * {@link AnimationController} to lerp between values diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimation.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimation.java index e3b5b38e1..5c7a26efa 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimation.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; @@ -19,9 +17,8 @@ * @param scaleKeyFrames The deserialized scale {@code Keyframe} stack */ public record BoneAnimation( - String boneName, - KeyframeStack> rotationKeyFrames, - KeyframeStack> positionKeyFrames, - KeyframeStack> scaleKeyFrames -) { -} + String boneName, + KeyframeStack> rotationKeyFrames, + KeyframeStack> positionKeyFrames, + KeyframeStack> scaleKeyFrames +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimationQueue.java index 5904f694e..9c4a62d87 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimationQueue.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimationQueue.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; @@ -16,30 +14,30 @@ * onto their respective queues to be used for transformations in rendering */ public record BoneAnimationQueue( - CoreGeoBone bone, - AnimationPointQueue rotationXQueue, - AnimationPointQueue rotationYQueue, - AnimationPointQueue rotationZQueue, - AnimationPointQueue positionXQueue, - AnimationPointQueue positionYQueue, - AnimationPointQueue positionZQueue, - AnimationPointQueue scaleXQueue, - AnimationPointQueue scaleYQueue, - AnimationPointQueue scaleZQueue + CoreGeoBone bone, + AnimationPointQueue rotationXQueue, + AnimationPointQueue rotationYQueue, + AnimationPointQueue rotationZQueue, + AnimationPointQueue positionXQueue, + AnimationPointQueue positionYQueue, + AnimationPointQueue positionZQueue, + AnimationPointQueue scaleXQueue, + AnimationPointQueue scaleYQueue, + AnimationPointQueue scaleZQueue ) { public BoneAnimationQueue(CoreGeoBone bone) { this( - bone, - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue() + bone, + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue() ); } @@ -53,11 +51,11 @@ public BoneAnimationQueue(CoreGeoBone bone) { * @param endValue The value of the point at the end of its transition */ public void addPosXPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.positionXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -72,11 +70,11 @@ public void addPosXPoint( * @param endValue The value of the point at the end of its transition */ public void addPosYPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.positionYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -91,11 +89,11 @@ public void addPosYPoint( * @param endValue The value of the point at the end of its transition */ public void addPosZPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.positionZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -116,34 +114,34 @@ public void addPosZPoint( * new point */ public void addNextPosition( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - BoneSnapshot startSnapshot, - AnimationPoint nextXPoint, - AnimationPoint nextYPoint, - AnimationPoint nextZPoint + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + BoneSnapshot startSnapshot, + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint ) { addPosXPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getOffsetX(), - nextXPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getOffsetX(), + nextXPoint.animationStartValue() ); addPosYPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getOffsetY(), - nextYPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getOffsetY(), + nextYPoint.animationStartValue() ); addPosZPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getOffsetZ(), - nextZPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getOffsetZ(), + nextZPoint.animationStartValue() ); } @@ -157,11 +155,11 @@ public void addNextPosition( * @param endValue The value of the point at the end of its transition */ public void addScaleXPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.scaleXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -176,11 +174,11 @@ public void addScaleXPoint( * @param endValue The value of the point at the end of its transition */ public void addScaleYPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.scaleYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -195,11 +193,11 @@ public void addScaleYPoint( * @param endValue The value of the point at the end of its transition */ public void addScaleZPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.scaleZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -220,34 +218,34 @@ public void addScaleZPoint( * new point */ public void addNextScale( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - BoneSnapshot startSnapshot, - AnimationPoint nextXPoint, - AnimationPoint nextYPoint, - AnimationPoint nextZPoint + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + BoneSnapshot startSnapshot, + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint ) { addScaleXPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getScaleX(), - nextXPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getScaleX(), + nextXPoint.animationStartValue() ); addScaleYPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getScaleY(), - nextYPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getScaleY(), + nextYPoint.animationStartValue() ); addScaleZPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getScaleZ(), - nextZPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getScaleZ(), + nextZPoint.animationStartValue() ); } @@ -261,11 +259,11 @@ public void addNextScale( * @param endValue The value of the point at the end of its transition */ public void addRotationXPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.rotationXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -280,11 +278,11 @@ public void addRotationXPoint( * @param endValue The value of the point at the end of its transition */ public void addRotationYPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.rotationYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -299,11 +297,11 @@ public void addRotationYPoint( * @param endValue The value of the point at the end of its transition */ public void addRotationZPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.rotationZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -325,35 +323,35 @@ public void addRotationZPoint( * new point */ public void addNextRotation( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - BoneSnapshot startSnapshot, - BoneSnapshot initialSnapshot, - AnimationPoint nextXPoint, - AnimationPoint nextYPoint, - AnimationPoint nextZPoint + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + BoneSnapshot startSnapshot, + BoneSnapshot initialSnapshot, + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint ) { addRotationXPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getRotX() - initialSnapshot.getRotX(), - nextXPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getRotX() - initialSnapshot.getRotX(), + nextXPoint.animationStartValue() ); addRotationYPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getRotY() - initialSnapshot.getRotY(), - nextYPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getRotY() - initialSnapshot.getRotY(), + nextYPoint.animationStartValue() ); addRotationZPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getRotZ() - initialSnapshot.getRotZ(), - nextZPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getRotZ() - initialSnapshot.getRotZ(), + nextZPoint.animationStartValue() ); } diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/Keyframe.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/Keyframe.java index 89f663a16..891b804a3 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/Keyframe.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/Keyframe.java @@ -1,19 +1,18 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core.animation.EasingType; -import mod.azure.azurelib.core.math.IValue; import java.util.List; import java.util.Objects; +import mod.azure.azurelib.core.animation.EasingType; +import mod.azure.azurelib.core.math.IValue; + /** * Animation keyframe data * @@ -24,11 +23,11 @@ * @param easingArgs The arguments to provide to the easing calculation */ public record Keyframe( - double length, - T startValue, - T endValue, - EasingType easingType, - List easingArgs + double length, + T startValue, + T endValue, + EasingType easingType, + List easingArgs ) { public Keyframe(double length, T startValue, T endValue) { diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeLocation.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeLocation.java index aa287dae6..152ceb28e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeLocation.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeLocation.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; @@ -14,7 +12,6 @@ * @param startTick The animation tick time at the start of this {@code Keyframe} */ public record KeyframeLocation>( - T keyframe, - double startTick -) { -} + T keyframe, + double startTick +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeStack.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeStack.java index 91e3bbc88..34e395108 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeStack.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeStack.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; @@ -15,9 +13,9 @@ * Stores a triplet of {@link Keyframe Keyframes} in an ordered stack */ public record KeyframeStack>( - List xKeyframes, - List yKeyframes, - List zKeyframes + List xKeyframes, + List yKeyframes, + List zKeyframes ) { public KeyframeStack() { diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java index 5107bd073..0d2344e86 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event; @@ -20,10 +18,10 @@ public class CustomInstructionKeyframeEvent extends KeyFrameEvent { public CustomInstructionKeyframeEvent( - T entity, - double animationTick, - AnimationController controller, - CustomInstructionKeyframeData customInstructionKeyframeData + T entity, + double animationTick, + AnimationController controller, + CustomInstructionKeyframeData customInstructionKeyframeData ) { super(entity, animationTick, controller, customInstructionKeyframeData); } diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java index f65aed61c..1d59e5085 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event; @@ -19,7 +17,6 @@ * @see CustomInstructionKeyframeEvent * @see ParticleKeyframeEvent * @see SoundKeyframeEvent - * * @deprecated */ public abstract class KeyFrameEvent { diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java index 520753668..5ada20342 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event; @@ -20,10 +18,10 @@ public class ParticleKeyframeEvent extends KeyFrameEvent { public ParticleKeyframeEvent( - T animatable, - double animationTick, - AnimationController controller, - ParticleKeyframeData particleKeyFrameData + T animatable, + double animationTick, + AnimationController controller, + ParticleKeyframeData particleKeyFrameData ) { super(animatable, animationTick, controller, particleKeyFrameData); } diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java index efd790cba..c42f4ed73 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event; @@ -28,10 +26,10 @@ public class SoundKeyframeEvent extends KeyFrameEvent controller, - SoundKeyframeData keyFrameData + T entity, + double animationTick, + AnimationController controller, + SoundKeyframeData keyFrameData ) { super(entity, animationTick, controller, keyFrameData); } diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/CustomInstructionKeyframeData.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/CustomInstructionKeyframeData.java index 0d23c6d34..f07750361 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/CustomInstructionKeyframeData.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/CustomInstructionKeyframeData.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event.data; -import mod.azure.azurelib.core.keyframe.Keyframe; - import java.util.Objects; +import mod.azure.azurelib.core.keyframe.Keyframe; + /** * Custom instruction {@link Keyframe} instruction holder */ diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/KeyFrameData.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/KeyFrameData.java index 148a17e5d..2572cd91b 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/KeyFrameData.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/KeyFrameData.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event.data; -import mod.azure.azurelib.core.keyframe.Keyframe; - import java.util.Objects; +import mod.azure.azurelib.core.keyframe.Keyframe; + /** * Base class for custom {@link Keyframe} events.
    * diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/ParticleKeyframeData.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/ParticleKeyframeData.java index d9722f898..75b8d807a 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/ParticleKeyframeData.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/ParticleKeyframeData.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event.data; -import mod.azure.azurelib.core.keyframe.Keyframe; - import java.util.Objects; +import mod.azure.azurelib.core.keyframe.Keyframe; + /** * Particle {@link Keyframe} instruction holder */ diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/SoundKeyframeData.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/SoundKeyframeData.java index 5279e2edd..f7dc21846 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/SoundKeyframeData.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/SoundKeyframeData.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event.data; -import mod.azure.azurelib.core.keyframe.Keyframe; - import java.util.Objects; +import mod.azure.azurelib.core.keyframe.Keyframe; + /** * Sound {@link Keyframe} instruction holder */ diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Constant.java b/common/src/main/java/mod/azure/azurelib/core/math/Constant.java index ddf2e2d58..ef029f3c6 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Constant.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Constant.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Group.java b/common/src/main/java/mod/azure/azurelib/core/math/Group.java index a236f8962..29cd49e4c 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Group.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Group.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/IValue.java b/common/src/main/java/mod/azure/azurelib/core/math/IValue.java index d915a17f2..6b1383d29 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/IValue.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/IValue.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/MathBuilder.java b/common/src/main/java/mod/azure/azurelib/core/math/MathBuilder.java index 25e954c27..a936d60ad 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/MathBuilder.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/MathBuilder.java @@ -1,12 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import mod.azure.azurelib.common.internal.common.AzureLibException; import mod.azure.azurelib.core.math.functions.Function; import mod.azure.azurelib.core.math.functions.classic.*; @@ -19,19 +23,12 @@ import mod.azure.azurelib.core.math.functions.rounding.Trunc; import mod.azure.azurelib.core.math.functions.utility.*; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * Math builder This class is responsible for parsing math expressions provided by user in a string to an {@link IValue} * which can be used to compute some value dynamically using different math operators, variables and functions. It works * by first breaking down given string into a list of tokens and then putting them together in a binary tree-like - * {@link IValue}. - * TODO: maybe implement constant pool (to reuse same values)? - * TODO: maybe pre-compute constant expressions? + * {@link IValue}. TODO: maybe implement constant pool (to reuse same values)? TODO: maybe pre-compute constant + * expressions? */ public class MathBuilder { @@ -127,8 +124,8 @@ public String[] breakdown(String expression) throws AzureLibException { /* Amount of left and right brackets should be the same */ if (left != right) { throw new AzureLibException( - "Given expression '" + expression - + "' has more uneven amount of parenthesis, there are " + left + " open and " + right + " closed!" + "Given expression '" + expression + + "' has more uneven amount of parenthesis, there are " + left + " open and " + right + " closed!" ); } @@ -156,8 +153,8 @@ public List breakdownChars(String[] chars) { boolean isFirst = size == 0 && buffer.isEmpty(); boolean isOperatorBehind = size > 0 - && (this.isOperator(symbols.get(size - 1)) || symbols.get(size - 1).equals(",")) - && buffer.isEmpty(); + && (this.isOperator(symbols.get(size - 1)) || symbols.get(size - 1).equals(",")) + && buffer.isEmpty(); if (isFirst || isOperatorBehind) { buffer += s; @@ -289,9 +286,9 @@ public IValue parseSymbols(List symbols) throws Exception { Operation operation = this.operationForOperator((String) symbols.get(lastOp)); return new Operator( - operation, - this.parseSymbols(symbols.subList(0, lastOp)), - this.parseSymbols(symbols.subList(lastOp + 1, size)) + operation, + this.parseSymbols(symbols.subList(0, lastOp)), + this.parseSymbols(symbols.subList(lastOp + 1, size)) ); } @@ -366,9 +363,9 @@ protected IValue tryTernary(List symbols) throws Exception { if (questions == colons && question > 0 && question + 1 < colon && colon < size - 1) { return new Ternary( - this.parseSymbols(symbols.subList(0, question)), - this.parseSymbols(symbols.subList(question + 1, colon)), - this.parseSymbols(symbols.subList(colon + 1, size)) + this.parseSymbols(symbols.subList(0, question)), + this.parseSymbols(symbols.subList(question + 1, colon)), + this.parseSymbols(symbols.subList(colon + 1, size)) ); } diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Negate.java b/common/src/main/java/mod/azure/azurelib/core/math/Negate.java index c8ad7354e..e8a5b0785 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Negate.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Negate.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Operation.java b/common/src/main/java/mod/azure/azurelib/core/math/Operation.java index a5e4c5a30..10b710099 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Operation.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Operation.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; @@ -12,30 +10,34 @@ /** * Operation enumeration This enumeration provides different hardcoded enumerations of default math operators such - * addition, substraction, multiplication, division, modulo and power. - * TODO: maybe convert to classes (for the sake of API)? + * addition, substraction, multiplication, division, modulo and power. TODO: maybe convert to classes (for the sake of + * API)? */ public enum Operation { ADD("+", 1) { + @Override public double calculate(double a, double b) { return a + b; } }, SUB("-", 1) { + @Override public double calculate(double a, double b) { return a - b; } }, MUL("*", 2) { + @Override public double calculate(double a, double b) { return a * b; } }, DIV("/", 2) { + @Override public double calculate(double a, double b) { /* To avoid any exceptions */ @@ -43,60 +45,70 @@ public double calculate(double a, double b) { } }, MOD("%", 2) { + @Override public double calculate(double a, double b) { return a % b; } }, POW("^", 3) { + @Override public double calculate(double a, double b) { return Math.pow(a, b); } }, AND("&&", 5) { + @Override public double calculate(double a, double b) { return a != 0 && b != 0 ? 1 : 0; } }, OR("||", 5) { + @Override public double calculate(double a, double b) { return a != 0 || b != 0 ? 1 : 0; } }, LESS("<", 5) { + @Override public double calculate(double a, double b) { return a < b ? 1 : 0; } }, LESS_THAN("<=", 5) { + @Override public double calculate(double a, double b) { return a <= b ? 1 : 0; } }, GREATER_THAN(">=", 5) { + @Override public double calculate(double a, double b) { return a >= b ? 1 : 0; } }, GREATER(">", 5) { + @Override public double calculate(double a, double b) { return a > b ? 1 : 0; } }, EQUALS("==", 5) { + @Override public double calculate(double a, double b) { return equals(a, b) ? 1 : 0; } }, NOT_EQUALS("!=", 5) { + @Override public double calculate(double a, double b) { return !equals(a, b) ? 1 : 0; @@ -115,6 +127,7 @@ public double calculate(double a, double b) { * String-ified name of this operation */ public final String sign; + /** * Value of this operation in relation to other operations (i.e precedence importance) */ diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Operator.java b/common/src/main/java/mod/azure/azurelib/core/math/Operator.java index e4b50651e..5c8fb94e2 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Operator.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Operator.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Ternary.java b/common/src/main/java/mod/azure/azurelib/core/math/Ternary.java index 764460b30..3c2c3033a 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Ternary.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Ternary.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Variable.java b/common/src/main/java/mod/azure/azurelib/core/math/Variable.java index b877e78af..d063b01fc 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Variable.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Variable.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/Function.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/Function.java index 9b0679342..845513e7a 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/Function.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/Function.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions; @@ -22,10 +20,10 @@ public abstract class Function implements IValue { protected Function(IValue[] values, String name) throws Exception { if (values.length < this.getRequiredArguments()) { String message = String.format( - "Function '%s' requires at least %s arguments. %s are given!", - this.getName(), - this.getRequiredArguments(), - values.length + "Function '%s' requires at least %s arguments. %s are given!", + this.getName(), + this.getRequiredArguments(), + values.length ); throw new Exception(message); diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ACos.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ACos.java index f05dca068..8386ec30e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ACos.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ACos.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ASin.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ASin.java index a91726528..d4f1a640f 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ASin.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ASin.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan.java index 5c0da958e..409e58660 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan2.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan2.java index 4357a8118..ad484f32b 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan2.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan2.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Abs.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Abs.java index 6e2c4da4f..f13177d45 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Abs.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Abs.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Cos.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Cos.java index 0ccd43ca8..9e6a051f7 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Cos.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Cos.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Exp.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Exp.java index d6d29f55f..2a69cbb29 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Exp.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Exp.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Ln.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Ln.java index 647f5db93..d7ca8b645 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Ln.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Ln.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Mod.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Mod.java index bb21e645f..e5c1c2012 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Mod.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Mod.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pi.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pi.java index 1d0d8eaf2..907d74938 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pi.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pi.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pow.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pow.java index 12ee336f5..532183325 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pow.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pow.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sin.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sin.java index a55531a60..243194293 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sin.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sin.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sqrt.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sqrt.java index 0329f16ad..31661858d 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sqrt.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sqrt.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Clamp.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Clamp.java index 8f8d35dbb..9cc2ccc05 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Clamp.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Clamp.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.limit; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Max.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Max.java index 575ba4577..3c38c63f6 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Max.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Max.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.limit; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Min.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Min.java index 753696f85..a2c2d9830 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Min.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Min.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.limit; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Ceil.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Ceil.java index c95fdbcdd..dbecf3ba8 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Ceil.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Ceil.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.rounding; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Floor.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Floor.java index f4c042fd5..d71637316 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Floor.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Floor.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.rounding; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Round.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Round.java index 61deed22e..27ecd7e8e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Round.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Round.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.rounding; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Trunc.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Trunc.java index 486d0b391..d81fd55fc 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Trunc.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Trunc.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.rounding; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRoll.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRoll.java index 6aa65cad8..df12b4299 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRoll.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRoll.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRollInteger.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRollInteger.java index 6a1af5ab8..d5d92b9cf 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRollInteger.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRollInteger.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/HermiteBlend.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/HermiteBlend.java index a2be1f341..097989541 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/HermiteBlend.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/HermiteBlend.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Lerp.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Lerp.java index ff2a7f48d..9a30fe42e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Lerp.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Lerp.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/LerpRotate.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/LerpRotate.java index 2d58605aa..ff2198d74 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/LerpRotate.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/LerpRotate.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Random.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Random.java index 588f4c029..34ab843ed 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Random.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Random.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/RandomInteger.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/RandomInteger.java index a0d75b624..587ddf5b3 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/RandomInteger.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/RandomInteger.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/LazyVariable.java b/common/src/main/java/mod/azure/azurelib/core/molang/LazyVariable.java index c35fa9d99..27869155d 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/LazyVariable.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/LazyVariable.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang; -import mod.azure.azurelib.core.math.Variable; - import java.util.function.DoubleSupplier; +import mod.azure.azurelib.core.math.Variable; + /** * Lazy override of Variable, to allow for deferred value calculation.
    * Optimises rendering as values are not touched until needed (if at all) diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/MolangException.java b/common/src/main/java/mod/azure/azurelib/core/molang/MolangException.java index ec0ab8eb0..3ad3f53a5 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/MolangException.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/MolangException.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/MolangParser.java b/common/src/main/java/mod/azure/azurelib/core/molang/MolangParser.java index 31e3059cb..cb95791a8 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/MolangParser.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/MolangParser.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang; @@ -10,6 +8,12 @@ import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.function.DoubleSupplier; + import mod.azure.azurelib.core.math.Constant; import mod.azure.azurelib.core.math.IValue; import mod.azure.azurelib.core.math.MathBuilder; @@ -20,11 +24,6 @@ import mod.azure.azurelib.core.molang.functions.CosDegrees; import mod.azure.azurelib.core.molang.functions.SinDegrees; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.function.DoubleSupplier; - /** * Utility class for parsing and utilising MoLang functions and expressions * @@ -103,8 +102,8 @@ public static MolangValue parseExpression(String expression) throws MolangExcept * Parse a single Molang statement */ protected static MolangValue parseOneLine( - String expression, - MolangCompoundValue currentStatement + String expression, + MolangCompoundValue currentStatement ) throws MolangException { if (expression.startsWith(RETURN)) { try { @@ -118,8 +117,8 @@ protected static MolangValue parseOneLine( List symbols = INSTANCE.breakdownChars(INSTANCE.breakdown(expression)); if ( - symbols.size() >= 3 && symbols.get(0) instanceof String name && INSTANCE.isVariable(symbols.get(0)) - && symbols.get(1).equals("=") + symbols.size() >= 3 && symbols.get(0) instanceof String name && INSTANCE.isVariable(symbols.get(0)) + && symbols.get(1).equals("=") ) { symbols = symbols.subList(2, symbols.size()); LazyVariable variable; @@ -249,7 +248,7 @@ public double getAsDouble() { * * @param name The name of the variable to get * @return The registered {@code LazyVariable} instance, or a newly registered instance if one wasn't registered - * previously + * previously */ @Override public LazyVariable getVariable(String name) { diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/MolangQueries.java b/common/src/main/java/mod/azure/azurelib/core/molang/MolangQueries.java index fbcdac346..b56f7d4c4 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/MolangQueries.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/MolangQueries.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangCompoundValue.java b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangCompoundValue.java index 08f5c1f10..92bfdc124 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangCompoundValue.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangCompoundValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang.expressions; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core.molang.LazyVariable; import java.util.List; import java.util.Map; import java.util.StringJoiner; +import mod.azure.azurelib.core.molang.LazyVariable; + /** * An extension of the {@link MolangValue} class, allowing for compound expressions. */ diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangValue.java b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangValue.java index 5fe2d0b1e..3cf7d0e54 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangValue.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangValue.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang.expressions; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangVariableHolder.java b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangVariableHolder.java index ad5cfd1a5..00207e6ed 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangVariableHolder.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangVariableHolder.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang.expressions; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/functions/CosDegrees.java b/common/src/main/java/mod/azure/azurelib/core/molang/functions/CosDegrees.java index 6ac470e0e..204baffa2 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/functions/CosDegrees.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/functions/CosDegrees.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang.functions; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/functions/SinDegrees.java b/common/src/main/java/mod/azure/azurelib/core/molang/functions/SinDegrees.java index cb7d22d1e..fbc8e2ff8 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/functions/SinDegrees.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/functions/SinDegrees.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang.functions; diff --git a/common/src/main/java/mod/azure/azurelib/core/object/Axis.java b/common/src/main/java/mod/azure/azurelib/core/object/Axis.java index 44787163b..9e3b00162 100644 --- a/common/src/main/java/mod/azure/azurelib/core/object/Axis.java +++ b/common/src/main/java/mod/azure/azurelib/core/object/Axis.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.object; diff --git a/common/src/main/java/mod/azure/azurelib/core/object/Color.java b/common/src/main/java/mod/azure/azurelib/core/object/Color.java index a79d17644..969544043 100644 --- a/common/src/main/java/mod/azure/azurelib/core/object/Color.java +++ b/common/src/main/java/mod/azure/azurelib/core/object/Color.java @@ -61,10 +61,10 @@ public static Color ofRGB(int r, int g, int b) { */ public static Color ofRGBA(float r, float g, float b, float a) { return ofRGBA( - (int) (r * 255f + 0.5), - (int) (g * 255f + 0.5f), - (int) (b * 255f + 0.5f), - (int) (a * 255f + 0.5f) + (int) (r * 255f + 0.5), + (int) (g * 255f + 0.5f), + (int) (b * 255f + 0.5f), + (int) (a * 255f + 0.5f) ); } @@ -196,10 +196,10 @@ public Color brighter(double factor) { b = i; return ofRGBA( - Math.min((int) (r / (1 / factor)), 255), - Math.min((int) (g / (1 / factor)), 255), - Math.min((int) (b / (1 / factor)), 255), - getAlpha() + Math.min((int) (r / (1 / factor)), 255), + Math.min((int) (g / (1 / factor)), 255), + Math.min((int) (b / (1 / factor)), 255), + getAlpha() ); } @@ -212,10 +212,10 @@ public Color brighter(double factor) { */ public Color darker(float factor) { return ofRGBA( - Math.max((int) (getRed() * (1 / factor)), 0), - Math.max((int) (getGreen() * (1 / factor)), 0), - Math.max((int) (getBlue() * (1 / factor)), 0), - getAlpha() + Math.max((int) (getRed() * (1 / factor)), 0), + Math.max((int) (getGreen() * (1 / factor)), 0), + Math.max((int) (getBlue() * (1 / factor)), 0), + getAlpha() ); } diff --git a/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java b/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java index f5bc93e16..91e9e9bf7 100644 --- a/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java +++ b/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.object; diff --git a/common/src/main/java/mod/azure/azurelib/core/object/PlayState.java b/common/src/main/java/mod/azure/azurelib/core/object/PlayState.java index 36f77de0c..a6a1a5e22 100644 --- a/common/src/main/java/mod/azure/azurelib/core/object/PlayState.java +++ b/common/src/main/java/mod/azure/azurelib/core/object/PlayState.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.object; diff --git a/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java b/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java index 570ca63f5..403fabc54 100644 --- a/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java +++ b/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java b/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java index 828ba20fc..0308a9032 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; @@ -10,24 +8,28 @@ public enum Interpolation { LINEAR("linear") { + @Override public float interpolate(float a, float b, float x) { return Interpolations.lerp(a, b, x); } }, QUAD_IN("quad_in") { + @Override public float interpolate(float a, float b, float x) { return a + (b - a) * x * x; } }, QUAD_OUT("quad_out") { + @Override public float interpolate(float a, float b, float x) { return a - (b - a) * x * (x - 2); } }, QUAD_INOUT("quad_inout") { + @Override public float interpolate(float a, float b, float x) { x *= 2; @@ -41,12 +43,14 @@ public float interpolate(float a, float b, float x) { } }, CUBIC_IN("cubic_in") { + @Override public float interpolate(float a, float b, float x) { return a + (b - a) * x * x * x; } }, CUBIC_OUT("cubic_out") { + @Override public float interpolate(float a, float b, float x) { x -= 1; @@ -54,6 +58,7 @@ public float interpolate(float a, float b, float x) { } }, CUBIC_INOUT("cubic_inout") { + @Override public float interpolate(float a, float b, float x) { x *= 2; @@ -67,18 +72,21 @@ public float interpolate(float a, float b, float x) { } }, EXP_IN("exp_in") { + @Override public float interpolate(float a, float b, float x) { return a + (b - a) * (float) Math.pow(2, 10 * (x - 1)); } }, EXP_OUT("exp_out") { + @Override public float interpolate(float a, float b, float x) { return a + (b - a) * (float) (-Math.pow(2, -10 * x) + 1); } }, EXP_INOUT("exp_inout") { + @Override public float interpolate(float a, float b, float x) { if (x == 0) diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/Interpolations.java b/common/src/main/java/mod/azure/azurelib/core/utils/Interpolations.java index b17c9f1c1..6b414d69e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/Interpolations.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/Interpolations.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/JsonUtils.java b/common/src/main/java/mod/azure/azurelib/core/utils/JsonUtils.java index afaeaada2..4d3a95901 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/JsonUtils.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/JsonUtils.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/MathHelper.java b/common/src/main/java/mod/azure/azurelib/core/utils/MathHelper.java index 2650a5e6b..3c28ce431 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/MathHelper.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/MathHelper.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/MathUtils.java b/common/src/main/java/mod/azure/azurelib/core/utils/MathUtils.java index 4e21ba43a..b83d1f92f 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/MathUtils.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/MathUtils.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/Timer.java b/common/src/main/java/mod/azure/azurelib/core/utils/Timer.java index 460ced003..0753773bf 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/Timer.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/Timer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; @@ -10,7 +8,9 @@ public class Timer { private final long duration; + private boolean enabled; + private long time; public Timer(long duration) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java b/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java index f5d38109b..d9a35b9a4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java @@ -32,9 +32,9 @@ protected final CompletableFuture loadResources( BiConsumer map ) { return CompletableFuture.supplyAsync( - () -> resourceManager.listResources(type, fileName -> fileName.toString().endsWith(".json")), - executor - ) + () -> resourceManager.listResources(type, fileName -> fileName.toString().endsWith(".json")), + executor + ) .thenApplyAsync(resources -> { var tasks = new Object2ObjectOpenHashMap>(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java index c026e5c6e..4a450c9f1 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java @@ -1,10 +1,11 @@ package mod.azure.azurelib.core2.animation; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; + import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimTriggerPacket; import mod.azure.azurelib.common.platform.Services; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; -import net.minecraft.world.entity.Entity; -import org.jetbrains.annotations.Nullable; public class AzAnimationDispatcher { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index feffd23ea..fb310d555 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -1,6 +1,11 @@ package mod.azure.azurelib.core2.animation; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core.state.BoneSnapshot; @@ -11,16 +16,13 @@ import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; import mod.azure.azurelib.core2.animation.primitive.AzStage; import mod.azure.azurelib.core2.model.AzBakedModel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; public class AzAnimationProcessor { private static final Logger LOGGER = LoggerFactory.getLogger(AzAnimationProcessor.class); private final AzAnimator animator; + private final Map bonesByName; public boolean reloadAnimations; @@ -52,9 +54,9 @@ public Queue buildAnimationQueue(T animatable, AzRawAnimation if (animation == null) { LOGGER.warn( - "Unable to find animation: {} for {}", - stage.animationName(), - animatable.getClass().getSimpleName() + "Unable to find animation: {} for {}", + stage.animationName(), + animatable.getClass().getSimpleName() ); return null; } else { @@ -105,13 +107,13 @@ public void tickAnimation(T animatable, AzAnimationState event) { if (rotXPoint != null && rotYPoint != null && rotZPoint != null) { bone.setRotX( - (float) EasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() + (float) EasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() ); bone.setRotY( - (float) EasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() + (float) EasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() ); bone.setRotZ( - (float) EasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() + (float) EasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() ); snapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); snapshot.startRotAnim(); @@ -150,18 +152,18 @@ public void tickAnimation(T animatable, AzAnimationState event) { saveSnapshot.stopRotAnim(animTime); double percentageReset = Math.min( - (animTime - saveSnapshot.getLastResetRotationTick()) / resetTickLength, - 1 + (animTime - saveSnapshot.getLastResetRotationTick()) / resetTickLength, + 1 ); bone.setRotX( - (float) Interpolations.lerp(saveSnapshot.getRotX(), initialSnapshot.getRotX(), percentageReset) + (float) Interpolations.lerp(saveSnapshot.getRotX(), initialSnapshot.getRotX(), percentageReset) ); bone.setRotY( - (float) Interpolations.lerp(saveSnapshot.getRotY(), initialSnapshot.getRotY(), percentageReset) + (float) Interpolations.lerp(saveSnapshot.getRotY(), initialSnapshot.getRotY(), percentageReset) ); bone.setRotZ( - (float) Interpolations.lerp(saveSnapshot.getRotZ(), initialSnapshot.getRotZ(), percentageReset) + (float) Interpolations.lerp(saveSnapshot.getRotZ(), initialSnapshot.getRotZ(), percentageReset) ); if (percentageReset >= 1) { @@ -177,7 +179,10 @@ public void tickAnimation(T animatable, AzAnimationState event) { saveSnapshot.stopPosAnim(animTime); } - var percentageReset = Math.min((animTime - saveSnapshot.getLastResetPositionTick()) / resetTickLength, 1); + var percentageReset = Math.min( + (animTime - saveSnapshot.getLastResetPositionTick()) / resetTickLength, + 1 + ); bone.setPosX( (float) Interpolations.lerp( @@ -214,7 +219,10 @@ public void tickAnimation(T animatable, AzAnimationState event) { saveSnapshot.stopScaleAnim(animTime); } - double percentageReset = Math.min((animTime - saveSnapshot.getLastResetScaleTick()) / resetTickLength, 1); + double percentageReset = Math.min( + (animTime - saveSnapshot.getLastResetScaleTick()) / resetTickLength, + 1 + ); bone.setScaleX( (float) Interpolations.lerp(saveSnapshot.getScaleX(), initialSnapshot.getScaleX(), percentageReset) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java index 749861c6d..1f31a660e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java @@ -1,14 +1,15 @@ package mod.azure.azurelib.core2.animation; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +import java.util.Map; +import java.util.Objects; + import mod.azure.azurelib.core.object.DataTicket; import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; -import java.util.Map; -import java.util.Objects; - /** * Animation state handler for end-users.
    * This is where users would set their selected animation to play, stop the controller, or any number of other @@ -27,7 +28,9 @@ public class AzAnimationState { private final boolean isMoving; private final Map, Object> extraData = new Object2ObjectOpenHashMap<>(); + public double animationTick; + protected AzAnimationController controller; public AzAnimationState(T animatable, float limbSwing, float limbSwingAmount, float partialTick, boolean isMoving) { @@ -157,8 +160,8 @@ public boolean isCurrentAnimation(AzRawAnimation animation) { } /** - * Similar to {@link AzAnimationState#isCurrentAnimation}, but additionally checks the current stage of the animation - * by name.
    + * Similar to {@link AzAnimationState#isCurrentAnimation}, but additionally checks the current stage of the + * animation by name.
    * This can be used to check if a multi-stage animation has reached a given stage (if it is running at all)
    * Note that this will still return true even if the animation has finished, matching with the last animation stage * in the {@link AzRawAnimation} last provided @@ -168,9 +171,9 @@ public boolean isCurrentAnimation(AzRawAnimation animation) { */ public boolean isCurrentAnimationStage(String name) { return getController().getCurrentAnimation() != null && getController().getCurrentAnimation() - .animation() - .name() - .equals(name); + .animation() + .name() + .equals(name); } /** diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index f8fe04da7..eff7412cf 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -1,5 +1,11 @@ package mod.azure.azurelib.core2.animation; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.AzureLibException; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; @@ -9,26 +15,26 @@ import mod.azure.azurelib.core2.animation.cache.AzBoneSnapshotCache; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; -import net.minecraft.client.Minecraft; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; - -import java.util.Objects; public abstract class AzAnimator { // Remnants from AnimatableManager. private final AzAnimationControllerContainer animationControllerContainer; + private final AzAnimationProcessor animationProcessor; + private final AzBoneSnapshotCache boneSnapshotCache; // Remnants from AnimatableManager. private double lastUpdateTime; + private boolean isFirstTick = true; + private double firstTickTime = -1; // Remnants from GeoModel. private double animTime; + private double lastGameTickTime; protected AzAnimator() { @@ -38,6 +44,7 @@ protected AzAnimator() { } public abstract void registerControllers(AzAnimationControllerContainer animationControllerContainer); + public abstract @NotNull ResourceLocation getAnimationLocation(T animatable); public void animate(T animatable, AzAnimationState animationState) { @@ -53,9 +60,9 @@ public void animate(T animatable, AzAnimationState animationState) { boolean isReRender = !isFirstTick && currentFrameTime == lastUpdateTime; // TODO: Figure out why this was here to begin with. -// if (isReRender && instanceId == this.lastRenderedInstance) { -// return; -// } + // if (isReRender && instanceId == this.lastRenderedInstance) { + // return; + // } if (!isReRender && (!minecraft.isPaused() || shouldPlayAnimsWhileGamePaused())) { this.lastUpdateTime = currentFrameTime; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java index 7f0225580..e09894262 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java @@ -3,6 +3,9 @@ import org.jetbrains.annotations.Nullable; public interface AzAnimatorAccessor { - @Nullable AzAnimator getAnimator(); + + @Nullable + AzAnimator getAnimator(); + void setAnimator(AzAnimator animator); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java index aaa170058..7e17087b4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java @@ -1,9 +1,6 @@ package mod.azure.azurelib.core2.animation.cache; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.internal.common.loading.FileLoader; -import mod.azure.azurelib.core2.AzResourceCache; -import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; import org.jetbrains.annotations.Nullable; @@ -12,6 +9,10 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import mod.azure.azurelib.common.internal.common.loading.FileLoader; +import mod.azure.azurelib.core2.AzResourceCache; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; + public class AzBakedAnimationCache extends AzResourceCache { private static final AzBakedAnimationCache INSTANCE = new AzBakedAnimationCache(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java index 9eb553f3a..406941233 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java @@ -1,10 +1,11 @@ package mod.azure.azurelib.core2.animation.cache; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.core.state.BoneSnapshot; import java.util.Map; +import mod.azure.azurelib.core.state.BoneSnapshot; + public class AzBoneSnapshotCache { private final Map boneSnapshotsByName; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 77dfc0a86..82451cf0b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -2,6 +2,19 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.Set; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; + import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core.keyframe.AnimationPoint; @@ -19,7 +32,6 @@ import mod.azure.azurelib.core2.animation.AzAnimationProcessor; import mod.azure.azurelib.core2.animation.AzAnimationState; import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; import mod.azure.azurelib.core2.animation.controller.handler.AzAnimationStateHandler; import mod.azure.azurelib.core2.animation.controller.handler.AzCustomKeyframeHandler; import mod.azure.azurelib.core2.animation.controller.handler.AzParticleKeyframeHandler; @@ -28,19 +40,8 @@ import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Queue; -import java.util.Set; -import java.util.function.Function; -import java.util.function.ToDoubleFunction; /** * The actual controller that handles the playing and usage of animations, including their various keyframes and @@ -52,21 +53,35 @@ public class AzAnimationController { protected static final Logger LOGGER = LoggerFactory.getLogger(AzAnimationController.class); protected final String name; + protected final AzAnimationStateHandler stateHandler; + protected final Map boneAnimationQueues = new Object2ObjectOpenHashMap<>(); + protected final Map boneSnapshots = new Object2ObjectOpenHashMap<>(); + protected final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); + protected final Set executedKeyFrames = new ObjectOpenHashSet<>(); + private final AzAnimator animator; protected Queue animationQueue = new LinkedList<>(); + protected boolean isJustStarting = false; + protected boolean needsAnimationReload = false; + protected boolean shouldResetTick = false; + protected boolean justStartedTransition = false; + protected AzSoundKeyframeHandler soundKeyframeHandler = null; + protected AzParticleKeyframeHandler particleKeyframeHandler = null; + protected AzCustomKeyframeHandler customKeyframeHandler = null; + protected AzRawAnimation triggeredAnimation = null; protected boolean handlingTriggeredAnimations = false; @@ -84,6 +99,7 @@ public class AzAnimationController { protected ToDoubleFunction animationSpeedModifier = obj -> 1d; protected Function overrideEasingTypeFunction = obj -> null; + protected boolean justStopped = true; // FIXME: There used to be more constructors here. We should bring those back as a builder pattern. @@ -110,8 +126,8 @@ public AzAnimationController( } /** - * Applies the given {@link AzSoundKeyframeHandler} to this controller, for handling {@link AzSoundKeyframeEvent sound - * keyframe instructions}. + * Applies the given {@link AzSoundKeyframeHandler} to this controller, for handling {@link AzSoundKeyframeEvent + * sound keyframe instructions}. * * @return this */ @@ -122,8 +138,8 @@ public AzAnimationController setSoundKeyframeHandler(AzSoundKeyframeHandler setParticleKeyframeHandler(AzParticleKeyframeHan * @return this */ public AzAnimationController setCustomInstructionKeyframeHandler( - AzCustomKeyframeHandler customInstructionHandler + AzCustomKeyframeHandler customInstructionHandler ) { this.customKeyframeHandler = customInstructionHandler; @@ -398,7 +414,9 @@ protected PlayState handleAnimationState(AzAnimationState state) { setAnimation(state.getAnimatable(), triggeredAnimation); if ( - !hasAnimationFinished() && (!handlingTriggeredAnimations || stateHandler.handle(state) == PlayState.CONTINUE) + !hasAnimationFinished() && (!handlingTriggeredAnimations || stateHandler.handle( + state + ) == PlayState.CONTINUE) ) { return PlayState.CONTINUE; } @@ -502,38 +520,38 @@ public void process( if (!rotationKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addNextRotation( - null, - adjustedTick, - transitionLength, - boneSnapshot, - bone.getInitialSnapshot(), - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) + null, + adjustedTick, + transitionLength, + boneSnapshot, + bone.getInitialSnapshot(), + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) ); } if (!positionKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addNextPosition( - null, - adjustedTick, - transitionLength, - boneSnapshot, - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) + null, + adjustedTick, + transitionLength, + boneSnapshot, + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) ); } if (!scaleKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addNextScale( - null, - adjustedTick, - transitionLength, - boneSnapshot, - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) + null, + adjustedTick, + transitionLength, + boneSnapshot, + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) ); } } @@ -549,7 +567,12 @@ public void process( * @param crashWhenCantFindBone Whether the controller should throw an exception when unable to find the required * bone, or continue with the remaining bones */ - protected void processCurrentAnimation(T animatable, double adjustedTick, double seekTime, boolean crashWhenCantFindBone) { + protected void processCurrentAnimation( + T animatable, + double adjustedTick, + double seekTime, + boolean crashWhenCantFindBone + ) { if (adjustedTick >= currentAnimation.animation().length()) { if ( currentAnimation.loopType().shouldPlayAgain(animatable, this, this.currentAnimation.animation()) @@ -597,25 +620,25 @@ protected void processCurrentAnimation(T animatable, double adjustedTick, double if (!rotationKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addRotations( - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) ); } if (!positionKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addPositions( - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) ); } if (!scaleKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addScales( - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) ); } } @@ -626,15 +649,15 @@ protected void processCurrentAnimation(T animatable, double adjustedTick, double if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { if (soundKeyframeHandler == null) { LOGGER.warn( - "Sound Keyframe found for {} -> {}, but no keyframe handler registered", - animatable.getClass().getSimpleName(), - getName() + "Sound Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + getName() ); break; } soundKeyframeHandler.handle( - new AzSoundKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) + new AzSoundKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) ); } } @@ -643,41 +666,44 @@ protected void processCurrentAnimation(T animatable, double adjustedTick, double if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { if (particleKeyframeHandler == null) { LOGGER.warn( - "Particle Keyframe found for {} -> {}, but no keyframe handler registered", - animatable.getClass().getSimpleName(), - getName() + "Particle Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + getName() ); break; } particleKeyframeHandler.handle( - new AzParticleKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) + new AzParticleKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) ); } } for ( - var keyframeData : currentAnimation.animation() + var keyframeData : currentAnimation.animation() .keyFrames() .customInstructions() ) { if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { if (customKeyframeHandler == null) { LOGGER.warn( - "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", - animatable.getClass().getSimpleName(), - getName() + "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + getName() ); break; } customKeyframeHandler.handle( - new AzCustomInstructionKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) + new AzCustomInstructionKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) ); } } - if (this.transitionLength == 0 && this.shouldResetTick && this.animationState == AzAnimationControllerState.TRANSITIONING) { + if ( + this.transitionLength == 0 && this.shouldResetTick + && this.animationState == AzAnimationControllerState.TRANSITIONING + ) { this.currentAnimation = this.animationQueue.poll(); } } @@ -696,15 +722,15 @@ protected void createInitialQueues(Collection modelRendererList) { } /** - * Cache the relevant {@link BoneSnapshot BoneSnapshots} for the current {@link AzQueuedAnimation} - * for animation lerping + * Cache the relevant {@link BoneSnapshot BoneSnapshots} for the current {@link AzQueuedAnimation} for animation + * lerping * * @param animation The {@code QueuedAnimation} to filter {@code BoneSnapshots} for * @param snapshots The master snapshot collection to pull filter from */ protected void saveSnapshotsForAnimation( - AzQueuedAnimation animation, - Map snapshots + AzQueuedAnimation animation, + Map snapshots ) { if (animation.animation().boneAnimations() == null) { return; @@ -726,7 +752,7 @@ protected void saveSnapshotsForAnimation( * * @param tick The currently used tick value * @return 0 if {@link AzAnimationController#shouldResetTick} is set to false, or a - * {@link AzAnimationController#animationSpeedModifier} modified value otherwise + * {@link AzAnimationController#animationSpeedModifier} modified value otherwise */ protected double adjustTick(T animatable, double tick) { if (!shouldResetTick) { @@ -785,8 +811,8 @@ protected AnimationPoint getAnimationPointAtTick( * @return A new {@code KeyFrameLocation} containing the current {@code KeyFrame} and the tick time used to find it */ protected KeyframeLocation> getCurrentKeyFrameLocation( - List> frames, - double ageInTicks + List> frames, + double ageInTicks ) { var totalFrameTime = 0; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java index d67b7d3e8..63224aace 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java @@ -5,4 +5,4 @@ public enum AzAnimationControllerState { TRANSITIONING, PAUSED, STOPPED; -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java index eee1fea77..38ca3c3e8 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java @@ -4,9 +4,9 @@ import mod.azure.azurelib.core2.animation.AzAnimationState; /** - * Every render frame, the {@code AzAnimationController} will call this handler for each animatable that is - * being rendered. This handler defines which animation should be currently playing, and returning a - * {@link PlayState} to tell the controller what to do next.
    + * Every render frame, the {@code AzAnimationController} will call this handler for each animatable that is being + * rendered. This handler defines which animation should be currently playing, and returning a {@link PlayState} to tell + * the controller what to do next.
    * Example Usage:
    * *
    {@code
    @@ -31,4 +31,4 @@ public interface AzAnimationStateHandler {
          * {@code PlayState.CONTINUE} return.
          */
         PlayState handle(AzAnimationState state);
    -}
    \ No newline at end of file
    +}
    diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzCustomKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzCustomKeyframeHandler.java
    index 12c782102..014828458 100644
    --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzCustomKeyframeHandler.java
    +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzCustomKeyframeHandler.java
    @@ -11,4 +11,4 @@
     public interface AzCustomKeyframeHandler {
     
         void handle(AzCustomInstructionKeyframeEvent event);
    -}
    \ No newline at end of file
    +}
    diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzParticleKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzParticleKeyframeHandler.java
    index fe80c4381..864f459da 100644
    --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzParticleKeyframeHandler.java
    +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzParticleKeyframeHandler.java
    @@ -11,4 +11,4 @@
     public interface AzParticleKeyframeHandler {
     
         void handle(AzParticleKeyframeEvent event);
    -}
    \ No newline at end of file
    +}
    diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzSoundKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzSoundKeyframeHandler.java
    index a0ed97dd0..55b709723 100644
    --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzSoundKeyframeHandler.java
    +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzSoundKeyframeHandler.java
    @@ -11,4 +11,4 @@
     public interface AzSoundKeyframeHandler {
     
         void handle(AzSoundKeyframeEvent event);
    -}
    \ No newline at end of file
    +}
    diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java
    index c850a9ad6..8eb37ea4d 100644
    --- a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java
    +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java
    @@ -10,10 +10,10 @@
     public class AzCustomInstructionKeyframeEvent extends AzKeyFrameEvent {
     
         public AzCustomInstructionKeyframeEvent(
    -            T entity,
    -            double animationTick,
    -            AzAnimationController controller,
    -            CustomInstructionKeyframeData customInstructionKeyframeData
    +        T entity,
    +        double animationTick,
    +        AzAnimationController controller,
    +        CustomInstructionKeyframeData customInstructionKeyframeData
         ) {
             super(entity, animationTick, controller, customInstructionKeyframeData);
         }
    diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzKeyFrameEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzKeyFrameEvent.java
    index e2e24fba6..2f8720d4c 100644
    --- a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzKeyFrameEvent.java
    +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzKeyFrameEvent.java
    @@ -22,7 +22,12 @@ public abstract class AzKeyFrameEvent {
     
         private final E eventKeyFrame;
     
    -    protected AzKeyFrameEvent(T animatable, double animationTick, AzAnimationController controller, E eventKeyFrame) {
    +    protected AzKeyFrameEvent(
    +        T animatable,
    +        double animationTick,
    +        AzAnimationController controller,
    +        E eventKeyFrame
    +    ) {
             this.animatable = animatable;
             this.animationTick = animationTick;
             this.controller = controller;
    diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java
    index 0d0c172d7..59221de64 100644
    --- a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java
    +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java
    @@ -1,8 +1,6 @@
     /**
    - * This class is a fork of the matching class found in the Geckolib repository.
    - * Original source: https://github.com/bernie-g/geckolib
    - * Copyright © 2024 Bernie-G.
    - * Licensed under the MIT License.
    + * This class is a fork of the matching class found in the Geckolib repository. Original source:
    + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License.
      * https://github.com/bernie-g/geckolib/blob/main/LICENSE
      */
     package mod.azure.azurelib.core2.animation.event;
    diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java
    index ffd2fb663..1a074a5d5 100644
    --- a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java
    +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java
    @@ -1,8 +1,6 @@
     /**
    - * This class is a fork of the matching class found in the Geckolib repository.
    - * Original source: https://github.com/bernie-g/geckolib
    - * Copyright © 2024 Bernie-G.
    - * Licensed under the MIT License.
    + * This class is a fork of the matching class found in the Geckolib repository. Original source:
    + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License.
      * https://github.com/bernie-g/geckolib/blob/main/LICENSE
      */
     package mod.azure.azurelib.core2.animation.event;
    @@ -26,10 +24,10 @@ public class AzSoundKeyframeEvent extends AzKeyFrameEvent controller,
    -            SoundKeyframeData keyFrameData
    +        T entity,
    +        double animationTick,
    +        AzAnimationController controller,
    +        SoundKeyframeData keyFrameData
         ) {
             super(entity, animationTick, controller, keyFrameData);
         }
    diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java
    index 3a4d9a409..0fdae43d2 100644
    --- a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java
    +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java
    @@ -1,5 +1,10 @@
     package mod.azure.azurelib.core2.animation.impl;
     
    +import net.minecraft.client.Minecraft;
    +import net.minecraft.util.Mth;
    +import net.minecraft.world.entity.Entity;
    +import net.minecraft.world.entity.LivingEntity;
    +
     import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity;
     import mod.azure.azurelib.common.api.common.animatable.GeoItem;
     import mod.azure.azurelib.common.internal.client.util.RenderUtils;
    @@ -7,14 +12,15 @@
     import mod.azure.azurelib.core.molang.MolangQueries;
     import mod.azure.azurelib.core2.animation.AzAnimationState;
     import mod.azure.azurelib.core2.animation.AzAnimator;
    -import net.minecraft.client.Minecraft;
    -import net.minecraft.util.Mth;
    -import net.minecraft.world.entity.Entity;
    -import net.minecraft.world.entity.LivingEntity;
     
     public abstract class AzEntityAnimator extends AzAnimator {
     
    -    public AzAnimationState createAnimationState(T animatable, float limbSwing, float limbSwingAmount, float partialTick) {
    +    public AzAnimationState createAnimationState(
    +        T animatable,
    +        float limbSwing,
    +        float limbSwingAmount,
    +        float partialTick
    +    ) {
             var velocity = animatable.getDeltaMovement();
             var avgVelocity = (float) (Math.abs(velocity.x) + Math.abs(velocity.z) / 2f);
             var motionThreshold = getMotionAnimThreshold(animatable);
    @@ -41,7 +47,10 @@ protected void applyMolangQueries(T entity, double animTime) {
             );
             parser.setMemoizedValue(MolangQueries.IS_ON_GROUND, () -> RenderUtils.booleanToFloat(entity.onGround()));
             parser.setMemoizedValue(MolangQueries.IS_IN_WATER, () -> RenderUtils.booleanToFloat(entity.isInWater()));
    -        parser.setMemoizedValue(MolangQueries.IS_IN_WATER_OR_RAIN, () -> RenderUtils.booleanToFloat(entity.isInWaterOrRain()));
    +        parser.setMemoizedValue(
    +            MolangQueries.IS_IN_WATER_OR_RAIN,
    +            () -> RenderUtils.booleanToFloat(entity.isInWaterOrRain())
    +        );
             parser.setMemoizedValue(MolangQueries.IS_ON_FIRE, () -> RenderUtils.booleanToFloat(entity.isOnFire()));
     
             if (entity instanceof LivingEntity livingEntity) {
    @@ -59,8 +68,8 @@ protected void applyMolangQueries(T entity, double animTime) {
          * Determines the threshold value before the animatable should be considered moving for animation purposes.
    * The default value and usage for this varies depending on the renderer.
    *
      - *
    • For entities, it represents the averaged lateral velocity of the object.
    • - *
    • For {@link GeoBlockEntity Tile Entities} and {@link GeoItem Items}, it's currently unused
    • + *
    • For entities, it represents the averaged lateral velocity of the object.
    • + *
    • For {@link GeoBlockEntity Tile Entities} and {@link GeoItem Items}, it's currently unused
    • *
    * The lower the value, the more sensitive the {@link AzAnimationState#isMoving()} check will be.
    * Particularly low values may have adverse effects however diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java index 05e67979d..7e8c9d7f7 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java @@ -4,6 +4,14 @@ import com.mojang.datafixers.util.Pair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import org.apache.commons.lang3.math.NumberUtils; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.util.JsonUtil; import mod.azure.azurelib.core.animation.EasingType; @@ -19,13 +27,6 @@ import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; import mod.azure.azurelib.core2.animation.primitive.AzKeyframes; import mod.azure.azurelib.core2.animation.primitive.AzLoopType; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.GsonHelper; -import org.apache.commons.lang3.math.NumberUtils; - -import java.lang.reflect.Type; -import java.util.List; -import java.util.Map; /** * {@link com.google.gson.Gson} {@link JsonDeserializer} for {@link AzBakedAnimations}.
    @@ -74,11 +75,14 @@ private static Pair getTripletObjBedrock(String timestamp, if (keyframe.has("pre")) { JsonElement pre = keyframe.get("pre"); - keyframeValues = pre.isJsonArray() ? pre.getAsJsonArray() : GsonHelper.getAsJsonArray(pre.getAsJsonObject(), "vector"); - } - else if (keyframe.has("post")) { + keyframeValues = pre.isJsonArray() + ? pre.getAsJsonArray() + : GsonHelper.getAsJsonArray(pre.getAsJsonObject(), "vector"); + } else if (keyframe.has("post")) { JsonElement post = keyframe.get("post"); - keyframeValues = post.isJsonArray() ? post.getAsJsonArray() : GsonHelper.getAsJsonArray(post.getAsJsonObject(), "vector"); + keyframeValues = post.isJsonArray() + ? post.getAsJsonArray() + : GsonHelper.getAsJsonArray(post.getAsJsonObject(), "vector"); } if (keyframeValues != null) @@ -101,9 +105,9 @@ private static double calculateAnimationLength(BoneAnimation[] boneAnimations) { @Override public AzBakedAnimations deserialize( - JsonElement json, - Type type, - JsonDeserializationContext context + JsonElement json, + Type type, + JsonDeserializationContext context ) throws JsonParseException { JsonObject jsonObj = json.getAsJsonObject(); @@ -119,10 +123,10 @@ public AzBakedAnimations deserialize( String ani = animName.getAsString(); if (includes.containsKey(ani)) { AzureLib.LOGGER.warn( - "Animation {} is already included! File already including: {} File trying to include from again: {}", - ani, - includes.get(ani), - fileId + "Animation {} is already included! File already including: {} File trying to include from again: {}", + ani, + includes.get(ani), + fileId ); } else { includes.put(ani, fileId); @@ -136,8 +140,8 @@ public AzBakedAnimations deserialize( for (Map.Entry entry : animationJsonList.entrySet()) { try { animations.put( - entry.getKey(), - bakeAnimation(entry.getKey(), entry.getValue().getAsJsonObject(), context) + entry.getKey(), + bakeAnimation(entry.getKey(), entry.getValue().getAsJsonObject(), context) ); } catch (MolangException ex) { AzureLib.LOGGER.error("Unable to parse animation: {}", entry.getKey()); @@ -154,11 +158,11 @@ private AzAnimation bakeAnimation( JsonDeserializationContext context ) throws MolangException { double length = animationObj.has("animation_length") - ? GsonHelper.getAsDouble(animationObj, "animation_length") * 20d - : -1; + ? GsonHelper.getAsDouble(animationObj, "animation_length") * 20d + : -1; AzLoopType loopType = AzLoopType.fromJson(animationObj.get("loop")); BoneAnimation[] boneAnimations = bakeBoneAnimations( - GsonHelper.getAsJsonObject(animationObj, "bones", new JsonObject()) + GsonHelper.getAsJsonObject(animationObj, "bones", new JsonObject()) ); AzKeyframes keyframes = context.deserialize(animationObj, AzKeyframes.class); @@ -175,16 +179,16 @@ private BoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangExc for (Map.Entry entry : bonesObj.entrySet()) { JsonObject entryObj = entry.getValue().getAsJsonObject(); KeyframeStack> scaleFrames = buildKeyframeStack( - getTripletObj(entryObj.get("scale")), - false + getTripletObj(entryObj.get("scale")), + false ); KeyframeStack> positionFrames = buildKeyframeStack( - getTripletObj(entryObj.get("position")), - false + getTripletObj(entryObj.get("position")), + false ); KeyframeStack> rotationFrames = buildKeyframeStack( - getTripletObj(entryObj.get("rotation")), - true + getTripletObj(entryObj.get("rotation")), + true ); animations[index] = new BoneAnimation(entry.getKey(), rotationFrames, positionFrames, scaleFrames); @@ -195,8 +199,8 @@ private BoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangExc } private KeyframeStack> buildKeyframeStack( - List> entries, - boolean isForRotation + List> entries, + boolean isForRotation ) throws MolangException { if (entries.isEmpty()) return new KeyframeStack<>(); @@ -222,40 +226,40 @@ private KeyframeStack> buildKeyframeStack( double timeDelta = curTime - prevTime; JsonArray keyFrameVector = element instanceof JsonArray array - ? array - : GsonHelper.getAsJsonArray(element.getAsJsonObject(), "vector"); + ? array + : GsonHelper.getAsJsonArray(element.getAsJsonObject(), "vector"); MolangValue rawXValue = MolangParser.parseJson(keyFrameVector.get(0)); MolangValue rawYValue = MolangParser.parseJson(keyFrameVector.get(1)); MolangValue rawZValue = MolangParser.parseJson(keyFrameVector.get(2)); IValue xValue = isForRotation && rawXValue.isConstant() - ? new Constant(Math.toRadians(-rawXValue.get())) - : rawXValue; + ? new Constant(Math.toRadians(-rawXValue.get())) + : rawXValue; IValue yValue = isForRotation && rawYValue.isConstant() - ? new Constant(Math.toRadians(-rawYValue.get())) - : rawYValue; + ? new Constant(Math.toRadians(-rawYValue.get())) + : rawYValue; IValue zValue = isForRotation && rawZValue.isConstant() - ? new Constant(Math.toRadians(rawZValue.get())) - : rawZValue; + ? new Constant(Math.toRadians(rawZValue.get())) + : rawZValue; JsonObject entryObj = element instanceof JsonObject obj ? obj : null; EasingType easingType = entryObj != null && entryObj.has("easing") - ? EasingType.fromJson(entryObj.get("easing")) - : EasingType.LINEAR; + ? EasingType.fromJson(entryObj.get("easing")) + : EasingType.LINEAR; List easingArgs = entryObj != null && entryObj.has("easingArgs") - ? JsonUtil.jsonArrayToList( + ? JsonUtil.jsonArrayToList( GsonHelper.getAsJsonArray(entryObj, "easingArgs"), ele -> new Constant(ele.getAsDouble()) - ) - : new ObjectArrayList<>(); + ) + : new ObjectArrayList<>(); xFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) ); yFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) ); zFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) ); xPrev = xValue; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzKeyFramesAdapter.java b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzKeyFramesAdapter.java index ddecd93d2..53c0dc9c6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzKeyFramesAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzKeyFramesAdapter.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core2.animation.parse; @@ -16,15 +14,16 @@ import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.util.GsonHelper; + +import java.lang.reflect.Type; +import java.util.Map; + import mod.azure.azurelib.common.internal.common.util.JsonUtil; import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; import mod.azure.azurelib.core2.animation.primitive.AzKeyframes; -import net.minecraft.util.GsonHelper; - -import java.lang.reflect.Type; -import java.util.Map; /** * {@link Gson} {@link JsonDeserializer} for {@link AzKeyframes}.
    @@ -39,8 +38,8 @@ private static SoundKeyframeData[] buildSoundFrameData(JsonObject rootObj) { for (Map.Entry entry : soundsObj.entrySet()) { sounds[index] = new SoundKeyframeData( - Double.parseDouble(entry.getKey()) * 20d, - GsonHelper.getAsString(entry.getValue().getAsJsonObject(), "effect") + Double.parseDouble(entry.getKey()) * 20d, + GsonHelper.getAsString(entry.getValue().getAsJsonObject(), "effect") ); index++; } @@ -60,10 +59,10 @@ private static ParticleKeyframeData[] buildParticleFrameData(JsonObject rootObj) String script = GsonHelper.getAsString(obj, "pre_effect_script", ""); particles[index] = new ParticleKeyframeData( - Double.parseDouble(entry.getKey()) * 20d, - effect, - locator, - script + Double.parseDouble(entry.getKey()) * 20d, + effect, + locator, + script ); index++; } @@ -74,7 +73,7 @@ private static ParticleKeyframeData[] buildParticleFrameData(JsonObject rootObj) private static CustomInstructionKeyframeData[] buildCustomFrameData(JsonObject rootObj) { JsonObject customInstructionsObj = GsonHelper.getAsJsonObject(rootObj, "timeline", new JsonObject()); CustomInstructionKeyframeData[] customInstructions = new CustomInstructionKeyframeData[customInstructionsObj - .size()]; + .size()]; int index = 0; for (Map.Entry entry : customInstructionsObj.entrySet()) { @@ -87,8 +86,8 @@ private static CustomInstructionKeyframeData[] buildCustomFrameData(JsonObject r } customInstructions[index] = new CustomInstructionKeyframeData( - Double.parseDouble(entry.getKey()) * 20d, - instructions + Double.parseDouble(entry.getKey()) * 20d, + instructions ); index++; } @@ -98,9 +97,9 @@ private static CustomInstructionKeyframeData[] buildCustomFrameData(JsonObject r @Override public AzKeyframes deserialize( - JsonElement json, - Type type, - JsonDeserializationContext context + JsonElement json, + Type type, + JsonDeserializationContext context ) throws JsonParseException { JsonObject obj = json.getAsJsonObject(); SoundKeyframeData[] sounds = buildSoundFrameData(obj); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java index 6e0130af5..0124c9972 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java @@ -25,8 +25,11 @@ public static AzAnimation generateWaitAnimation(double length) { length, AzLoopType.PLAY_ONCE, new BoneAnimation[0], - new AzKeyframes(new SoundKeyframeData[0], new ParticleKeyframeData[0], - new CustomInstructionKeyframeData[0]) + new AzKeyframes( + new SoundKeyframeData[0], + new ParticleKeyframeData[0], + new CustomInstructionKeyframeData[0] + ) ); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimations.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimations.java index ea490c4df..36d2784dd 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimations.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimations.java @@ -14,6 +14,7 @@ public record AzBakedAnimations( Map animations, Map includes ) { + /** * Gets an {@link AzAnimation} by its name, if present */ diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzKeyframes.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzKeyframes.java index da7883b56..0e80f9387 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzKeyframes.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzKeyframes.java @@ -8,4 +8,4 @@ public record AzKeyframes( SoundKeyframeData[] sounds, ParticleKeyframeData[] particles, CustomInstructionKeyframeData[] customInstructions -) {} \ No newline at end of file +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java index b578db81e..818b6fa67 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java @@ -1,16 +1,17 @@ package mod.azure.azurelib.core2.animation.primitive; import com.google.gson.JsonElement; -import mod.azure.azurelib.core2.animation.controller.AzAnimationController; -import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerState; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerState; + /** * Loop type functional interface to define post-play handling for a given animation.
    - * Custom loop types are supported by extending this class and providing the extended class instance as the loop - * type for the animation + * Custom loop types are supported by extending this class and providing the extended class instance as the loop type + * for the animation */ @FunctionalInterface public interface AzLoopType { @@ -18,11 +19,11 @@ public interface AzLoopType { Map LOOP_TYPES = new ConcurrentHashMap<>(4); AzLoopType DEFAULT = (animatable, controller, currentAnimation) -> currentAnimation.loopType() - .shouldPlayAgain(animatable, controller, currentAnimation); + .shouldPlayAgain(animatable, controller, currentAnimation); AzLoopType PLAY_ONCE = register( - "play_once", - register("false", (animatable, controller, currentAnimation) -> false) + "play_once", + register("false", (animatable, controller, currentAnimation) -> false) ); AzLoopType HOLD_ON_LAST_FRAME = register("hold_on_last_frame", (animatable, controller, currentAnimation) -> { @@ -66,8 +67,7 @@ static AzLoopType fromString(String name) { /** * Register a AzLoopType with AzureLib for handling loop functionality of animations..
    * MUST be called during mod construct
    - * It is recommended you don't call this directly, and instead call it via - * {@code AzureLibUtil#addCustomLoopType} + * It is recommended you don't call this directly, and instead call it via {@code AzureLibUtil#addCustomLoopType} * * @param name The name of the loop type * @param loopType The loop type to register @@ -92,4 +92,4 @@ boolean shouldPlayAgain( AzAnimationController controller, AzAnimation currentAnimation ); -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzQueuedAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzQueuedAnimation.java index 4dba6736e..a05124a3c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzQueuedAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzQueuedAnimation.java @@ -6,4 +6,4 @@ public record AzQueuedAnimation( AzAnimation animation, AzLoopType loopType -) {} \ No newline at end of file +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzRawAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzRawAnimation.java index d50504a5b..8f6bf7f0b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzRawAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzRawAnimation.java @@ -1,11 +1,12 @@ package mod.azure.azurelib.core2.animation.primitive; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import java.util.List; import java.util.Objects; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; + /** * A builder class for a raw/unbaked animation. These are constructed to pass to the {@link AzAnimationController} to * build into full-fledged animations for usage.
    @@ -145,5 +146,4 @@ public int hashCode() { return Objects.hash(this.animationList); } - } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzStage.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzStage.java index a36747fab..c3e47820a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzStage.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzStage.java @@ -35,4 +35,4 @@ public boolean equals(Object obj) { public int hashCode() { return Objects.hash(this.animationName, this.loopType); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java index 2c5b1676c..b9f8d9d03 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java @@ -1,16 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core2.model; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; -import mod.azure.azurelib.core.state.BoneSnapshot; import org.jetbrains.annotations.Nullable; import org.joml.Matrix3f; import org.joml.Matrix4f; @@ -20,6 +15,10 @@ import java.util.List; import java.util.Objects; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.state.BoneSnapshot; + /** * Mutable bone object representing a set of cubes, as well as child bones.
    * This is the object that is directly modified by animations to handle movement @@ -41,27 +40,49 @@ public class AzBone implements CoreGeoBone { private final Boolean dontRender; private final Boolean reset; + private final Matrix4f modelSpaceMatrix = new Matrix4f(); + private final Matrix4f localSpaceMatrix = new Matrix4f(); + private final Matrix4f worldSpaceMatrix = new Matrix4f(); + private BoneSnapshot initialSnapshot; + private boolean hidden; + private boolean childrenHidden = false; + private float scaleX = 1; + private float scaleY = 1; + private float scaleZ = 1; + private float positionX; + private float positionY; + private float positionZ; + private float pivotX; + private float pivotY; + private float pivotZ; + private float rotX; + private float rotY; + private float rotZ; + private boolean positionChanged = false; + private boolean rotationChanged = false; + private boolean scaleChanged = false; + private Matrix3f worldSpaceNormal = new Matrix3f(); private boolean trackingMatrices; diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java b/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java index 884f17e9f..62718eaa7 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java @@ -1,12 +1,6 @@ package mod.azure.azurelib.core2.model.cache; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.internal.common.loading.FileLoader; -import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; -import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; -import mod.azure.azurelib.core2.AzResourceCache; -import mod.azure.azurelib.core2.model.AzBakedModel; -import mod.azure.azurelib.core2.model.factory.registry.AzBakedModelFactoryRegistry; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; import org.jetbrains.annotations.Nullable; @@ -15,6 +9,13 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import mod.azure.azurelib.common.internal.common.loading.FileLoader; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; +import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; +import mod.azure.azurelib.core2.AzResourceCache; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.factory.registry.AzBakedModelFactoryRegistry; + public class AzBakedModelCache extends AzResourceCache { private static final AzBakedModelCache INSTANCE = new AzBakedModelCache(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java index a360ca108..5573ff13f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java @@ -1,5 +1,9 @@ package mod.azure.azurelib.core2.model.factory; +import net.minecraft.core.Direction; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; + import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; import mod.azure.azurelib.common.internal.common.loading.json.raw.Cube; @@ -11,13 +15,9 @@ import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.model.factory.primitive.VertexSet; -import net.minecraft.core.Direction; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; public abstract class AzBakedModelFactory { - /** * Construct the output model from the given {@link GeometryTree}.
    */ @@ -30,7 +30,11 @@ public abstract class AzBakedModelFactory { * @param properties The loaded properties for the model * @param parent The parent bone for this bone, or null if a top-level bone */ - public abstract AzBone constructBone(BoneStructure boneStructure, ModelProperties properties, @Nullable AzBone parent); + public abstract AzBone constructBone( + BoneStructure boneStructure, + ModelProperties properties, + @Nullable AzBone parent + ); /** * Construct a {@link GeoCube} from the relevant raw input data @@ -98,29 +102,29 @@ public GeoQuad buildQuad( double[] uvSize = cube.size(); Vec3 uvSizeVec = new Vec3(Math.floor(uvSize[0]), Math.floor(uvSize[1]), Math.floor(uvSize[2])); double[][] uvData = switch (direction) { - case WEST -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.z, uvSizeVec.y} + case WEST -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.z, uvSizeVec.y } }; - case EAST -> new double[][]{ - new double[]{uv[0], uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.z, uvSizeVec.y} + case EAST -> new double[][] { + new double[] { uv[0], uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.z, uvSizeVec.y } }; - case NORTH -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.x, uvSizeVec.y} + case NORTH -> new double[][] { + new double[] { uv[0] + uvSizeVec.z, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, uvSizeVec.y } }; - case SOUTH -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x + uvSizeVec.z, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.x, uvSizeVec.y} + case SOUTH -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x + uvSizeVec.z, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, uvSizeVec.y } }; - case UP -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z, uv[1]}, - new double[]{uvSizeVec.x, uvSizeVec.z} + case UP -> new double[][] { + new double[] { uv[0] + uvSizeVec.z, uv[1] }, + new double[] { uvSizeVec.x, uvSizeVec.z } }; - case DOWN -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.x, -uvSizeVec.z} + case DOWN -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, -uvSizeVec.z } }; }; diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java index 32567b9b4..2626f56f6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java @@ -1,6 +1,8 @@ package mod.azure.azurelib.core2.model.factory.impl; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.world.phys.Vec3; + import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; import mod.azure.azurelib.common.internal.common.loading.json.raw.Cube; @@ -11,7 +13,6 @@ import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.model.factory.AzBakedModelFactory; import mod.azure.azurelib.core2.model.factory.primitive.VertexSet; -import net.minecraft.world.phys.Vec3; public final class AzBuiltinBakedModelFactory extends AzBakedModelFactory { @@ -85,4 +86,4 @@ public GeoCube constructCube(Cube cube, ModelProperties properties, AzBone bone) return new GeoCube(quads, pivot, rotation, size, inflate, mirror); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/primitive/VertexSet.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/primitive/VertexSet.java index ed18f4e4c..20c86e27f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/factory/primitive/VertexSet.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/primitive/VertexSet.java @@ -1,9 +1,10 @@ package mod.azure.azurelib.core2.model.factory.primitive; -import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; import net.minecraft.core.Direction; import net.minecraft.world.phys.Vec3; +import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; + /** * Holder class to make it easier to store and refer to vertices for a given cube */ @@ -51,7 +52,7 @@ public VertexSet(Vec3 origin, Vec3 vertexSize, double inflation) { * Returns the normal vertex array for a west-facing quad */ public GeoVertex[] quadWest() { - return new GeoVertex[]{ this.topRightBack, this.topLeftBack, this.bottomLeftBack, this.bottomRightBack }; + return new GeoVertex[] { this.topRightBack, this.topLeftBack, this.bottomLeftBack, this.bottomRightBack }; } /** @@ -70,7 +71,7 @@ public GeoVertex[] quadEast() { * Returns the normal vertex array for a north-facing quad */ public GeoVertex[] quadNorth() { - return new GeoVertex[]{ this.topLeftBack, this.topLeftFront, this.bottomLeftFront, this.bottomLeftBack }; + return new GeoVertex[] { this.topLeftBack, this.topLeftFront, this.bottomLeftFront, this.bottomLeftBack }; } /** @@ -89,7 +90,7 @@ public GeoVertex[] quadSouth() { * Returns the normal vertex array for a top-facing quad */ public GeoVertex[] quadUp() { - return new GeoVertex[]{ this.topRightBack, this.topRightFront, this.topLeftFront, this.topLeftBack }; + return new GeoVertex[] { this.topRightBack, this.topRightFront, this.topLeftFront, this.topLeftBack }; } /** @@ -117,4 +118,4 @@ public GeoVertex[] verticesForQuad(Direction direction, boolean boxUv, boolean m case DOWN -> mirror && !boxUv ? quadUp() : quadDown(); }; } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/registry/AzBakedModelFactoryRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/registry/AzBakedModelFactoryRegistry.java index 2d948954e..8b045376e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/factory/registry/AzBakedModelFactoryRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/registry/AzBakedModelFactoryRegistry.java @@ -1,15 +1,17 @@ package mod.azure.azurelib.core2.model.factory.registry; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +import java.util.Map; + import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; import mod.azure.azurelib.core2.model.factory.AzBakedModelFactory; import mod.azure.azurelib.core2.model.factory.impl.AzBuiltinBakedModelFactory; -import java.util.Map; - public class AzBakedModelFactoryRegistry { private static final Map FACTORIES = new Object2ObjectOpenHashMap<>(1); + private static final AzBakedModelFactory DEFAULT_FACTORY = new AzBuiltinBakedModelFactory(); public static AzBakedModelFactory getForNamespace(String namespace) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 06f725b3d..f4d52b26b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -2,12 +2,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; -import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; -import mod.azure.azurelib.core2.model.AzBakedModel; -import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; -import mod.azure.azurelib.core2.render.pipeline.impl.AzEntityRendererPipeline; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderer; @@ -23,11 +17,21 @@ import java.util.List; import java.util.Objects; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import mod.azure.azurelib.core2.render.pipeline.impl.AzEntityRendererPipeline; + public abstract class AzEntityRenderer extends EntityRenderer { private float scaleWidth = 1; + private float scaleHeight = 1; + private final AzEntityRendererPipeline azEntityRendererPipeline; + private final List> renderLayers; @Nullable @@ -41,18 +45,42 @@ protected AzEntityRenderer(EntityRendererProvider.Context context) { protected abstract @NotNull ResourceLocation getModelLocation(T entity); - public void superRender(@NotNull T entity, float entityYaw, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource bufferSource, int packedLight) { + public void superRender( + @NotNull T entity, + float entityYaw, + float partialTick, + @NotNull PoseStack poseStack, + @NotNull MultiBufferSource bufferSource, + int packedLight + ) { super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight); } @Override - public void render(@NotNull T entity, float entityYaw, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource bufferSource, int packedLight) { + public void render( + @NotNull T entity, + float entityYaw, + float partialTick, + @NotNull PoseStack poseStack, + @NotNull MultiBufferSource bufferSource, + int packedLight + ) { var cachedEntityAnimator = provideAnimator(entity); var azBakedModel = provideBakedModel(entity, cachedEntityAnimator); - // Point the renderer's current animator reference to the cached entity animator before rendering. + // Point the renderer's current animator reference to the cached entity animator before rendering. reusedAzEntityAnimator = cachedEntityAnimator; // Execute the render pipeline. - azEntityRendererPipeline.render(poseStack, azBakedModel, entity, bufferSource, null, null, entityYaw, partialTick, packedLight); + azEntityRendererPipeline.render( + poseStack, + azBakedModel, + entity, + bufferSource, + null, + null, + entityYaw, + partialTick, + packedLight + ); } protected @Nullable AzEntityAnimator createAnimator() { @@ -71,7 +99,8 @@ public void render(@NotNull T entity, float entityYaw, float partialTick, @NotNu } protected @Nullable AzEntityAnimator provideAnimator(T entity) { - // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for the entity. + // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for the + // entity. @SuppressWarnings("unchecked") var entityAnimatorCache = (AzAnimatorAccessor) entity; var cachedEntityAnimator = (AzEntityAnimator) entityAnimatorCache.getAnimator(); @@ -165,8 +194,8 @@ public boolean shouldShowName(T entity) { case HIDE_FOR_OTHER_TEAMS -> playerTeam == null ? visibleToClient : entityTeam.isAlliedTo( - playerTeam - ) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); + playerTeam + ) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); case HIDE_FOR_OWN_TEAM -> playerTeam == null ? visibleToClient : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; }; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/RenderLeashUtil.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/RenderLeashUtil.java index 5d67368c7..a613dd603 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/RenderLeashUtil.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/RenderLeashUtil.java @@ -49,10 +49,10 @@ public static void renderLea int holderBlockLight = leashHolder.isOnFire() ? 15 : leashHolder.level() - .getBrightness( - LightLayer.BLOCK, - holderEyePos - ); + .getBrightness( + LightLayer.BLOCK, + holderEyePos + ); int entitySkyLight = mob.level().getBrightness(LightLayer.SKY, entityEyePos); int holderSkyLight = mob.level().getBrightness(LightLayer.SKY, holderEyePos); diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java index 5ee99bc8a..aebfa564f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java @@ -2,11 +2,12 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; + import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; /** * Render layer base class for rendering additional layers of effects or textures over an existing model at runtime.
    @@ -17,32 +18,59 @@ public abstract class AzRenderLayer { public AzRenderLayer() {} /** - * This method is called by the {@link AzRendererPipeline} before rendering, immediately after {@link AzRendererPipeline#preRender} has been called.
    + * This method is called by the {@link AzRendererPipeline} before rendering, immediately after + * {@link AzRendererPipeline#preRender} has been called.
    * This allows for RenderLayers to perform pre-render manipulations such as hiding or showing bones */ - public abstract void preRender(PoseStack poseStack, T animatable, AzBakedModel bakedModel, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, - int packedLight, int packedOverlay); + public abstract void preRender( + PoseStack poseStack, + T animatable, + AzBakedModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ); /** * This is the method that is actually called by the render for your render layer to function.
    * This is called after the animatable has been rendered, but before supplementary rendering like nametags. */ - public abstract void render(PoseStack poseStack, T animatable, AzBakedModel bakedModel, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, - int packedLight, int packedOverlay); + public abstract void render( + PoseStack poseStack, + T animatable, + AzBakedModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ); /** * This method is called by the {@link AzRendererPipeline} for each bone being rendered.
    * This is a more expensive call, particularly if being used to render something on a different buffer.
    - * It does however have the benefit of having the matrix translations and other transformations already applied from render-time.
    + * It does however have the benefit of having the matrix translations and other transformations already applied from + * render-time.
    * It's recommended to avoid using this unless necessary.
    *
    * The {@link AzBone} in question has already been rendered by this stage.
    *
    - * If you do use it, and you render something that changes the {@link VertexConsumer buffer}, you need to reset it back to the previous buffer - * using {@link MultiBufferSource#getBuffer} before ending the method + * If you do use it, and you render something that changes the {@link VertexConsumer buffer}, you need to + * reset it back to the previous buffer using {@link MultiBufferSource#getBuffer} before ending the method */ - public abstract void renderForBone(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay); -} \ No newline at end of file + public abstract void renderForBone( + PoseStack poseStack, + T animatable, + AzBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index c214f7d6c..a43730d33 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -2,15 +2,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; -import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; -import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core.object.Color; -import mod.azure.azurelib.core2.model.AzBakedModel; -import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.OverlayTexture; @@ -24,21 +15,37 @@ import java.util.List; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; +import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core.object.Color; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + public abstract class AzRendererPipeline { protected abstract @NotNull ResourceLocation getTextureLocation(@NotNull T animatable); /** * Gets the {@link RenderType} to render the given animatable with.
    - * Uses the {@link RenderType#entityCutoutNoCull} {@code RenderType} by default.
    + * Uses the {@link RenderType#entityCutoutNoCull} {@code RenderType} by default.
    * Override this to change the way a model will render (such as translucent models, etc) */ - public abstract RenderType getDefaultRenderType(T animatable, ResourceLocation texture, - @Nullable MultiBufferSource bufferSource, float partialTick); + public abstract RenderType getDefaultRenderType( + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ); /** - * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this GeoRenderer.
    + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
    * This should only be called immediately prior to rendering, and only + * * @see AnimatableTexture#setAndUpdate */ protected abstract void updateAnimatedTextureFrame(T animatable); @@ -50,21 +57,44 @@ public abstract RenderType getDefaultRenderType(T animatable, ResourceLocation t /** * Create and fire the relevant {@code Pre-Render} event hook for this renderer.
    + * * @return Whether the renderer should proceed based on the cancellation state of the event */ - protected abstract boolean firePreRenderEvent(PoseStack poseStack, AzBakedModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + protected abstract boolean firePreRenderEvent( + PoseStack poseStack, + AzBakedModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Create and fire the relevant {@code Post-Render} event hook for this renderer */ - protected abstract void firePostRenderEvent(PoseStack poseStack, AzBakedModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + protected abstract void firePostRenderEvent( + PoseStack poseStack, + AzBakedModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Initial access point for rendering. It all begins here.
    - * All AzureLib renderers should immediately defer their respective default {@code render} calls to this, for consistent handling + * All AzureLib renderers should immediately defer their respective default {@code render} calls to this, for + * consistent handling */ - public void render(PoseStack poseStack, AzBakedModel model, T animatable, MultiBufferSource bufferSource, @Nullable RenderType renderType, @Nullable VertexConsumer buffer, - float yaw, float partialTick, int packedLight) { + public void render( + PoseStack poseStack, + AzBakedModel model, + T animatable, + MultiBufferSource bufferSource, + @Nullable RenderType renderType, + @Nullable VertexConsumer buffer, + float yaw, + float partialTick, + int packedLight + ) { poseStack.pushPose(); var renderColor = getRenderColor(animatable, partialTick, packedLight).argbInt(); @@ -78,74 +108,240 @@ public void render(PoseStack poseStack, AzBakedModel model, T animatable, MultiB buffer = bufferSource.getBuffer(renderType); } - preRender(poseStack, animatable, model, bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); + preRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + false, + partialTick, + packedLight, + packedOverlay, + renderColor + ); if (firePreRenderEvent(poseStack, model, bufferSource, partialTick, packedLight)) { - preApplyRenderLayers(poseStack, animatable, model, renderType, bufferSource, buffer, packedLight, packedLight, packedOverlay); - actuallyRender(poseStack, animatable, model, renderType, - bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); - applyRenderLayers(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); - postRender(poseStack, animatable, model, bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); + preApplyRenderLayers( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + packedLight, + packedLight, + packedOverlay + ); + actuallyRender( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + false, + partialTick, + packedLight, + packedOverlay, + renderColor + ); + applyRenderLayers( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); + postRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + false, + partialTick, + packedLight, + packedOverlay, + renderColor + ); firePostRenderEvent(poseStack, model, bufferSource, partialTick, packedLight); } poseStack.popPose(); - renderFinal(poseStack, animatable, model, bufferSource, buffer, partialTick, packedLight, packedOverlay, renderColor); + renderFinal( + poseStack, + animatable, + model, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + renderColor + ); doPostRenderCleanup(); } /** * Re-renders the provided {@link AzBakedModel}.
    - * Usually you'd use this for rendering alternate {@link RenderType} layers or for sub-model rendering whilst inside a {@link AzRenderLayer} or similar + * Usually you'd use this for rendering alternate {@link RenderType} layers or for sub-model rendering whilst inside + * a {@link AzRenderLayer} or similar */ - protected void reRender(AzBakedModel model, PoseStack poseStack, MultiBufferSource bufferSource, T animatable, - RenderType renderType, VertexConsumer buffer, float partialTick, - int packedLight, int packedOverlay, int colour) { + protected void reRender( + AzBakedModel model, + PoseStack poseStack, + MultiBufferSource bufferSource, + T animatable, + RenderType renderType, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { poseStack.pushPose(); - preRender(poseStack, animatable, model, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); - actuallyRender(poseStack, animatable, model, renderType, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); - postRender(poseStack, animatable, model, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); + preRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + true, + partialTick, + packedLight, + packedOverlay, + colour + ); + actuallyRender( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + true, + partialTick, + packedLight, + packedOverlay, + colour + ); + postRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + true, + partialTick, + packedLight, + packedOverlay, + colour + ); poseStack.popPose(); } /** * The actual render method that sub-type renderers should override to handle their specific rendering tasks.
    */ - protected void actuallyRender(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, - int packedLight, int packedOverlay, int colour) { + protected void actuallyRender( + PoseStack poseStack, + T animatable, + AzBakedModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { updateAnimatedTextureFrame(animatable); for (var bone : model.getTopLevelBones()) { - renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, - packedOverlay, colour); + renderRecursively( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour + ); } } /** * Renders the provided {@link AzBone} and its associated child bones */ - protected void renderRecursively(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, - int packedOverlay, int colour) { + protected void renderRecursively( + PoseStack poseStack, + T animatable, + AzBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { poseStack.pushPose(); RenderUtils.prepMatrixForBone(poseStack, bone); renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (!isReRender) { - applyRenderLayersForBone(poseStack, animatable, bone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + applyRenderLayersForBone( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); } - renderChildBones(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour); + renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour + ); poseStack.popPose(); } /** * Renders the {@link GeoCube GeoCubes} associated with a given {@link AzBone} */ - protected void renderCubesOfBone(PoseStack poseStack, AzBone bone, VertexConsumer buffer, int packedLight, - int packedOverlay, int colour) { + protected void renderCubesOfBone( + PoseStack poseStack, + AzBone bone, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour + ) { if (bone.isHidden()) return; @@ -158,15 +354,39 @@ protected void renderCubesOfBone(PoseStack poseStack, AzBone bone, VertexConsume /** * Render the child bones of a given {@link AzBone}.
    - * Note that this does not render the bone itself. That should be done through {@link AzRendererPipeline#renderCubesOfBone} separately + * Note that this does not render the bone itself. That should be done through + * {@link AzRendererPipeline#renderCubesOfBone} separately */ - protected void renderChildBones(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, - boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) { + protected void renderChildBones( + PoseStack poseStack, + T animatable, + AzBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { if (bone.isHidingChildren()) return; for (var childBone : bone.getChildBones()) { - renderRecursively(poseStack, animatable, childBone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour); + renderRecursively( + poseStack, + animatable, + childBone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour + ); } } @@ -174,8 +394,14 @@ protected void renderChildBones(PoseStack poseStack, T animatable, AzBone bone, * Renders an individual {@link GeoCube}.
    * This tends to be called recursively from something like {@link AzRendererPipeline#renderCubesOfBone} */ - protected void renderCube(PoseStack poseStack, GeoCube cube, VertexConsumer buffer, int packedLight, - int packedOverlay, int colour) { + protected void renderCube( + PoseStack poseStack, + GeoCube cube, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour + ) { RenderUtils.translateToPivotPoint(poseStack, cube); RenderUtils.rotateMatrixAroundCube(poseStack, cube); RenderUtils.translateAwayFromPivotPoint(poseStack, cube); @@ -195,81 +421,203 @@ protected void renderCube(PoseStack poseStack, GeoCube cube, VertexConsumer buff } /** - * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for rendering + * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for + * rendering */ - protected void createVerticesOfQuad(GeoQuad quad, Matrix4f poseState, Vector3f normal, VertexConsumer buffer, - int packedLight, int packedOverlay, int colour) { + protected void createVerticesOfQuad( + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour + ) { for (var vertex : quad.vertices()) { var position = vertex.position(); var vector4f = poseState.transform(new Vector4f(position.x(), position.y(), position.z(), 1.0f)); - buffer.addVertex(vector4f.x(), vector4f.y(), vector4f.z(), colour, vertex.texU(), - vertex.texV(), packedOverlay, packedLight, normal.x(), normal.y(), normal.z()); + buffer.addVertex( + vector4f.x(), + vector4f.y(), + vector4f.z(), + colour, + vertex.texU(), + vertex.texV(), + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() + ); } } /** - * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#preRender pre-render} actions. + * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their + * {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#preRender pre-render} actions. */ - protected void preApplyRenderLayers(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + protected void preApplyRenderLayers( + PoseStack poseStack, + T animatable, + AzBakedModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) { for (var renderLayer : getRenderLayers()) { - renderLayer.preRender(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + renderLayer.preRender( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); } } /** - * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#renderForBone per-bone} render actions. + * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their + * {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#renderForBone per-bone} render actions. */ - protected void applyRenderLayersForBone(PoseStack poseStack, T animatable, AzBone bone, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + protected void applyRenderLayersForBone( + PoseStack poseStack, + T animatable, + AzBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) { for (var renderLayer : getRenderLayers()) { - renderLayer.renderForBone(poseStack, animatable, bone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + renderLayer.renderForBone( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); } } /** * Render the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer */ - protected void applyRenderLayers(PoseStack poseStack, T animatable, AzBakedModel model, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + protected void applyRenderLayers( + PoseStack poseStack, + T animatable, + AzBakedModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) { for (var renderLayer : getRenderLayers()) { - renderLayer.render(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + renderLayer.render( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); } } /** - * Called before rendering the model to buffer. Allows for render modifications and preparatory - * work such as scaling and translating.
    + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
    * {@link PoseStack} translations made here are kept until the end of the render process */ - protected void preRender(PoseStack poseStack, T animatable, AzBakedModel model, @Nullable MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, - int packedOverlay, int colour) {} + protected void preRender( + PoseStack poseStack, + T animatable, + AzBakedModel model, + @Nullable MultiBufferSource bufferSource, + @Nullable VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) {} /** * Called after rendering the model to buffer. Post-render modifications should be performed here.
    * {@link PoseStack} transformations will be unused and lost once this method ends */ - protected void postRender(PoseStack poseStack, T animatable, AzBakedModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {} + protected void postRender( + PoseStack poseStack, + T animatable, + AzBakedModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) {} /** - * Call after all other rendering work has taken place, including reverting the {@link PoseStack}'s state. This method is not called in {@link AzRendererPipeline#reRender re-render} + * Call after all other rendering work has taken place, including reverting the {@link PoseStack}'s state. This + * method is not called in {@link AzRendererPipeline#reRender re-render} */ - protected void renderFinal(PoseStack poseStack, T animatable, AzBakedModel model, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, - int packedOverlay, int colour) {} + protected void renderFinal( + PoseStack poseStack, + T animatable, + AzBakedModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) {} /** * Called after all render operations are completed and the render pass is considered functionally complete. *

    - * Use this method to clean up any leftover persistent objects stored during rendering or any other post-render maintenance tasks as required + * Use this method to clean up any leftover persistent objects stored during rendering or any other post-render + * maintenance tasks as required */ protected void doPostRenderCleanup() {} /** - * Scales the {@link PoseStack} in preparation for rendering the model, excluding when re-rendering the model as part of a {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer} or external render call.
    - * Override and call super with modified scale values as needed to further modify the scale of the model (E.G. child entities) + * Scales the {@link PoseStack} in preparation for rendering the model, excluding when re-rendering the model as + * part of a {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer} or external render call.
    + * Override and call super with modified scale values as needed to further modify the scale of the model (E.G. child + * entities) */ - protected void scaleModelForRender(float widthScale, float heightScale, PoseStack poseStack, T animatable, AzBakedModel model, boolean isReRender, float partialTick, int packedLight, int packedOverlay) { + protected void scaleModelForRender( + float widthScale, + float heightScale, + PoseStack poseStack, + T animatable, + AzBakedModel model, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay + ) { if (!isReRender && (widthScale != 1 || heightScale != 1)) { poseStack.scale(widthScale, heightScale, widthScale); } @@ -285,9 +633,8 @@ protected Color getRenderColor(T animatable, float partialTick, int packedLight) /** * Gets a packed overlay coordinate pair for rendering.
    - * Mostly just used for the red tint when an entity is hurt, - * but can be used for other things like the {@link net.minecraft.world.entity.monster.Creeper} - * white tint when exploding. + * Mostly just used for the red tint when an entity is hurt, but can be used for other things like the + * {@link net.minecraft.world.entity.monster.Creeper} white tint when exploding. */ protected int getPackedOverlay(T animatable, float u, float partialTick) { return OverlayTexture.NO_OVERLAY; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java index d3cf1b89e..d76314f7c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -4,14 +4,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core2.model.AzBakedModel; -import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; -import mod.azure.azurelib.core2.render.entity.RenderLeashUtil; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; @@ -28,11 +20,21 @@ import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import mod.azure.azurelib.core2.render.entity.RenderLeashUtil; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; + public class AzEntityRendererPipeline extends AzRendererPipeline { private final AzEntityRenderer azEntityRenderer; protected Matrix4f entityRenderTranslations = new Matrix4f(); + protected Matrix4f modelRenderTranslations = new Matrix4f(); public AzEntityRendererPipeline(AzEntityRenderer azEntityRenderer) { @@ -45,7 +47,12 @@ public AzEntityRendererPipeline(AzEntityRenderer azEntityRenderer) { } @Override - public RenderType getDefaultRenderType(T animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) { + public RenderType getDefaultRenderType( + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ) { return RenderType.entityCutoutNoCull(texture); } @@ -99,8 +106,8 @@ public void preRender( /** * The actual render method that subtype renderers should override to handle their specific rendering tasks.
    - * {@link AzEntityRendererPipeline#preRender} has already been called by this stage, and {@link AzEntityRendererPipeline#postRender} will be - * called directly after + * {@link AzEntityRendererPipeline#preRender} has already been called by this stage, and + * {@link AzEntityRendererPipeline#postRender} will be called directly after */ @Override public void actuallyRender( @@ -124,17 +131,17 @@ public void actuallyRender( float lerpBodyRot = livingEntity == null ? 0 : Mth.rotLerp( - partialTick, - livingEntity.yBodyRotO, - livingEntity.yBodyRot - ); + partialTick, + livingEntity.yBodyRotO, + livingEntity.yBodyRot + ); float lerpHeadRot = livingEntity == null ? 0 : Mth.rotLerp( - partialTick, - livingEntity.yHeadRotO, - livingEntity.yHeadRot - ); + partialTick, + livingEntity.yHeadRotO, + livingEntity.yHeadRot + ); float netHeadYaw = lerpHeadRot - lerpBodyRot; if (shouldSit && animatable.getVehicle() instanceof LivingEntity livingentity) { @@ -188,25 +195,25 @@ public void actuallyRender( if (!isReRender) { // FIXME: Figure out what to do with this data stuff. -// float headPitch = Mth.lerp(partialTick, animatable.xRotO, animatable.getXRot()); -// var velocity = animatable.getDeltaMovement(); -// float avgVelocity = (float) (Math.abs(velocity.x) + Math.abs(velocity.z) / 2f); -// -// long instanceId = getInstanceId(animatable); -// -// animationState.setData(DataTickets.TICK, animatable.getTick(animatable)); -// animationState.setData(DataTickets.ENTITY, animatable); -// animationState.setData( -// DataTickets.ENTITY_MODEL_DATA, -// new EntityModelData( -// shouldSit, -// livingEntity != null && livingEntity.isBaby(), -// -netHeadYaw, -// -headPitch -// ) -// ); -// -// this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); + // float headPitch = Mth.lerp(partialTick, animatable.xRotO, animatable.getXRot()); + // var velocity = animatable.getDeltaMovement(); + // float avgVelocity = (float) (Math.abs(velocity.x) + Math.abs(velocity.z) / 2f); + // + // long instanceId = getInstanceId(animatable); + // + // animationState.setData(DataTickets.TICK, animatable.getTick(animatable)); + // animationState.setData(DataTickets.ENTITY, animatable); + // animationState.setData( + // DataTickets.ENTITY_MODEL_DATA, + // new EntityModelData( + // shouldSit, + // livingEntity != null && livingEntity.isBaby(), + // -netHeadYaw, + // -headPitch + // ) + // ); + // + // this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); var animator = azEntityRenderer.getAnimator(); @@ -341,7 +348,17 @@ public void renderRecursively( } @Override - public void renderFinal(PoseStack poseStack, T entity, AzBakedModel model, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay, int colour) { + public void renderFinal( + PoseStack poseStack, + T entity, + AzBakedModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { azEntityRenderer.superRender(entity, 0, partialTick, poseStack, bufferSource, packedLight); if (entity instanceof Mob mob) { @@ -359,7 +376,7 @@ public void renderFinal(PoseStack poseStack, T entity, AzBakedModel model, Multi @Override public void fireCompileRenderLayersEvent() { // FIXME: -// Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireCompileEntityRenderLayers(geoEntityRenderer); + // Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireCompileEntityRenderLayers(geoEntityRenderer); } /** @@ -377,7 +394,8 @@ public boolean firePreRenderEvent( ) { // FIXME: return true; -// return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPreRender(geoEntityRenderer, poseStack, model, bufferSource, partialTick, packedLight); + // return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPreRender(geoEntityRenderer, poseStack, model, + // bufferSource, partialTick, packedLight); } /** @@ -392,11 +410,13 @@ public void firePostRenderEvent( int packedLight ) { // FIXME: -// Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPostRender(geoEntityRenderer, poseStack, model, bufferSource, partialTick, packedLight); + // Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPostRender(geoEntityRenderer, poseStack, model, + // bufferSource, partialTick, packedLight); } /** - * Applies rotation transformations to the renderer prior to render time to account for various entity states, default scale of 1 + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * default scale of 1 */ protected void applyRotations( T animatable, @@ -409,10 +429,17 @@ protected void applyRotations( } /** - * Applies rotation transformations to the renderer prior to render time to account for various entity states, scalable + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * scalable */ - protected void applyRotations(T animatable, PoseStack poseStack, float ageInTicks, float rotationYaw, - float partialTick, float nativeScale) { + protected void applyRotations( + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick, + float nativeScale + ) { if (isShaking(animatable)) { rotationYaw += (float) (Math.cos(animatable.tickCount * 3.25d) * Math.PI * 0.4d); } @@ -425,20 +452,23 @@ protected void applyRotations(T animatable, PoseStack poseStack, float ageInTick if (livingEntity.deathTime > 0) { float deathRotation = (livingEntity.deathTime + partialTick - 1f) / 20f * 1.6f; - poseStack.mulPose(Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable))); - } - else if (livingEntity.isAutoSpinAttack()) { + poseStack.mulPose( + Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable)) + ); + } else if (livingEntity.isAutoSpinAttack()) { poseStack.mulPose(Axis.XP.rotationDegrees(-90f - livingEntity.getXRot())); poseStack.mulPose(Axis.YP.rotationDegrees((livingEntity.tickCount + partialTick) * -75f)); - } - else if (animatable.hasPose(Pose.SLEEPING)) { + } else if (animatable.hasPose(Pose.SLEEPING)) { Direction bedOrientation = livingEntity.getBedOrientation(); - poseStack.mulPose(Axis.YP.rotationDegrees(bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw)); + poseStack.mulPose( + Axis.YP.rotationDegrees( + bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw + ) + ); poseStack.mulPose(Axis.ZP.rotationDegrees(getDeathMaxRotation(animatable))); poseStack.mulPose(Axis.YP.rotationDegrees(270f)); - } - else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { + } else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { poseStack.translate(0, (animatable.getBbHeight() + 0.1f) / nativeScale, 0); poseStack.mulPose(Axis.ZP.rotationDegrees(180f)); } @@ -470,6 +500,9 @@ public int getPackedOverlay(T entity, float u, float partialTick) { return OverlayTexture.NO_OVERLAY; } - return OverlayTexture.pack(OverlayTexture.u(u), OverlayTexture.v(livingEntity.hurtTime > 0 || livingEntity.deathTime > 0)); + return OverlayTexture.pack( + OverlayTexture.u(u), + OverlayTexture.v(livingEntity.hurtTime > 0 || livingEntity.deathTime > 0) + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/APIOnly.java b/common/src/main/java/mod/azure/azurelib/sblforked/APIOnly.java index 15d396a64..6ae164efa 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/APIOnly.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/APIOnly.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked; @@ -12,8 +11,8 @@ import java.lang.annotation.Target; /** - * Methods marked with this annotation should only be used internally, or by abstract-subclasses. - * This is usually done to avoid accidentally overriding methods handled in the super class. + * Methods marked with this annotation should only be used internally, or by abstract-subclasses. This is usually done + * to avoid accidentally overriding methods handled in the super class. */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.METHOD) diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/SBLConstants.java b/common/src/main/java/mod/azure/azurelib/sblforked/SBLConstants.java index 214308383..5feec2788 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/SBLConstants.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/SBLConstants.java @@ -1,13 +1,13 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked; import java.util.ServiceLoader; public class SBLConstants { - public static final SBLLoader SBL_LOADER = ServiceLoader.load(SBLLoader.class).findFirst().get(); -} \ No newline at end of file + + public static final SBLLoader SBL_LOADER = ServiceLoader.load(SBLLoader.class).findFirst().get(); +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/SBLLoader.java b/common/src/main/java/mod/azure/azurelib/sblforked/SBLLoader.java index 3923615a2..ad51a4972 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/SBLLoader.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/SBLLoader.java @@ -1,13 +1,11 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked; import com.mojang.serialization.Codec; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.sensing.SensorType; import org.jetbrains.annotations.ApiStatus; @@ -15,14 +13,20 @@ import java.util.Optional; import java.util.function.Supplier; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; + public interface SBLLoader { - void init(Object eventBus); - boolean isDevEnv(); - - @ApiStatus.Internal - Supplier> registerMemoryType(String id); - @ApiStatus.Internal - Supplier> registerMemoryType(String id, Optional> codec); - @ApiStatus.Internal - > Supplier> registerSensorType(String id, Supplier sensor); + + void init(Object eventBus); + + boolean isDevEnv(); + + @ApiStatus.Internal + Supplier> registerMemoryType(String id); + + @ApiStatus.Internal + Supplier> registerMemoryType(String id, Optional> codec); + + @ApiStatus.Internal + > Supplier> registerSensorType(String id, Supplier sensor); } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/SmartBrainOwner.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/SmartBrainOwner.java index 0baab1b88..1a15e528e 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/SmartBrainOwner.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/SmartBrainOwner.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api; @@ -14,17 +13,18 @@ import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.Brain; import net.minecraft.world.entity.schedule.Activity; -import mod.azure.azurelib.sblforked.APIOnly; -import mod.azure.azurelib.sblforked.api.core.BrainActivityGroup; -import mod.azure.azurelib.sblforked.api.core.SmartBrain; -import mod.azure.azurelib.sblforked.api.core.schedule.SmartBrainSchedule; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; import java.util.Set; +import mod.azure.azurelib.sblforked.APIOnly; +import mod.azure.azurelib.sblforked.api.core.BrainActivityGroup; +import mod.azure.azurelib.sblforked.api.core.SmartBrain; +import mod.azure.azurelib.sblforked.api.core.schedule.SmartBrainSchedule; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; + /** * Implement this class for any entity you want to use the SmartBrain system.
    * This interface contains the helper and constructive methods for initialising your entity's brain. @@ -32,119 +32,131 @@ * @param Your entity */ public interface SmartBrainOwner> { - /** - * The list of {@link ExtendedSensor Sensors} that your entity will be using.
    - * Only supports ExtendedSensors. - * @return A {@link List} of {@link ExtendedSensor Sensors} that the entity will use to fill memories for tasks. - */ - List> getSensors(); - /** - * Override this for tasks that ideally should always be running, regardless of anything else.
    - * Usually you'd use this for things like moving towards the current target, floating on water, looking at a certain target, etc.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category - *

    - * Tasks returned in this category take up the {@link Activity#CORE} activity category - * - * @return a {@link BrainActivityGroup} containing the core tasks your entity should run. - */ - default BrainActivityGroup getCoreTasks() { - return BrainActivityGroup.empty(); - } + /** + * The list of {@link ExtendedSensor Sensors} that your entity will be using.
    + * Only supports ExtendedSensors. + * + * @return A {@link List} of {@link ExtendedSensor Sensors} that the entity will use to fill memories for tasks. + */ + List> getSensors(); + + /** + * Override this for tasks that ideally should always be running, regardless of anything else.
    + * Usually you'd use this for things like moving towards the current target, floating on water, looking at a certain + * target, etc.
    + * Like all task groups, this method is optional, if you have no tasks that apply to this category
    + *
    + * Tasks returned in this category take up the {@link Activity#CORE} activity category + * + * @return a {@link BrainActivityGroup} containing the core tasks your entity should run. + */ + default BrainActivityGroup getCoreTasks() { + return BrainActivityGroup.empty(); + } - /** - * Override this for tasks that would normally run when your entity is doing nothing else.
    - * Usually you'd use this for things like random walking, setting targets, or just standing still and doing nothing at all.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category - *

    - * Tasks returned in this category take up the {@link Activity#IDLE} activity category - * - * @return a {@link BrainActivityGroup} containing the idle tasks your entity should run. - */ - default BrainActivityGroup getIdleTasks() { - return BrainActivityGroup.empty(); - } + /** + * Override this for tasks that would normally run when your entity is doing nothing else.
    + * Usually you'd use this for things like random walking, setting targets, or just standing still and doing nothing + * at all.
    + * Like all task groups, this method is optional, if you have no tasks that apply to this category
    + *
    + * Tasks returned in this category take up the {@link Activity#IDLE} activity category + * + * @return a {@link BrainActivityGroup} containing the idle tasks your entity should run. + */ + default BrainActivityGroup getIdleTasks() { + return BrainActivityGroup.empty(); + } - /** - * Override this to add the tasks that would normally run when your entity attacking something, or is otherwise in combat.
    - * Usually you'd use this for things melee attacking, invalidating attack targets, or setting walk targets based off the current attack target.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category - *

    - * Tasks returned in this category take up the {@link Activity#FIGHT} activity category - * - * @return a {@link BrainActivityGroup} containing the fight tasks your entity should run. - */ - default BrainActivityGroup getFightTasks() { - return BrainActivityGroup.empty(); - } + /** + * Override this to add the tasks that would normally run when your entity attacking something, or is otherwise in + * combat.
    + * Usually you'd use this for things melee attacking, invalidating attack targets, or setting walk targets based off + * the current attack target.
    + * Like all task groups, this method is optional, if you have no tasks that apply to this category
    + *
    + * Tasks returned in this category take up the {@link Activity#FIGHT} activity category + * + * @return a {@link BrainActivityGroup} containing the fight tasks your entity should run. + */ + default BrainActivityGroup getFightTasks() { + return BrainActivityGroup.empty(); + } - /** - * Override this to add any additional tasks that don't fit into the categories already handled in the pre-defined activity task methods.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category - * - * @return a {@link Map} of Activities to BrainActivityGroups group containing the additional tasks your entity should run. - */ - default Map> getAdditionalTasks() { - return new Object2ObjectOpenHashMap<>(0); - } + /** + * Override this to add any additional tasks that don't fit into the categories already handled in the pre-defined + * activity task methods.
    + * Like all task groups, this method is optional, if you have no tasks that apply to this category + * + * @return a {@link Map} of Activities to BrainActivityGroups group containing the additional tasks your entity + * should run. + */ + default Map> getAdditionalTasks() { + return new Object2ObjectOpenHashMap<>(0); + } - /** - * The activity categories that should always be running, regardless of any other conditions or situations.
    - * This is usually just left as {@link Activity#CORE}, but it can be modified as needed - * - * @return A {@link Set} of {@link Activity Activities} - */ - default Set getAlwaysRunningActivities() { - return ImmutableSet.of(Activity.CORE); - } + /** + * The activity categories that should always be running, regardless of any other conditions or situations.
    + * This is usually just left as {@link Activity#CORE}, but it can be modified as needed + * + * @return A {@link Set} of {@link Activity Activities} + */ + default Set getAlwaysRunningActivities() { + return ImmutableSet.of(Activity.CORE); + } - /** - * The activity category that is used as a fallback, for when no other activity categories meet the conditions to run.
    - * This is almost always left as {@link Activity#IDLE}, but it can be modified as needed. - * - * @return The {@link Activity} to use as a fallback - */ - default Activity getDefaultActivity() { - return Activity.IDLE; - } + /** + * The activity category that is used as a fallback, for when no other activity categories meet the conditions to + * run.
    + * This is almost always left as {@link Activity#IDLE}, but it can be modified as needed. + * + * @return The {@link Activity} to use as a fallback + */ + default Activity getDefaultActivity() { + return Activity.IDLE; + } - /** - * Override this to return the order of activity categories the brain should attempt to run things in.
    - * The list is ordered in order of insertion - I.E. earlier elements have higher priority - * - * @return An ordered {@link List} of {@link Activity} categories - */ - default List getActivityPriorities() { - return ObjectArrayList.of(Activity.FIGHT, Activity.IDLE); - } + /** + * Override this to return the order of activity categories the brain should attempt to run things in.
    + * The list is ordered in order of insertion - I.E. earlier elements have higher priority + * + * @return An ordered {@link List} of {@link Activity} categories + */ + default List getActivityPriorities() { + return ObjectArrayList.of(Activity.FIGHT, Activity.IDLE); + } - /** - * Override this to do any additional work after the brain has been built and readied.
    - * By this stage, the brain has had all its memories, sensors, activities, and priorities set. - * - * @param brain The brain that the entity will be using. - */ - default void handleAdditionalBrainSetup(SmartBrain brain) {} + /** + * Override this to do any additional work after the brain has been built and readied.
    + * By this stage, the brain has had all its memories, sensors, activities, and priorities set. + * + * @param brain The brain that the entity will be using. + */ + default void handleAdditionalBrainSetup(SmartBrain brain) {} - /** - * Override this to return the {@link net.minecraft.world.entity.schedule.Schedule schedule} for your entity.
    - * This can be set at any time via {@link SmartBrain#setSchedule(SmartBrainSchedule)}, but it's recommended to - * do so statically if possible and provide it through this method - * @return The schedule for the brain, or null if no schedule - */ - @Nullable - default SmartBrainSchedule getSchedule() { - return null; - } + /** + * Override this to return the {@link net.minecraft.world.entity.schedule.Schedule schedule} for your entity.
    + * This can be set at any time via {@link SmartBrain#setSchedule(SmartBrainSchedule)}, but it's recommended to do so + * statically if possible and provide it through this method + * + * @return The schedule for the brain, or null if no schedule + */ + @Nullable + default SmartBrainSchedule getSchedule() { + return null; + } - /** - * SmartBrainOwners MUST call this from the entity's {@link LivingEntity#serverAiStep}, or {@link Mob#customServerAiStep} if extending Mob.
    - * Brains should only be ticked server side.
    - * This method does not need to be overridden. - * @param entity The brain owner - */ - @APIOnly - default void tickBrain(T entity) { - ((Brain)entity.getBrain()).tick((ServerLevel)entity.level(), entity); - } + /** + * SmartBrainOwners MUST call this from the entity's {@link LivingEntity#serverAiStep}, or + * {@link Mob#customServerAiStep} if extending Mob.
    + * Brains should only be ticked server side.
    + * This method does not need to be overridden. + * + * @param entity The brain owner + */ + @APIOnly + default void tickBrain(T entity) { + ((Brain) entity.getBrain()).tick((ServerLevel) entity.level(), entity); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/BrainActivityGroup.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/BrainActivityGroup.java index 5f5c70f68..d17b4af60 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/BrainActivityGroup.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/BrainActivityGroup.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core; @@ -15,105 +14,119 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.schedule.Activity; -import mod.azure.azurelib.sblforked.api.SmartBrainOwner; import java.util.List; import java.util.Set; +import mod.azure.azurelib.sblforked.api.SmartBrainOwner; + public class BrainActivityGroup> { - private final Activity activity; - private int priorityStart = 0; - private final List> behaviours = new ObjectArrayList<>(); - private final Set, MemoryStatus>> activityStartMemoryConditions = new ObjectOpenHashSet<>(); - private Set> wipedMemoriesOnFinish = null; - public BrainActivityGroup(Activity activity) { - this.activity = activity; - } + private final Activity activity; + + private int priorityStart = 0; + + private final List> behaviours = new ObjectArrayList<>(); + + private final Set, MemoryStatus>> activityStartMemoryConditions = + new ObjectOpenHashSet<>(); + + private Set> wipedMemoriesOnFinish = null; + + public BrainActivityGroup(Activity activity) { + this.activity = activity; + } - public BrainActivityGroup priority(int priorityStart) { - this.priorityStart = priorityStart; + public BrainActivityGroup priority(int priorityStart) { + this.priorityStart = priorityStart; - return this; - } + return this; + } - public BrainActivityGroup behaviours(Behavior... behaviours) { - this.behaviours.addAll(new ObjectArrayList<>(behaviours)); + public BrainActivityGroup behaviours(Behavior... behaviours) { + this.behaviours.addAll(new ObjectArrayList<>(behaviours)); - return this; - } + return this; + } - public BrainActivityGroup onlyStartWithMemoryStatus(MemoryModuleType memory, MemoryStatus status) { - this.activityStartMemoryConditions.add(Pair.of(memory, status)); + public BrainActivityGroup onlyStartWithMemoryStatus(MemoryModuleType memory, MemoryStatus status) { + this.activityStartMemoryConditions.add(Pair.of(memory, status)); - return this; - } + return this; + } - public BrainActivityGroup wipeMemoriesWhenFinished(MemoryModuleType... memories) { - if (this.wipedMemoriesOnFinish == null) { - this.wipedMemoriesOnFinish = new ObjectOpenHashSet<>(memories); - } - else { - this.wipedMemoriesOnFinish.addAll(new ObjectOpenHashSet<>(memories)); - } + public BrainActivityGroup wipeMemoriesWhenFinished(MemoryModuleType... memories) { + if (this.wipedMemoriesOnFinish == null) { + this.wipedMemoriesOnFinish = new ObjectOpenHashSet<>(memories); + } else { + this.wipedMemoriesOnFinish.addAll(new ObjectOpenHashSet<>(memories)); + } - return this; - } + return this; + } - public BrainActivityGroup requireAndWipeMemoriesOnUse(MemoryModuleType... memories) { - for (MemoryModuleType memory : memories) { - onlyStartWithMemoryStatus(memory, MemoryStatus.VALUE_PRESENT); - } + public BrainActivityGroup requireAndWipeMemoriesOnUse(MemoryModuleType... memories) { + for (MemoryModuleType memory : memories) { + onlyStartWithMemoryStatus(memory, MemoryStatus.VALUE_PRESENT); + } - wipeMemoriesWhenFinished(memories); + wipeMemoriesWhenFinished(memories); - return this; - } + return this; + } - public Activity getActivity() { - return this.activity; - } + public Activity getActivity() { + return this.activity; + } - public List> getBehaviours() { - return this.behaviours; - } + public List> getBehaviours() { + return this.behaviours; + } - public int getPriorityStart() { - return this.priorityStart; - } + public int getPriorityStart() { + return this.priorityStart; + } - public Set, MemoryStatus>> getActivityStartMemoryConditions() { - return this.activityStartMemoryConditions; - } + public Set, MemoryStatus>> getActivityStartMemoryConditions() { + return this.activityStartMemoryConditions; + } - public Set> getWipedMemoriesOnFinish() { - return this.wipedMemoriesOnFinish != null ? this.wipedMemoriesOnFinish : Set.of(); - } + public Set> getWipedMemoriesOnFinish() { + return this.wipedMemoriesOnFinish != null ? this.wipedMemoriesOnFinish : Set.of(); + } - public ImmutableList>> pairBehaviourPriorities() { - int priority = this.priorityStart; - ImmutableList.Builder>> pairedBehaviours = ImmutableList.builder(); + public ImmutableList>> pairBehaviourPriorities() { + int priority = this.priorityStart; + ImmutableList.Builder>> pairedBehaviours = ImmutableList.builder(); - for (Behavior behaviour : this.behaviours) { - pairedBehaviours.add(Pair.of(priority++, behaviour)); - } + for (Behavior behaviour : this.behaviours) { + pairedBehaviours.add(Pair.of(priority++, behaviour)); + } - return pairedBehaviours.build(); - } + return pairedBehaviours.build(); + } - public static > BrainActivityGroup empty() { - return new BrainActivityGroup(Activity.REST); - } + public static > BrainActivityGroup empty() { + return new BrainActivityGroup(Activity.REST); + } - public static > BrainActivityGroup coreTasks(Behavior... behaviours) { - return new BrainActivityGroup(Activity.CORE).priority(0).behaviours(behaviours); - } + public static > BrainActivityGroup coreTasks( + Behavior... behaviours + ) { + return new BrainActivityGroup(Activity.CORE).priority(0).behaviours(behaviours); + } - public static > BrainActivityGroup idleTasks(Behavior... behaviours) { - return new BrainActivityGroup(Activity.IDLE).priority(10).behaviours(behaviours); - } + public static > BrainActivityGroup idleTasks( + Behavior... behaviours + ) { + return new BrainActivityGroup(Activity.IDLE).priority(10).behaviours(behaviours); + } - public static > BrainActivityGroup fightTasks(Behavior... behaviours) { - return new BrainActivityGroup(Activity.FIGHT).priority(10).behaviours(behaviours).requireAndWipeMemoriesOnUse(MemoryModuleType.ATTACK_TARGET); - } + public static > BrainActivityGroup fightTasks( + Behavior... behaviours + ) { + return new BrainActivityGroup(Activity.FIGHT).priority(10) + .behaviours(behaviours) + .requireAndWipeMemoriesOnUse(MemoryModuleType.ATTACK_TARGET); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrain.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrain.java index 9d6eea5c8..e1b6cf16d 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrain.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrain.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core; @@ -24,6 +23,13 @@ import net.minecraft.world.entity.ai.sensing.SensorType; import net.minecraft.world.entity.schedule.Activity; import net.minecraft.world.entity.schedule.Schedule; +import org.apache.commons.lang3.mutable.MutableObject; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Stream; + import mod.azure.azurelib.sblforked.api.SmartBrainOwner; import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; import mod.azure.azurelib.sblforked.api.core.schedule.SmartBrainSchedule; @@ -31,406 +37,491 @@ import mod.azure.azurelib.sblforked.object.BrainBehaviourConsumer; import mod.azure.azurelib.sblforked.object.BrainBehaviourPredicate; import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.apache.commons.lang3.mutable.MutableObject; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.Consumer; -import java.util.stream.Stream; /** - * Supercedes vanilla's {@link Brain}. One of the core components of the SBL - * library.
    - * Any entity that returns a {@link SmartBrainProvider} from - * {@link LivingEntity#brainProvider()} will have one of these. - * + * Supercedes vanilla's {@link Brain}. One of the core components of the SBL library.
    + * Any entity that returns a {@link SmartBrainProvider} from {@link LivingEntity#brainProvider()} will have one of + * these. + * * @param The entity */ public class SmartBrain> extends Brain { - private final List> expirableMemories = new ObjectArrayList<>(); - private final List> behaviours = new ObjectArrayList<>(); - private final List>, ExtendedSensor>> sensors = new ObjectArrayList<>(); - private SmartBrainSchedule schedule = null; - - private boolean sortBehaviours = false; - - public SmartBrain(List> memories, List> sensors, @Nullable List> taskList) { - super(memories, ImmutableList.of(), ImmutableList.of(), SmartBrain::emptyBrainCodec); - - for (ExtendedSensor sensor : sensors) { - this.sensors.add(Pair.of((SensorType)sensor.type(), sensor)); - } - - if (taskList != null) { - for (BrainActivityGroup group : taskList) { - addActivity(group); - } - } - } - - @Override - public void tick(ServerLevel level, E entity) { - entity.level().getProfiler().push("SmartBrain"); - - if (this.sortBehaviours) - this.behaviours.sort(Comparator.comparingInt(ActivityBehaviours::priority)); - - forgetOutdatedMemories(); - tickSensors(level, entity); - checkForNewBehaviours(level, entity); - tickRunningBehaviours(level, entity); - findAndSetActiveActivity(entity); - - entity.level().getProfiler().pop(); - - if (entity instanceof Mob mob) - mob.setAggressive(BrainUtils.hasMemory(mob, MemoryModuleType.ATTACK_TARGET)); - } - - private void findAndSetActiveActivity(E entity) { - if (this.schedule != null) { - Activity scheduledActivity = this.schedule.tick(entity); - - if (scheduledActivity != null && !getActiveActivities().contains(scheduledActivity) && activityRequirementsAreMet(scheduledActivity)) { - setActiveActivity(scheduledActivity); - - return; - } - } - - setActiveActivityToFirstValid(entity.getActivityPriorities()); - } - - private void tickSensors(ServerLevel level, E entity) { - for (Pair>, ExtendedSensor> sensor : this.sensors) { - sensor.getSecond().tick(level, entity); - } - } - - private void checkForNewBehaviours(ServerLevel level, E entity) { - long gameTime = level.getGameTime(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - if (getActiveActivities().contains(pair.getFirst())) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.STOPPED) - behaviour.tryStart(level, entity, gameTime); - } - } - } - } - } - - private void tickRunningBehaviours(ServerLevel level, E entity) { - long gameTime = level.getGameTime(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.tickOrStop(level, entity, gameTime); - } - } - } - } - - @Override - public void forgetOutdatedMemories() { - Iterator> expirable = this.expirableMemories.iterator(); - - while (expirable.hasNext()) { - MemoryModuleType memoryType = expirable.next(); - Optional> memory = memories.get(memoryType); - - if (memory.isEmpty()) { - expirable.remove(); - } - else { - ExpirableValue value = memory.get(); - - if (!value.canExpire()) { - expirable.remove(); - } - else if (value.hasExpired()) { - expirable.remove(); - eraseMemory(memoryType); - } - else { - value.tick(); - } - } - } - } - - @Override - public void stopAll(ServerLevel level, E entity) { - long gameTime = level.getGameTime(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.doStop(level, entity, gameTime); - } - } - } - } - - @Override - public Optional getMemory(MemoryModuleType type) { - return (Optional) this.memories.computeIfAbsent(type, key -> Optional.empty()).map(ExpirableValue::getValue); - } - - @Override - public void setMemoryInternal(MemoryModuleType memoryType, Optional> memory) { - if (memory.isPresent() && memory.get().getValue()instanceof Collection collection && collection.isEmpty()) - memory = Optional.empty(); - - this.memories.put(memoryType, memory); - - if (memory.isPresent() && memory.get().canExpire() && !this.expirableMemories.contains(memoryType)) - this.expirableMemories.add(memoryType); - } - - @Override - public boolean isMemoryValue(MemoryModuleType memoryType, U memory) { - Optional value = getMemory(memoryType); - - return value.isPresent() && value.get().equals(memory); - } - - private static > Codec> emptyBrainCodec() { - MutableObject>> brainCodec = new MutableObject<>(); - - brainCodec.setValue(Codec.unit(() -> new Brain<>(ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), brainCodec::getValue))); - - return brainCodec.getValue(); - } - - private static > List>> convertSensorsToTypes(List> sensors) { - List>> types = new ObjectArrayList<>(sensors.size()); - - for (ExtendedSensor sensor : sensors) { - types.add((SensorType)sensor.type()); - } - - return types; - } - - @Override - public Brain copyWithoutBehaviors() { - SmartBrain brain = new SmartBrain<>(this.memories.keySet().stream().toList(), this.sensors.stream().map(pair -> (ExtendedSensor) pair.getSecond()).toList(), null); - - for (Map.Entry, Optional>> entry : this.memories.entrySet()) { - MemoryModuleType memoryType = entry.getKey(); - - if (entry.getValue().isPresent()) - brain.memories.put(memoryType, entry.getValue()); - } - - return brain; - } - - @Override - public List> getRunningBehaviors() { - List> runningBehaviours = new ObjectArrayList<>(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - runningBehaviours.add(behaviour); - } - } - } - - return runningBehaviours; - } - - /** - * Returns a stream of all {@link BehaviorControl Behaviours} registered to this brain - */ - public Stream> getBehaviours() { - return this.behaviours.stream().map(ActivityBehaviours::behaviours).flatMap(list -> list.stream().map(Pair::getSecond).flatMap(List::stream)); - } - - @Override - public void removeAllBehaviors() { - this.behaviours.clear(); - } - - @Override - public void addActivityAndRemoveMemoriesWhenStopped(Activity activity, ImmutableList>> tasks, Set, MemoryStatus>> memorieStatuses, Set> memoryTypes) { - this.activityRequirements.put(activity, memorieStatuses); - - if (!memoryTypes.isEmpty()) - this.activityMemoriesToEraseWhenStopped.put(activity, memoryTypes); - - for (Pair> pair : tasks) { - addBehaviour(pair.getFirst(), activity, pair.getSecond()); - } - } - - /** - * Adds a full {@link BrainActivityGroup} to the brain, inclusive of activities and conditions - */ - public void addActivity(BrainActivityGroup activityGroup) { - addActivityAndRemoveMemoriesWhenStopped(activityGroup.getActivity(), activityGroup.pairBehaviourPriorities(), activityGroup.getActivityStartMemoryConditions(), activityGroup.getWipedMemoriesOnFinish()); - } - - /** - * Add a behaviour to the behaviours list of this brain. - * - * @param priority The behaviour's priority value - * @param activity The behaviour's activity category - * @param behaviour The behaviour instance - */ - public void addBehaviour(int priority, Activity activity, BehaviorControl behaviour) { - for (ActivityBehaviours behaviourGroup : this.behaviours) { - if (behaviourGroup.priority == priority) { - for (Pair>> pair : behaviourGroup.behaviours) { - if (pair.getFirst() == activity) { - pair.getSecond().add(behaviour); - - return; - } - } - - behaviourGroup.behaviours.add(Pair.of(activity, ObjectArrayList.of(behaviour))); - - return; - } - } - - this.behaviours.add(new ActivityBehaviours<>(priority, ObjectArrayList.of(Pair.of(activity, ObjectArrayList.>of(behaviour))))); - this.sortBehaviours = true; - } - - /** - * Removes any behaviours matching the given predicate from the provided brain.
    - * Removed behaviours are stopped prior to removal - * @param entity The owner of the brain - * @param predicate The predicate checked for each (priority, activity, behaviour) - */ - public void removeBehaviour(E entity, BrainBehaviourPredicate predicate) { - for (ActivityBehaviours behaviourGroup : this.behaviours) { - int priority = behaviourGroup.priority; - - for (Pair>> pair : behaviourGroup.behaviours) { - Activity activity = pair.getFirst(); - - for (Iterator> iterator = pair.getSecond().iterator(); iterator.hasNext();) { - BehaviorControl behaviour = iterator.next(); - - checkBehaviour(priority, activity, behaviour, null, predicate, () -> { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.doStop((ServerLevel)entity.level(), entity, entity.level().getGameTime()); - - iterator.remove(); - }); - } - } - } - } - - /** - * Sets a {@link SmartBrainSchedule} for this brain, for scheduled functionality - * @param schedule The schedule to set for the brain - * @return this - */ - public SmartBrain setSchedule(SmartBrainSchedule schedule) { - this.schedule = schedule; - - return this; - } - - /** - * @return The {@link SmartBrainSchedule schedule} of this brain - */ - @Override - public SmartBrainSchedule getSchedule() { - return this.schedule; - } - - /** - * Cheekily (and conveniently) uses the {@link SmartBrainSchedule schedule} system to schedule a delayed runnable for this entity/brain. - * @param delay The delay (in ticks) before running the task - * @param task The task to run at the given tick - */ - public void scheduleTask(E brainOwner, int delay, Consumer task) { - if (this.schedule == null) - this.schedule = new SmartBrainSchedule(); - - this.schedule.scheduleTask(brainOwner, delay, (Consumer)task); - } - - private static void checkBehaviour(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parentBehaviour, BrainBehaviourPredicate predicate, Runnable callback) { - if (predicate.isBehaviour(priority, activity, behaviour, parentBehaviour)) { - callback.run(); - } - else if (behaviour instanceof GateBehavior groupBehaviour) { - for (Iterator> childBehaviourIterator = groupBehaviour.behaviors.iterator(); childBehaviourIterator.hasNext();) { - checkBehaviour(priority, activity, childBehaviourIterator.next(), groupBehaviour, predicate, childBehaviourIterator::remove); - } - - if (!groupBehaviour.behaviors.iterator().hasNext()) - callback.run(); - } - else if (behaviour instanceof GroupBehaviour groupBehaviour) { - for (Iterator> childBehaviourIterator = groupBehaviour.getBehaviours(); childBehaviourIterator.hasNext();) { - checkBehaviour(priority, activity, childBehaviourIterator.next(), groupBehaviour, predicate, childBehaviourIterator::remove); - } - - if (!groupBehaviour.getBehaviours().hasNext()) - callback.run(); - } - } - - /** - * Loops over all {@link BehaviorControl Behaviours} registered to this brain, calling the consumer for each - * @param consumer The consumer called for each (priority, activity, behaviour) - */ - public void forEachBehaviour(BrainBehaviourConsumer consumer) { - for (ActivityBehaviours behavioursGroup : this.behaviours) { - int priority = behavioursGroup.priority(); - - for (Pair>> behaviourList : behavioursGroup.behaviours()) { - Activity activity = behaviourList.getFirst(); - - for (BehaviorControl behaviour : behaviourList.getSecond()) { - consumeBehaviour(priority, activity, behaviour, null, consumer); - } - } - } - } - - private static void consumeBehaviour(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parentBehaviour, BrainBehaviourConsumer consumer) { - consumer.consume(priority, activity, behaviour, parentBehaviour); - - if (behaviour instanceof GateBehavior groupBehaviour) { - groupBehaviour.behaviors.stream().forEach(childBehaviour -> consumeBehaviour(priority, activity, (BehaviorControl)childBehaviour, groupBehaviour, consumer)); - } - else if (behaviour instanceof GroupBehaviour groupBehaviour) { - groupBehaviour.getBehaviours().forEachRemaining(childBehaviour -> consumeBehaviour(priority, activity, (BehaviorControl)childBehaviour, groupBehaviour, consumer)); - } - } - - /** - * Adds an {@link ExtendedSensor} to this brain - */ - public void addSensor(ExtendedSensor sensor) { - SensorType> sensorType = (SensorType)sensor.type(); - - this.sensors.add(Pair.of(sensorType, sensor)); - } - - /** - * Not supported, use {@link SmartBrain#setSchedule(SmartBrainSchedule)} instead - */ - @Deprecated(forRemoval = true) - @Override - public final void setSchedule(Schedule schedule) {} - - private record ActivityBehaviours> (int priority, List>>> behaviours) {} + + private final List> expirableMemories = new ObjectArrayList<>(); + + private final List> behaviours = new ObjectArrayList<>(); + + private final List>, ExtendedSensor>> sensors = + new ObjectArrayList<>(); + + private SmartBrainSchedule schedule = null; + + private boolean sortBehaviours = false; + + public SmartBrain( + List> memories, + List> sensors, + @Nullable List> taskList + ) { + super(memories, ImmutableList.of(), ImmutableList.of(), SmartBrain::emptyBrainCodec); + + for (ExtendedSensor sensor : sensors) { + this.sensors.add(Pair.of((SensorType) sensor.type(), sensor)); + } + + if (taskList != null) { + for (BrainActivityGroup group : taskList) { + addActivity(group); + } + } + } + + @Override + public void tick(ServerLevel level, E entity) { + entity.level().getProfiler().push("SmartBrain"); + + if (this.sortBehaviours) + this.behaviours.sort(Comparator.comparingInt(ActivityBehaviours::priority)); + + forgetOutdatedMemories(); + tickSensors(level, entity); + checkForNewBehaviours(level, entity); + tickRunningBehaviours(level, entity); + findAndSetActiveActivity(entity); + + entity.level().getProfiler().pop(); + + if (entity instanceof Mob mob) + mob.setAggressive(BrainUtils.hasMemory(mob, MemoryModuleType.ATTACK_TARGET)); + } + + private void findAndSetActiveActivity(E entity) { + if (this.schedule != null) { + Activity scheduledActivity = this.schedule.tick(entity); + + if ( + scheduledActivity != null && !getActiveActivities().contains(scheduledActivity) + && activityRequirementsAreMet(scheduledActivity) + ) { + setActiveActivity(scheduledActivity); + + return; + } + } + + setActiveActivityToFirstValid(entity.getActivityPriorities()); + } + + private void tickSensors(ServerLevel level, E entity) { + for (Pair>, ExtendedSensor> sensor : this.sensors) { + sensor.getSecond().tick(level, entity); + } + } + + private void checkForNewBehaviours(ServerLevel level, E entity) { + long gameTime = level.getGameTime(); + + for (ActivityBehaviours behaviourGroup : this.behaviours) { + for (Pair>> pair : behaviourGroup.behaviours) { + if (getActiveActivities().contains(pair.getFirst())) { + for (BehaviorControl behaviour : pair.getSecond()) { + if (behaviour.getStatus() == Behavior.Status.STOPPED) + behaviour.tryStart(level, entity, gameTime); + } + } + } + } + } + + private void tickRunningBehaviours(ServerLevel level, E entity) { + long gameTime = level.getGameTime(); + + for (ActivityBehaviours behaviourGroup : this.behaviours) { + for (Pair>> pair : behaviourGroup.behaviours) { + for (BehaviorControl behaviour : pair.getSecond()) { + if (behaviour.getStatus() == Behavior.Status.RUNNING) + behaviour.tickOrStop(level, entity, gameTime); + } + } + } + } + + @Override + public void forgetOutdatedMemories() { + Iterator> expirable = this.expirableMemories.iterator(); + + while (expirable.hasNext()) { + MemoryModuleType memoryType = expirable.next(); + Optional> memory = memories.get(memoryType); + + if (memory.isEmpty()) { + expirable.remove(); + } else { + ExpirableValue value = memory.get(); + + if (!value.canExpire()) { + expirable.remove(); + } else if (value.hasExpired()) { + expirable.remove(); + eraseMemory(memoryType); + } else { + value.tick(); + } + } + } + } + + @Override + public void stopAll(ServerLevel level, E entity) { + long gameTime = level.getGameTime(); + + for (ActivityBehaviours behaviourGroup : this.behaviours) { + for (Pair>> pair : behaviourGroup.behaviours) { + for (BehaviorControl behaviour : pair.getSecond()) { + if (behaviour.getStatus() == Behavior.Status.RUNNING) + behaviour.doStop(level, entity, gameTime); + } + } + } + } + + @Override + public Optional getMemory(MemoryModuleType type) { + return (Optional) this.memories.computeIfAbsent(type, key -> Optional.empty()).map(ExpirableValue::getValue); + } + + @Override + public void setMemoryInternal(MemoryModuleType memoryType, Optional> memory) { + if (memory.isPresent() && memory.get().getValue() instanceof Collection collection && collection.isEmpty()) + memory = Optional.empty(); + + this.memories.put(memoryType, memory); + + if (memory.isPresent() && memory.get().canExpire() && !this.expirableMemories.contains(memoryType)) + this.expirableMemories.add(memoryType); + } + + @Override + public boolean isMemoryValue(MemoryModuleType memoryType, U memory) { + Optional value = getMemory(memoryType); + + return value.isPresent() && value.get().equals(memory); + } + + private static > Codec> emptyBrainCodec() { + MutableObject>> brainCodec = new MutableObject<>(); + + brainCodec.setValue( + Codec.unit( + () -> new Brain<>(ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), brainCodec::getValue) + ) + ); + + return brainCodec.getValue(); + } + + private static > List>> convertSensorsToTypes( + List> sensors + ) { + List>> types = new ObjectArrayList<>(sensors.size()); + + for (ExtendedSensor sensor : sensors) { + types.add((SensorType) sensor.type()); + } + + return types; + } + + @Override + public Brain copyWithoutBehaviors() { + SmartBrain brain = new SmartBrain<>( + this.memories.keySet().stream().toList(), + this.sensors.stream().map(pair -> (ExtendedSensor) pair.getSecond()).toList(), + null + ); + + for (Map.Entry, Optional>> entry : this.memories.entrySet()) { + MemoryModuleType memoryType = entry.getKey(); + + if (entry.getValue().isPresent()) + brain.memories.put(memoryType, entry.getValue()); + } + + return brain; + } + + @Override + public List> getRunningBehaviors() { + List> runningBehaviours = new ObjectArrayList<>(); + + for (ActivityBehaviours behaviourGroup : this.behaviours) { + for (Pair>> pair : behaviourGroup.behaviours) { + for (BehaviorControl behaviour : pair.getSecond()) { + if (behaviour.getStatus() == Behavior.Status.RUNNING) + runningBehaviours.add(behaviour); + } + } + } + + return runningBehaviours; + } + + /** + * Returns a stream of all {@link BehaviorControl Behaviours} registered to this brain + */ + public Stream> getBehaviours() { + return this.behaviours.stream() + .map(ActivityBehaviours::behaviours) + .flatMap(list -> list.stream().map(Pair::getSecond).flatMap(List::stream)); + } + + @Override + public void removeAllBehaviors() { + this.behaviours.clear(); + } + + @Override + public void addActivityAndRemoveMemoriesWhenStopped( + Activity activity, + ImmutableList>> tasks, + Set, MemoryStatus>> memorieStatuses, + Set> memoryTypes + ) { + this.activityRequirements.put(activity, memorieStatuses); + + if (!memoryTypes.isEmpty()) + this.activityMemoriesToEraseWhenStopped.put(activity, memoryTypes); + + for (Pair> pair : tasks) { + addBehaviour(pair.getFirst(), activity, pair.getSecond()); + } + } + + /** + * Adds a full {@link BrainActivityGroup} to the brain, inclusive of activities and conditions + */ + public void addActivity(BrainActivityGroup activityGroup) { + addActivityAndRemoveMemoriesWhenStopped( + activityGroup.getActivity(), + activityGroup.pairBehaviourPriorities(), + activityGroup.getActivityStartMemoryConditions(), + activityGroup.getWipedMemoriesOnFinish() + ); + } + + /** + * Add a behaviour to the behaviours list of this brain. + * + * @param priority The behaviour's priority value + * @param activity The behaviour's activity category + * @param behaviour The behaviour instance + */ + public void addBehaviour(int priority, Activity activity, BehaviorControl behaviour) { + for (ActivityBehaviours behaviourGroup : this.behaviours) { + if (behaviourGroup.priority == priority) { + for (Pair>> pair : behaviourGroup.behaviours) { + if (pair.getFirst() == activity) { + pair.getSecond().add(behaviour); + + return; + } + } + + behaviourGroup.behaviours.add(Pair.of(activity, ObjectArrayList.of(behaviour))); + + return; + } + } + + this.behaviours.add( + new ActivityBehaviours<>( + priority, + ObjectArrayList.of(Pair.of(activity, ObjectArrayList.>of(behaviour))) + ) + ); + this.sortBehaviours = true; + } + + /** + * Removes any behaviours matching the given predicate from the provided brain.
    + * Removed behaviours are stopped prior to removal + * + * @param entity The owner of the brain + * @param predicate The predicate checked for each (priority, activity, behaviour) + */ + public void removeBehaviour(E entity, BrainBehaviourPredicate predicate) { + for (ActivityBehaviours behaviourGroup : this.behaviours) { + int priority = behaviourGroup.priority; + + for (Pair>> pair : behaviourGroup.behaviours) { + Activity activity = pair.getFirst(); + + for (Iterator> iterator = pair.getSecond().iterator(); iterator.hasNext();) { + BehaviorControl behaviour = iterator.next(); + + checkBehaviour(priority, activity, behaviour, null, predicate, () -> { + if (behaviour.getStatus() == Behavior.Status.RUNNING) + behaviour.doStop((ServerLevel) entity.level(), entity, entity.level().getGameTime()); + + iterator.remove(); + }); + } + } + } + } + + /** + * Sets a {@link SmartBrainSchedule} for this brain, for scheduled functionality + * + * @param schedule The schedule to set for the brain + * @return this + */ + public SmartBrain setSchedule(SmartBrainSchedule schedule) { + this.schedule = schedule; + + return this; + } + + /** + * @return The {@link SmartBrainSchedule schedule} of this brain + */ + @Override + public SmartBrainSchedule getSchedule() { + return this.schedule; + } + + /** + * Cheekily (and conveniently) uses the {@link SmartBrainSchedule schedule} system to schedule a delayed runnable + * for this entity/brain. + * + * @param delay The delay (in ticks) before running the task + * @param task The task to run at the given tick + */ + public void scheduleTask(E brainOwner, int delay, Consumer task) { + if (this.schedule == null) + this.schedule = new SmartBrainSchedule(); + + this.schedule.scheduleTask(brainOwner, delay, (Consumer) task); + } + + private static void checkBehaviour( + int priority, + Activity activity, + BehaviorControl behaviour, + @Nullable BehaviorControl parentBehaviour, + BrainBehaviourPredicate predicate, + Runnable callback + ) { + if (predicate.isBehaviour(priority, activity, behaviour, parentBehaviour)) { + callback.run(); + } else if (behaviour instanceof GateBehavior groupBehaviour) { + for ( + Iterator> childBehaviourIterator = groupBehaviour.behaviors.iterator(); + childBehaviourIterator.hasNext(); + ) { + checkBehaviour( + priority, + activity, + childBehaviourIterator.next(), + groupBehaviour, + predicate, + childBehaviourIterator::remove + ); + } + + if (!groupBehaviour.behaviors.iterator().hasNext()) + callback.run(); + } else if (behaviour instanceof GroupBehaviour groupBehaviour) { + for ( + Iterator> childBehaviourIterator = groupBehaviour.getBehaviours(); + childBehaviourIterator.hasNext(); + ) { + checkBehaviour( + priority, + activity, + childBehaviourIterator.next(), + groupBehaviour, + predicate, + childBehaviourIterator::remove + ); + } + + if (!groupBehaviour.getBehaviours().hasNext()) + callback.run(); + } + } + + /** + * Loops over all {@link BehaviorControl Behaviours} registered to this brain, calling the consumer for each + * + * @param consumer The consumer called for each (priority, activity, behaviour) + */ + public void forEachBehaviour(BrainBehaviourConsumer consumer) { + for (ActivityBehaviours behavioursGroup : this.behaviours) { + int priority = behavioursGroup.priority(); + + for (Pair>> behaviourList : behavioursGroup.behaviours()) { + Activity activity = behaviourList.getFirst(); + + for (BehaviorControl behaviour : behaviourList.getSecond()) { + consumeBehaviour(priority, activity, behaviour, null, consumer); + } + } + } + } + + private static void consumeBehaviour( + int priority, + Activity activity, + BehaviorControl behaviour, + @Nullable BehaviorControl parentBehaviour, + BrainBehaviourConsumer consumer + ) { + consumer.consume(priority, activity, behaviour, parentBehaviour); + + if (behaviour instanceof GateBehavior groupBehaviour) { + groupBehaviour.behaviors.stream() + .forEach( + childBehaviour -> consumeBehaviour( + priority, + activity, + (BehaviorControl) childBehaviour, + groupBehaviour, + consumer + ) + ); + } else if (behaviour instanceof GroupBehaviour groupBehaviour) { + groupBehaviour.getBehaviours() + .forEachRemaining( + childBehaviour -> consumeBehaviour( + priority, + activity, + (BehaviorControl) childBehaviour, + groupBehaviour, + consumer + ) + ); + } + } + + /** + * Adds an {@link ExtendedSensor} to this brain + */ + public void addSensor(ExtendedSensor sensor) { + SensorType> sensorType = (SensorType) sensor.type(); + + this.sensors.add(Pair.of(sensorType, sensor)); + } + + /** + * Not supported, use {@link SmartBrain#setSchedule(SmartBrainSchedule)} instead + */ + @Deprecated(forRemoval = true) + @Override + public final void setSchedule(Schedule schedule) {} + + private record ActivityBehaviours>( + int priority, + List>>> behaviours + ) {} } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrainProvider.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrainProvider.java index aede4d53d..5dff12cc0 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrainProvider.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrainProvider.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core; @@ -20,130 +19,136 @@ import net.minecraft.world.entity.ai.behavior.GateBehavior; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.schedule.Activity; -import mod.azure.azurelib.sblforked.api.SmartBrainOwner; -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import java.util.List; import java.util.Map; import java.util.Set; +import mod.azure.azurelib.sblforked.api.SmartBrainOwner; +import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; + /** - * The provider of {@link SmartBrain SmartBrains}. All entities intending to - * utilise this library should return a new instance of this in - * {@link LivingEntity#brainProvider()}
    + * The provider of {@link SmartBrain SmartBrains}. All entities intending to utilise this library should return a new + * instance of this in {@link LivingEntity#brainProvider()}
    * All entities that use this provider use SmartBrains. - * + * * @param The entity */ public class SmartBrainProvider> extends Brain.Provider { - private static final Map, ImmutableList>> BRAIN_MEMORY_CACHE = new Object2ObjectOpenHashMap<>(); - - private final E owner; - - private final boolean nonStaticMemories; - - /** - * @param owner The owner of the brain - */ - public SmartBrainProvider(E owner) { - this(owner, false); - } - - /** - * @param owner The owner of the brain - * @param nonStaticMemories Whether the entity has different behaviours or - * sensors depending on the entity instance - */ - public SmartBrainProvider(E owner, boolean nonStaticMemories) { - super(List.of(), List.of()); - - this.owner = owner; - this.nonStaticMemories = nonStaticMemories; - } - - @Override - public final SmartBrain makeBrain(Dynamic codecLoader) { - List> sensors = this.owner.getSensors(); - List> taskList = compileTasks(); - ImmutableList> memories; - - if (!this.nonStaticMemories && BRAIN_MEMORY_CACHE.containsKey(this.owner.getType())) { - memories = BRAIN_MEMORY_CACHE.get(this.owner.getType()); - } - else { - memories = createMemoryList(taskList, sensors); - - if (!this.nonStaticMemories) - BRAIN_MEMORY_CACHE.put((EntityType)this.owner.getType(), memories); - } - - SmartBrain brain = new SmartBrain(memories, sensors, taskList); - - finaliseBrain(brain); - - return brain; - } - - private ImmutableList> createMemoryList(List> taskList, List> sensors) { - Set> memoryTypes = new ObjectOpenHashSet<>(); - - taskList.forEach(activityGroup -> activityGroup.getBehaviours().forEach(behavior -> collectMemoriesFromTask(memoryTypes, behavior))); - sensors.forEach(sensor -> memoryTypes.addAll(sensor.memoriesUsed())); - - return ImmutableList.copyOf(memoryTypes); - } - - private void collectMemoriesFromTask(Set> memories, BehaviorControl behaviour) { - if (behaviour instanceof GateBehavior gateBehaviour) { - gateBehaviour.behaviors.stream().forEach(subBehaviour -> collectMemoriesFromTask(memories, subBehaviour)); - } - else if (behaviour instanceof GroupBehaviour groupBehaviour) { - groupBehaviour.getBehaviours().forEachRemaining(subBehaviour -> collectMemoriesFromTask(memories, subBehaviour)); - } - else if (behaviour instanceof Behavior behaviour2) { - memories.addAll(behaviour2.entryCondition.keySet()); - } - } - - private List> compileTasks() { - List> tasks = new ObjectArrayList<>(); - BrainActivityGroup activityGroup; - - if (!(activityGroup = owner.getCoreTasks()).getBehaviours().isEmpty()) - tasks.add(activityGroup); - - if (!(activityGroup = owner.getIdleTasks()).getBehaviours().isEmpty()) - tasks.add(activityGroup); - - if (!(activityGroup = owner.getFightTasks()).getBehaviours().isEmpty()) - tasks.add(activityGroup); - - tasks.addAll(owner.getAdditionalTasks().values()); - - return tasks; - } - - private void finaliseBrain(SmartBrain brain) { - brain.setCoreActivities(this.owner.getAlwaysRunningActivities()); - brain.setDefaultActivity(this.owner.getDefaultActivity()); - brain.useDefaultActivity(); - brain.setSchedule(this.owner.getSchedule()); - this.owner.handleAdditionalBrainSetup(brain); - } - - /** - * Use one of the startup 'getTasks' methods if adding at startup, or else use {@link mod.azure.azurelib.sblforked.util.BrainUtils#addActivity(Brain, BrainActivityGroup)} - */ - @Deprecated(forRemoval = true) - protected void addActivity(SmartBrain brain, Activity activity, BrainActivityGroup activityGroup) { - brain.activityRequirements.put(activity, activityGroup.getActivityStartMemoryConditions()); - - if (!activityGroup.getWipedMemoriesOnFinish().isEmpty()) - brain.activityMemoriesToEraseWhenStopped.put(activity, activityGroup.getWipedMemoriesOnFinish()); - - for (Pair> pair : activityGroup.pairBehaviourPriorities()) { - brain.addBehaviour(pair.getFirst(), activity, pair.getSecond()); - } - } + + private static final Map, ImmutableList>> BRAIN_MEMORY_CACHE = + new Object2ObjectOpenHashMap<>(); + + private final E owner; + + private final boolean nonStaticMemories; + + /** + * @param owner The owner of the brain + */ + public SmartBrainProvider(E owner) { + this(owner, false); + } + + /** + * @param owner The owner of the brain + * @param nonStaticMemories Whether the entity has different behaviours or sensors depending on the entity instance + */ + public SmartBrainProvider(E owner, boolean nonStaticMemories) { + super(List.of(), List.of()); + + this.owner = owner; + this.nonStaticMemories = nonStaticMemories; + } + + @Override + public final SmartBrain makeBrain(Dynamic codecLoader) { + List> sensors = this.owner.getSensors(); + List> taskList = compileTasks(); + ImmutableList> memories; + + if (!this.nonStaticMemories && BRAIN_MEMORY_CACHE.containsKey(this.owner.getType())) { + memories = BRAIN_MEMORY_CACHE.get(this.owner.getType()); + } else { + memories = createMemoryList(taskList, sensors); + + if (!this.nonStaticMemories) + BRAIN_MEMORY_CACHE.put((EntityType) this.owner.getType(), memories); + } + + SmartBrain brain = new SmartBrain(memories, sensors, taskList); + + finaliseBrain(brain); + + return brain; + } + + private ImmutableList> createMemoryList( + List> taskList, + List> sensors + ) { + Set> memoryTypes = new ObjectOpenHashSet<>(); + + taskList.forEach( + activityGroup -> activityGroup.getBehaviours() + .forEach(behavior -> collectMemoriesFromTask(memoryTypes, behavior)) + ); + sensors.forEach(sensor -> memoryTypes.addAll(sensor.memoriesUsed())); + + return ImmutableList.copyOf(memoryTypes); + } + + private void collectMemoriesFromTask(Set> memories, BehaviorControl behaviour) { + if (behaviour instanceof GateBehavior gateBehaviour) { + gateBehaviour.behaviors.stream().forEach(subBehaviour -> collectMemoriesFromTask(memories, subBehaviour)); + } else if (behaviour instanceof GroupBehaviour groupBehaviour) { + groupBehaviour.getBehaviours() + .forEachRemaining(subBehaviour -> collectMemoriesFromTask(memories, subBehaviour)); + } else if (behaviour instanceof Behavior behaviour2) { + memories.addAll(behaviour2.entryCondition.keySet()); + } + } + + private List> compileTasks() { + List> tasks = new ObjectArrayList<>(); + BrainActivityGroup activityGroup; + + if (!(activityGroup = owner.getCoreTasks()).getBehaviours().isEmpty()) + tasks.add(activityGroup); + + if (!(activityGroup = owner.getIdleTasks()).getBehaviours().isEmpty()) + tasks.add(activityGroup); + + if (!(activityGroup = owner.getFightTasks()).getBehaviours().isEmpty()) + tasks.add(activityGroup); + + tasks.addAll(owner.getAdditionalTasks().values()); + + return tasks; + } + + private void finaliseBrain(SmartBrain brain) { + brain.setCoreActivities(this.owner.getAlwaysRunningActivities()); + brain.setDefaultActivity(this.owner.getDefaultActivity()); + brain.useDefaultActivity(); + brain.setSchedule(this.owner.getSchedule()); + this.owner.handleAdditionalBrainSetup(brain); + } + + /** + * Use one of the startup 'getTasks' methods if adding at startup, or else use + * {@link mod.azure.azurelib.sblforked.util.BrainUtils#addActivity(Brain, BrainActivityGroup)} + */ + @Deprecated(forRemoval = true) + protected void addActivity(SmartBrain brain, Activity activity, BrainActivityGroup activityGroup) { + brain.activityRequirements.put(activity, activityGroup.getActivityStartMemoryConditions()); + + if (!activityGroup.getWipedMemoriesOnFinish().isEmpty()) + brain.activityMemoriesToEraseWhenStopped.put(activity, activityGroup.getWipedMemoriesOnFinish()); + + for (Pair> pair : activityGroup.pairBehaviourPriorities()) { + brain.addBehaviour(pair.getFirst(), activity, pair.getSecond()); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/AllApplicableBehaviours.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/AllApplicableBehaviours.java index c29ac491a..e80c1ccf7 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/AllApplicableBehaviours.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/AllApplicableBehaviours.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour; @@ -10,117 +9,132 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import mod.azure.azurelib.sblforked.object.SBLShufflingList; import org.jetbrains.annotations.Nullable; import java.util.Set; import java.util.stream.Collectors; +import mod.azure.azurelib.sblforked.object.SBLShufflingList; + /** * Group behaviour that attempts to run all sub-behaviours in order, running any that apply.
    * This allows for wrapping entire groups of behaviours in overarching conditions or nesting them in other groups.
    * This will count this behaviour as running if any of the child behaviours are running. + * * @param The entity */ public final class AllApplicableBehaviours extends GroupBehaviour { - public AllApplicableBehaviours(Pair, Integer>... behaviours) { - super(behaviours); - } - - public AllApplicableBehaviours(ExtendedBehaviour... behaviours) { - super(behaviours); - } - - @Override - protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { - if (this.cooldownFinishedAt > gameTime || !hasRequiredMemories(entity) || !this.startCondition.test(entity) || !checkExtraStartConditions(level, entity)) - return false; - - return (this.runningBehaviour = pickBehaviour(level, entity, gameTime, this.behaviours)) != null; - } - - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour(ServerLevel level, E entity, long gameTime, SBLShufflingList> extendedBehaviours) { - ExtendedBehaviour lastSuccessfulBehaviour = null; - - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (behaviour.tryStart(level, entity, gameTime)) - lastSuccessfulBehaviour = behaviour; - } - - return lastSuccessfulBehaviour; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - boolean stillOperational = false; - - for (ExtendedBehaviour behaviour : this.behaviours) { - stillOperational |= behaviour.getStatus() == Status.RUNNING && behaviour.canStillUse((ServerLevel)entity.level(), entity, entity.level().getGameTime()); - } - - return stillOperational; - } - - @Override - protected boolean timedOut(long gameTime) { - boolean timedOut = true; - - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING && !behaviour.timedOut(gameTime)) - timedOut = false; - } - - return timedOut; - } - - @Override - protected void tick(ServerLevel level, E owner, long gameTime) { - boolean stillRunning = false; - - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING) { - behaviour.tickOrStop(level, owner, gameTime); - - if (behaviour.getStatus() != Status.STOPPED) - stillRunning = true; - } - } - - if (!stillRunning) - doStop(level, owner, gameTime); - } - - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - this.cooldownFinishedAt = gameTime + cooldownProvider.apply(entity); - - this.taskStopCallback.accept(entity); - stop(entity); - - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING) - behaviour.doStop(level, entity, gameTime); - } - } - - @Override - public Status getStatus() { - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING) - return Status.RUNNING; - } - - return Status.STOPPED; - } - - @Override - public String toString() { - final Set> activeBehaviours = this.behaviours.stream() - .filter(behaviorControl -> behaviorControl.getStatus() == Status.RUNNING) - .collect(Collectors.toSet()); - - return "(" + getClass().getSimpleName() + "): " + activeBehaviours; - } + + public AllApplicableBehaviours(Pair, Integer>... behaviours) { + super(behaviours); + } + + public AllApplicableBehaviours(ExtendedBehaviour... behaviours) { + super(behaviours); + } + + @Override + protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { + if ( + this.cooldownFinishedAt > gameTime || !hasRequiredMemories(entity) || !this.startCondition.test(entity) + || !checkExtraStartConditions(level, entity) + ) + return false; + + return (this.runningBehaviour = pickBehaviour(level, entity, gameTime, this.behaviours)) != null; + } + + @Nullable + @Override + protected ExtendedBehaviour pickBehaviour( + ServerLevel level, + E entity, + long gameTime, + SBLShufflingList> extendedBehaviours + ) { + ExtendedBehaviour lastSuccessfulBehaviour = null; + + for (ExtendedBehaviour behaviour : extendedBehaviours) { + if (behaviour.tryStart(level, entity, gameTime)) + lastSuccessfulBehaviour = behaviour; + } + + return lastSuccessfulBehaviour; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + boolean stillOperational = false; + + for (ExtendedBehaviour behaviour : this.behaviours) { + stillOperational |= behaviour.getStatus() == Status.RUNNING && behaviour.canStillUse( + (ServerLevel) entity.level(), + entity, + entity.level().getGameTime() + ); + } + + return stillOperational; + } + + @Override + protected boolean timedOut(long gameTime) { + boolean timedOut = true; + + for (ExtendedBehaviour behaviour : this.behaviours) { + if (behaviour.getStatus() == Status.RUNNING && !behaviour.timedOut(gameTime)) + timedOut = false; + } + + return timedOut; + } + + @Override + protected void tick(ServerLevel level, E owner, long gameTime) { + boolean stillRunning = false; + + for (ExtendedBehaviour behaviour : this.behaviours) { + if (behaviour.getStatus() == Status.RUNNING) { + behaviour.tickOrStop(level, owner, gameTime); + + if (behaviour.getStatus() != Status.STOPPED) + stillRunning = true; + } + } + + if (!stillRunning) + doStop(level, owner, gameTime); + } + + @Override + protected void stop(ServerLevel level, E entity, long gameTime) { + this.cooldownFinishedAt = gameTime + cooldownProvider.apply(entity); + + this.taskStopCallback.accept(entity); + stop(entity); + + for (ExtendedBehaviour behaviour : this.behaviours) { + if (behaviour.getStatus() == Status.RUNNING) + behaviour.doStop(level, entity, gameTime); + } + } + + @Override + public Status getStatus() { + for (ExtendedBehaviour behaviour : this.behaviours) { + if (behaviour.getStatus() == Status.RUNNING) + return Status.RUNNING; + } + + return Status.STOPPED; + } + + @Override + public String toString() { + final Set> activeBehaviours = this.behaviours.stream() + .filter(behaviorControl -> behaviorControl.getStatus() == Status.RUNNING) + .collect(Collectors.toSet()); + + return "(" + getClass().getSimpleName() + "): " + activeBehaviours; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/DelayedBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/DelayedBehaviour.java index 0936262c0..c4a79d1f9 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/DelayedBehaviour.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/DelayedBehaviour.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour; @@ -13,71 +12,75 @@ /** * An abstract behaviour used for tasks that should have a start, and then a followup delayed action.
    - * This is most useful for things like attacks that have associated animations, or action which require a charge up or prep time.
    + * This is most useful for things like attacks that have associated animations, or action which require a charge up or + * prep time.
    * * @param The entity */ public abstract class DelayedBehaviour extends ExtendedBehaviour { - protected final int delayTime; - protected long delayFinishedAt = 0; - protected Consumer delayedCallback = entity -> {}; - - public DelayedBehaviour(int delayTicks) { - this.delayTime = delayTicks; - - runFor(entity -> Math.max(delayTicks, 60)); - } - - /** - * A callback for when the delayed action is called. - * @param callback The callback - * @return this - */ - public final DelayedBehaviour whenActivating(Consumer callback) { - this.delayedCallback = callback; - - return this; - } - - @Override - protected final void start(ServerLevel level, E entity, long gameTime) { - if (this.delayTime > 0) { - this.delayFinishedAt = gameTime + this.delayTime; - - super.start(level, entity, gameTime); - } - else { - super.start(level, entity, gameTime); - doDelayedAction(entity); - } - } - - @Override - protected final void stop(ServerLevel level, E entity, long gameTime) { - super.stop(level, entity, gameTime); - - this.delayFinishedAt = 0; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.delayFinishedAt >= entity.level().getGameTime(); - } - - @Override - protected final void tick(ServerLevel level, E entity, long gameTime) { - super.tick(level, entity, gameTime); - - if (this.delayFinishedAt <= gameTime) { - doDelayedAction(entity); - this.delayedCallback.accept(entity); - } - } - - /** - * The action to take once the delay period has elapsed. - * - * @param entity The owner of the brain - */ - protected void doDelayedAction(E entity) {} + + protected final int delayTime; + + protected long delayFinishedAt = 0; + + protected Consumer delayedCallback = entity -> {}; + + public DelayedBehaviour(int delayTicks) { + this.delayTime = delayTicks; + + runFor(entity -> Math.max(delayTicks, 60)); + } + + /** + * A callback for when the delayed action is called. + * + * @param callback The callback + * @return this + */ + public final DelayedBehaviour whenActivating(Consumer callback) { + this.delayedCallback = callback; + + return this; + } + + @Override + protected final void start(ServerLevel level, E entity, long gameTime) { + if (this.delayTime > 0) { + this.delayFinishedAt = gameTime + this.delayTime; + + super.start(level, entity, gameTime); + } else { + super.start(level, entity, gameTime); + doDelayedAction(entity); + } + } + + @Override + protected final void stop(ServerLevel level, E entity, long gameTime) { + super.stop(level, entity, gameTime); + + this.delayFinishedAt = 0; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return this.delayFinishedAt >= entity.level().getGameTime(); + } + + @Override + protected final void tick(ServerLevel level, E entity, long gameTime) { + super.tick(level, entity, gameTime); + + if (this.delayFinishedAt <= gameTime) { + doDelayedAction(entity); + this.delayedCallback.accept(entity); + } + } + + /** + * The action to take once the delay period has elapsed. + * + * @param entity The owner of the brain + */ + protected void doDelayedAction(E entity) {} } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/ExtendedBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/ExtendedBehaviour.java index 8db53125b..4b05bc0ec 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/ExtendedBehaviour.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/ExtendedBehaviour.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour; @@ -14,320 +13,313 @@ import net.minecraft.world.entity.ai.behavior.Behavior; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.APIOnly; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.APIOnly; + /** - * An extension of the base Behavior class that is used for tasks in the brain - * system.
    - * This extension auto-handles some boilerplate and adds in some additional - * auto-handled functions:
    + * An extension of the base Behavior class that is used for tasks in the brain system.
    + * This extension auto-handles some boilerplate and adds in some additional auto-handled functions:
    *

      *
    • Task start and stop callbacks for additional entity-interactions
    • *
    • A functional implementation of a duration provider
    • *
    • A functional implementation of a cooldown provider
    • *
    - * Ideally, all custom behaviours should use at least this class as a base, - * instead of the core Behavior class + * Ideally, all custom behaviours should use at least this class as a base, instead of the core Behavior class * * @param Your entity */ public abstract class ExtendedBehaviour extends Behavior { - protected Predicate startCondition = entity -> true; - protected Predicate stopCondition = entity -> false; - protected Consumer taskStartCallback = entity -> {}; - protected Consumer taskStopCallback = entity -> {}; - - protected Function runtimeProvider = entity -> 60; - protected Function cooldownProvider = entity -> 0; - protected long cooldownFinishedAt = 0; - - public ExtendedBehaviour() { - super(new Object2ObjectOpenHashMap<>()); - - for (Pair, MemoryStatus> memoryReq : getMemoryRequirements()) { - this.entryCondition.put(memoryReq.getFirst(), memoryReq.getSecond()); - } - } - - /** - * A callback for when the task begins. Use this to trigger effects or handle - * things when the entity activates this task. - * - * @param callback The callback - * @return this - */ - public final ExtendedBehaviour whenStarting(Consumer callback) { - this.taskStartCallback = callback; - - return this; - } - - /** - * A callback for when the task stops. Use this to trigger effects or handle - * things when the entity ends this task.
    - * Note that the task stopping does not necessarily mean it was successful. - * - * @param callback The callback - * @return this - */ - public final ExtendedBehaviour whenStopping(Consumer callback) { - this.taskStopCallback = callback; - - return this; - } - - /** - * Set the length that the task should run for, once activated. The value used - * is in ticks. - * - * @param timeProvider A function for the tick value - * @return this - */ - public final ExtendedBehaviour runFor(Function timeProvider) { - this.runtimeProvider = timeProvider; - - return this; - } - - /** - * Set the length that the task should wait for between activations. This is the - * time between when the task stops, and it is able to start again. The value - * used is in ticks - * - * @param timeProvider A function for the tick value - * @return this - */ - public final ExtendedBehaviour cooldownFor(Function timeProvider) { - this.cooldownProvider = timeProvider; - - return this; - } - - /** - * Set an additional condition for the behaviour to be able to start. Useful for - * dynamically predicating behaviours.
    - * Prevents this behaviour starting unless this predicate returns true. - * - * @param predicate The predicate - * @return this - */ - public final ExtendedBehaviour startCondition(Predicate predicate) { - this.startCondition = predicate; - - return this; - } - - /** - * Set an automatic condition for the behavior to stop. Useful for dynamically - * stopping behaviours. Has no effect on one-shot behaviours that don't have a - * runtime.
    - * Stops the behaviour if it is active and this predicate returns true. - * - * @param predicate The predicate - * @return this - */ - public final ExtendedBehaviour stopIf(Predicate predicate) { - this.stopCondition = predicate; - - return this; - } - - /** - * Defines a maximum value timeout period for this behaviour. - *

    Functionally, this means that the behaviour will not timeout, and will rely on other factors to stop (such as memory conditions failing)

    - * @return this - */ - public final ExtendedBehaviour noTimeout() { - return runFor(entity -> Integer.MAX_VALUE); - } - - @Override - public final boolean tryStart(ServerLevel level, E entity, long gameTime) { - if (!doStartCheck(level, entity, gameTime)) - return false; - - this.status = Status.RUNNING; - this.endTimestamp = gameTime + this.runtimeProvider.apply(entity); - - start(level, entity, gameTime); - - return true; - } - - @APIOnly - protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { - return this.cooldownFinishedAt <= gameTime && hasRequiredMemories(entity) && this.startCondition.test(entity) - && checkExtraStartConditions(level, entity); - } - - /** - * Check any extra conditions required for this behaviour to start.
    - * By this stage, memory conditions from - * {@link ExtendedBehaviour#getMemoryRequirements()} have already been checked. - * - * @param level The level the entity is in - * @param entity The owner of the brain - * @return Whether the conditions have been met to start the behaviour - */ - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return true; - } - - /** - * The root stop method for when this behaviour stops. This method should only - * be overridden by other abstract subclasses.
    - * If overriding, ensure you either call {@code super} or manually call - * {@code stop(E)} yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - */ - @APIOnly - @Override - protected void start(ServerLevel level, E entity, long gameTime) { - this.taskStartCallback.accept(entity); - start(entity); - } - - /** - * Override this for custom behaviour implementations. This is a safe endpoint - * for behaviours so that all required auto-handling is safely contained without - * super calls.
    - * This is called when the behaviour is to start. Set up any instance variables - * needed or perform the required actions.
    - * By this stage any memory requirements set in - * {@link ExtendedBehaviour#getMemoryRequirements()} are true, so any memories - * paired with {@link MemoryStatus#VALUE_PRESENT} are safe to retrieve. - * - * @param entity The entity being handled (I.E. the owner of the brain) - */ - protected void start(E entity) { - } - - /** - * The root stop method for when this behaviour stops. This method should only - * be overridden by other abstract subclasses.
    - * If overriding, ensure you either call {@code super} or manually call - * {@code stop(E)} yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - */ - @APIOnly - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - this.cooldownFinishedAt = gameTime + cooldownProvider.apply(entity); - - this.taskStopCallback.accept(entity); - stop(entity); - } - - /** - * Override this for custom behaviour implementations. This is a safe endpoint - * for behaviours so that all required auto-handling is safely contained without - * super calls.
    - * This is called when the behaviour is to stop. Close off any instanced - * variables and such here, ready for the next start. - * - * @param entity The entity being handled (I.E. the owner of the brain) - */ - protected void stop(E entity) { - } - - /** - * The root method to check if this behaviour should continue running. This - * method should only be overridden by other abstract subclasses.
    - * If overriding, ensure you either call super or manually call the - * {@link ExtendedBehaviour#stopCondition} check yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - * @return Whether the behaviour should continue ticking - */ - @Override - protected boolean canStillUse(ServerLevel level, E entity, long gameTime) { - return shouldKeepRunning(entity) && !this.stopCondition.test(entity); - } - - /** - * Check whether the behaviour should continue running. This is checked before - * {@link ExtendedBehaviour#tick(E)}.
    - * Memories are not guaranteed to be in their required state here, so if you - * have required memories, it might be worth checking them here. - * - * @param entity The owner of the brain - * @return Whether the behaviour should continue ticking - */ - protected boolean shouldKeepRunning(E entity) { - return false; - } - - /** - * The root tick method for when this behaviour ticks. This method should only - * be overridden by other abstract subclasses.
    - * If overriding, ensure you either call {@code super} or manually call - * {@code tick(E)} yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - */ - @APIOnly - @Override - protected void tick(ServerLevel level, E entity, long gameTime) { - tick(entity); - } - - /** - * Override this for custom behaviour implementations. This is a safe endpoint - * for behaviours so that all required auto-handling is safely contained without - * super calls.
    - * This is called when the behaviour is ticked. Be aware this is called every - * tick, so use tick reduction if needed to minimise performance impacts of - * goals.
    - * NOTE: Memory requirements are not guaranteed at this stage. If you are - * retrieving brain memories, you'll need to check their presence before use. - * - * @param entity The entity being handled (I.E. the owner of the brain) - */ - protected void tick(E entity) { - } - - @Override - protected boolean timedOut(long gameTime) { - return super.timedOut(gameTime); - } - - @APIOnly - @Override - public final boolean hasRequiredMemories(E entity) { - Brain brain = entity.getBrain(); - - for (Pair, MemoryStatus> memoryPair : getMemoryRequirements()) { - if (!brain.checkMemory(memoryPair.getFirst(), memoryPair.getSecond())) - return false; - } - - return true; - } - - /** - * The list of memory requirements this task has prior to starting. This - * outlines the approximate state the brain should be in, in order to allow this - * behaviour to run.
    - * Bonus points if it's a statically-initialised list. - * - * @return The {@link List} of {@link MemoryModuleType Memories} and their - * associated required {@link MemoryStatus status} - */ - protected abstract List, MemoryStatus>> getMemoryRequirements(); + + protected Predicate startCondition = entity -> true; + + protected Predicate stopCondition = entity -> false; + + protected Consumer taskStartCallback = entity -> {}; + + protected Consumer taskStopCallback = entity -> {}; + + protected Function runtimeProvider = entity -> 60; + + protected Function cooldownProvider = entity -> 0; + + protected long cooldownFinishedAt = 0; + + public ExtendedBehaviour() { + super(new Object2ObjectOpenHashMap<>()); + + for (Pair, MemoryStatus> memoryReq : getMemoryRequirements()) { + this.entryCondition.put(memoryReq.getFirst(), memoryReq.getSecond()); + } + } + + /** + * A callback for when the task begins. Use this to trigger effects or handle things when the entity activates this + * task. + * + * @param callback The callback + * @return this + */ + public final ExtendedBehaviour whenStarting(Consumer callback) { + this.taskStartCallback = callback; + + return this; + } + + /** + * A callback for when the task stops. Use this to trigger effects or handle things when the entity ends this task. + *
    + * Note that the task stopping does not necessarily mean it was successful. + * + * @param callback The callback + * @return this + */ + public final ExtendedBehaviour whenStopping(Consumer callback) { + this.taskStopCallback = callback; + + return this; + } + + /** + * Set the length that the task should run for, once activated. The value used is in ticks. + * + * @param timeProvider A function for the tick value + * @return this + */ + public final ExtendedBehaviour runFor(Function timeProvider) { + this.runtimeProvider = timeProvider; + + return this; + } + + /** + * Set the length that the task should wait for between activations. This is the time between when the task stops, + * and it is able to start again. The value used is in ticks + * + * @param timeProvider A function for the tick value + * @return this + */ + public final ExtendedBehaviour cooldownFor(Function timeProvider) { + this.cooldownProvider = timeProvider; + + return this; + } + + /** + * Set an additional condition for the behaviour to be able to start. Useful for dynamically predicating + * behaviours.
    + * Prevents this behaviour starting unless this predicate returns true. + * + * @param predicate The predicate + * @return this + */ + public final ExtendedBehaviour startCondition(Predicate predicate) { + this.startCondition = predicate; + + return this; + } + + /** + * Set an automatic condition for the behavior to stop. Useful for dynamically stopping behaviours. Has no effect on + * one-shot behaviours that don't have a runtime.
    + * Stops the behaviour if it is active and this predicate returns true. + * + * @param predicate The predicate + * @return this + */ + public final ExtendedBehaviour stopIf(Predicate predicate) { + this.stopCondition = predicate; + + return this; + } + + /** + * Defines a maximum value timeout period for this behaviour. + *

    + * Functionally, this means that the behaviour will not timeout, and will rely on other factors to stop (such as + * memory conditions failing) + *

    + * + * @return this + */ + public final ExtendedBehaviour noTimeout() { + return runFor(entity -> Integer.MAX_VALUE); + } + + @Override + public final boolean tryStart(ServerLevel level, E entity, long gameTime) { + if (!doStartCheck(level, entity, gameTime)) + return false; + + this.status = Status.RUNNING; + this.endTimestamp = gameTime + this.runtimeProvider.apply(entity); + + start(level, entity, gameTime); + + return true; + } + + @APIOnly + protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { + return this.cooldownFinishedAt <= gameTime && hasRequiredMemories(entity) && this.startCondition.test(entity) + && checkExtraStartConditions(level, entity); + } + + /** + * Check any extra conditions required for this behaviour to start.
    + * By this stage, memory conditions from {@link ExtendedBehaviour#getMemoryRequirements()} have already been + * checked. + * + * @param level The level the entity is in + * @param entity The owner of the brain + * @return Whether the conditions have been met to start the behaviour + */ + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + return true; + } + + /** + * The root stop method for when this behaviour stops. This method should only be overridden by other abstract + * subclasses.
    + * If overriding, ensure you either call {@code super} or manually call {@code stop(E)} yourself. + * + * @param level The level the entity is in + * @param entity The entity the brain belongs to + * @param gameTime The current gameTime (in ticks) of the level + */ + @APIOnly + @Override + protected void start(ServerLevel level, E entity, long gameTime) { + this.taskStartCallback.accept(entity); + start(entity); + } + + /** + * Override this for custom behaviour implementations. This is a safe endpoint for behaviours so that all required + * auto-handling is safely contained without super calls.
    + * This is called when the behaviour is to start. Set up any instance variables needed or perform the required + * actions.
    + * By this stage any memory requirements set in {@link ExtendedBehaviour#getMemoryRequirements()} are true, so any + * memories paired with {@link MemoryStatus#VALUE_PRESENT} are safe to retrieve. + * + * @param entity The entity being handled (I.E. the owner of the brain) + */ + protected void start(E entity) {} + + /** + * The root stop method for when this behaviour stops. This method should only be overridden by other abstract + * subclasses.
    + * If overriding, ensure you either call {@code super} or manually call {@code stop(E)} yourself. + * + * @param level The level the entity is in + * @param entity The entity the brain belongs to + * @param gameTime The current gameTime (in ticks) of the level + */ + @APIOnly + @Override + protected void stop(ServerLevel level, E entity, long gameTime) { + this.cooldownFinishedAt = gameTime + cooldownProvider.apply(entity); + + this.taskStopCallback.accept(entity); + stop(entity); + } + + /** + * Override this for custom behaviour implementations. This is a safe endpoint for behaviours so that all required + * auto-handling is safely contained without super calls.
    + * This is called when the behaviour is to stop. Close off any instanced variables and such here, ready for the next + * start. + * + * @param entity The entity being handled (I.E. the owner of the brain) + */ + protected void stop(E entity) {} + + /** + * The root method to check if this behaviour should continue running. This method should only be overridden by + * other abstract subclasses.
    + * If overriding, ensure you either call super or manually call the {@link ExtendedBehaviour#stopCondition} check + * yourself. + * + * @param level The level the entity is in + * @param entity The entity the brain belongs to + * @param gameTime The current gameTime (in ticks) of the level + * @return Whether the behaviour should continue ticking + */ + @Override + protected boolean canStillUse(ServerLevel level, E entity, long gameTime) { + return shouldKeepRunning(entity) && !this.stopCondition.test(entity); + } + + /** + * Check whether the behaviour should continue running. This is checked before {@link ExtendedBehaviour#tick(E)}. + *
    + * Memories are not guaranteed to be in their required state here, so if you have required memories, it might be + * worth checking them here. + * + * @param entity The owner of the brain + * @return Whether the behaviour should continue ticking + */ + protected boolean shouldKeepRunning(E entity) { + return false; + } + + /** + * The root tick method for when this behaviour ticks. This method should only be overridden by other abstract + * subclasses.
    + * If overriding, ensure you either call {@code super} or manually call {@code tick(E)} yourself. + * + * @param level The level the entity is in + * @param entity The entity the brain belongs to + * @param gameTime The current gameTime (in ticks) of the level + */ + @APIOnly + @Override + protected void tick(ServerLevel level, E entity, long gameTime) { + tick(entity); + } + + /** + * Override this for custom behaviour implementations. This is a safe endpoint for behaviours so that all required + * auto-handling is safely contained without super calls.
    + * This is called when the behaviour is ticked. Be aware this is called every tick, so use tick reduction if + * needed to minimise performance impacts of goals.
    + * NOTE: Memory requirements are not guaranteed at this stage. If you are retrieving brain memories, you'll + * need to check their presence before use. + * + * @param entity The entity being handled (I.E. the owner of the brain) + */ + protected void tick(E entity) {} + + @Override + protected boolean timedOut(long gameTime) { + return super.timedOut(gameTime); + } + + @APIOnly + @Override + public final boolean hasRequiredMemories(E entity) { + Brain brain = entity.getBrain(); + + for (Pair, MemoryStatus> memoryPair : getMemoryRequirements()) { + if (!brain.checkMemory(memoryPair.getFirst(), memoryPair.getSecond())) + return false; + } + + return true; + } + + /** + * The list of memory requirements this task has prior to starting. This outlines the approximate state the brain + * should be in, in order to allow this behaviour to run.
    + * Bonus points if it's a statically-initialised list. + * + * @return The {@link List} of {@link MemoryModuleType Memories} and their associated required {@link MemoryStatus + * status} + */ + protected abstract List, MemoryStatus>> getMemoryRequirements(); } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/FirstApplicableBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/FirstApplicableBehaviour.java index 260783d76..031d3fec5 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/FirstApplicableBehaviour.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/FirstApplicableBehaviour.java @@ -1,38 +1,45 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour; import com.mojang.datafixers.util.Pair; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; -import mod.azure.azurelib.sblforked.object.SBLShufflingList; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.sblforked.object.SBLShufflingList; + /** * Group behaviour that attempts to run all sub-behaviours in order, until the first successful one. + * * @param The entity */ public final class FirstApplicableBehaviour extends GroupBehaviour { - public FirstApplicableBehaviour(Pair, Integer>... behaviours) { - super(behaviours); - } - public FirstApplicableBehaviour(ExtendedBehaviour... behaviours) { - super(behaviours); - } + public FirstApplicableBehaviour(Pair, Integer>... behaviours) { + super(behaviours); + } + + public FirstApplicableBehaviour(ExtendedBehaviour... behaviours) { + super(behaviours); + } - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour(ServerLevel level, E entity, long gameTime, SBLShufflingList> extendedBehaviours) { - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (behaviour.tryStart(level, entity, gameTime)) - return behaviour; - } + @Nullable + @Override + protected ExtendedBehaviour pickBehaviour( + ServerLevel level, + E entity, + long gameTime, + SBLShufflingList> extendedBehaviours + ) { + for (ExtendedBehaviour behaviour : extendedBehaviours) { + if (behaviour.tryStart(level, entity, gameTime)) + return behaviour; + } - return null; - } + return null; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/GroupBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/GroupBehaviour.java index b0d069c9c..d8003eb0b 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/GroupBehaviour.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/GroupBehaviour.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour; @@ -11,97 +10,112 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.object.SBLShufflingList; import org.jetbrains.annotations.Nullable; import java.util.Iterator; import java.util.List; +import mod.azure.azurelib.sblforked.object.SBLShufflingList; + /** - * Functional replacement to {@link net.minecraft.world.entity.ai.behavior.GateBehavior} due to the very poor way it is implemented.
    + * Functional replacement to {@link net.minecraft.world.entity.ai.behavior.GateBehavior} due to the very poor way it is + * implemented.
    * In particular, this allows nesting of group behaviours without breaking behaviour flow entirely.
    * It also allows for utilising the various callbacks and conditions that {@link ExtendedBehaviour} offers.
    - * NOTE: Only supports ExtendedBehaviour implementations as sub-behaviours. This is due to access-modifiers on the vanilla behaviours making this prohibitively annoying to work with. + * NOTE: Only supports ExtendedBehaviour implementations as sub-behaviours. This is due to access-modifiers on the + * vanilla behaviours making this prohibitively annoying to work with. */ public abstract class GroupBehaviour extends ExtendedBehaviour { - protected final SBLShufflingList> behaviours; - - @Nullable - protected ExtendedBehaviour runningBehaviour = null; - - public GroupBehaviour(Pair, Integer>... behaviours) { - this.behaviours = new SBLShufflingList<>(behaviours); - } - - public GroupBehaviour(ExtendedBehaviour... behaviours) { - this.behaviours = new SBLShufflingList<>(); - - for (ExtendedBehaviour behaviour : behaviours) { - this.behaviours.add(behaviour, 1); - } - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - public Iterator> getBehaviours() { - return this.behaviours.iterator(); - } - - @Nullable - protected abstract ExtendedBehaviour pickBehaviour(ServerLevel level, E entity, long gameTime, SBLShufflingList> behaviours); - - @Override - protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { - if (!super.doStartCheck(level, entity, gameTime)) - return false; - - return (this.runningBehaviour = pickBehaviour(level, entity, gameTime, this.behaviours)) != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.runningBehaviour != null && this.runningBehaviour.canStillUse((ServerLevel)entity.level(), entity, entity.level().getGameTime()); - } - - @Override - protected boolean timedOut(long gameTime) { - return this.runningBehaviour == null || this.runningBehaviour.timedOut(gameTime); - } - - @Override - protected void tick(ServerLevel level, E owner, long gameTime) { - this.runningBehaviour.tickOrStop(level, owner, gameTime); - - if (this.runningBehaviour.getStatus() == Status.STOPPED) { - this.runningBehaviour = null; - - doStop(level, owner, gameTime); - } - } - - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - super.stop(level, entity, gameTime); - - if (this.runningBehaviour != null) - this.runningBehaviour.stop(level, entity, gameTime); - - this.runningBehaviour = null; - } - - @Override - public Status getStatus() { - if (this.runningBehaviour == null) - return Status.STOPPED; - - return this.runningBehaviour.getStatus(); - } - @Override - public String toString() { - return "(" + getClass().getSimpleName() + "): " + (this.runningBehaviour == null ? this.runningBehaviour.getClass().getSimpleName() : "{}"); - } + protected final SBLShufflingList> behaviours; + + @Nullable + protected ExtendedBehaviour runningBehaviour = null; + + public GroupBehaviour(Pair, Integer>... behaviours) { + this.behaviours = new SBLShufflingList<>(behaviours); + } + + public GroupBehaviour(ExtendedBehaviour... behaviours) { + this.behaviours = new SBLShufflingList<>(); + + for (ExtendedBehaviour behaviour : behaviours) { + this.behaviours.add(behaviour, 1); + } + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return List.of(); + } + + public Iterator> getBehaviours() { + return this.behaviours.iterator(); + } + + @Nullable + protected abstract ExtendedBehaviour pickBehaviour( + ServerLevel level, + E entity, + long gameTime, + SBLShufflingList> behaviours + ); + + @Override + protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { + if (!super.doStartCheck(level, entity, gameTime)) + return false; + + return (this.runningBehaviour = pickBehaviour(level, entity, gameTime, this.behaviours)) != null; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return this.runningBehaviour != null && this.runningBehaviour.canStillUse( + (ServerLevel) entity.level(), + entity, + entity.level().getGameTime() + ); + } + + @Override + protected boolean timedOut(long gameTime) { + return this.runningBehaviour == null || this.runningBehaviour.timedOut(gameTime); + } + + @Override + protected void tick(ServerLevel level, E owner, long gameTime) { + this.runningBehaviour.tickOrStop(level, owner, gameTime); + + if (this.runningBehaviour.getStatus() == Status.STOPPED) { + this.runningBehaviour = null; + + doStop(level, owner, gameTime); + } + } + + @Override + protected void stop(ServerLevel level, E entity, long gameTime) { + super.stop(level, entity, gameTime); + + if (this.runningBehaviour != null) + this.runningBehaviour.stop(level, entity, gameTime); + + this.runningBehaviour = null; + } + + @Override + public Status getStatus() { + if (this.runningBehaviour == null) + return Status.STOPPED; + + return this.runningBehaviour.getStatus(); + } + + @Override + public String toString() { + return "(" + getClass().getSimpleName() + "): " + (this.runningBehaviour == null + ? this.runningBehaviour.getClass().getSimpleName() + : "{}"); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/HeldBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/HeldBehaviour.java index eb9d90066..16ef07b02 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/HeldBehaviour.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/HeldBehaviour.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour; @@ -13,53 +12,59 @@ /** * An abstract behaviour used for tasks that should have an ongoing effect, optionally with an early finish.
    - * This is most useful for things like attacks with multi-tick effects such as beams or flamethrowers, or other prolonged actions. + * This is most useful for things like attacks with multi-tick effects such as beams or flamethrowers, or other + * prolonged actions. + * * @param The entity */ public abstract class HeldBehaviour extends ExtendedBehaviour { - protected Function tickConsumer = entity -> true; - protected int runningTime = 0; - public HeldBehaviour() { - runFor(entity -> Integer.MAX_VALUE); - } + protected Function tickConsumer = entity -> true; - /** - * Set the per-tick handler for this held behaviour - * @param tickConsumer The consumer to handle the per-action tick. Return false to end the behaviour, or true to continue running - */ - public HeldBehaviour onTick(Function tickConsumer) { - this.tickConsumer = tickConsumer; + protected int runningTime = 0; - return this; - } + public HeldBehaviour() { + runFor(entity -> Integer.MAX_VALUE); + } - /** - * Gets the amount of ticks this behaviour has been held for - */ - public int getRunningTime() { - return this.runningTime; - } + /** + * Set the per-tick handler for this held behaviour + * + * @param tickConsumer The consumer to handle the per-action tick. Return false to end the behaviour, or true to + * continue running + */ + public HeldBehaviour onTick(Function tickConsumer) { + this.tickConsumer = tickConsumer; - @Override - protected boolean shouldKeepRunning(E entity) { - return true; - } + return this; + } - @Override - protected void start(ServerLevel level, E entity, long gameTime) { - super.start(level, entity, gameTime); + /** + * Gets the amount of ticks this behaviour has been held for + */ + public int getRunningTime() { + return this.runningTime; + } - this.runningTime = 0; - } + @Override + protected boolean shouldKeepRunning(E entity) { + return true; + } - @Override - protected void tick(ServerLevel level, E owner, long gameTime) { - super.tick(level, owner, gameTime); + @Override + protected void start(ServerLevel level, E entity, long gameTime) { + super.start(level, entity, gameTime); - if (!this.tickConsumer.apply(owner)) - doStop(level, owner, gameTime); + this.runningTime = 0; + } - this.runningTime++; - } + @Override + protected void tick(ServerLevel level, E owner, long gameTime) { + super.tick(level, owner, gameTime); + + if (!this.tickConsumer.apply(owner)) + doStop(level, owner, gameTime); + + this.runningTime++; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/OneRandomBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/OneRandomBehaviour.java index 1a94bce7d..f15482c8f 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/OneRandomBehaviour.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/OneRandomBehaviour.java @@ -1,40 +1,47 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour; import com.mojang.datafixers.util.Pair; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; -import mod.azure.azurelib.sblforked.object.SBLShufflingList; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.sblforked.object.SBLShufflingList; + /** * Group behaviour that attempts to run sub-behaviours in a + * * @param The entity */ public final class OneRandomBehaviour extends GroupBehaviour { - public OneRandomBehaviour(Pair, Integer>... behaviours) { - super(behaviours); - } - - public OneRandomBehaviour(ExtendedBehaviour... behaviours) { - super(behaviours); - } - - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour(ServerLevel level, E entity, long gameTime, SBLShufflingList> extendedBehaviours) { - extendedBehaviours.shuffle(); - - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (behaviour.tryStart(level, entity, gameTime)) - return behaviour; - } - - return null; - } -} \ No newline at end of file + + public OneRandomBehaviour(Pair, Integer>... behaviours) { + super(behaviours); + } + + public OneRandomBehaviour(ExtendedBehaviour... behaviours) { + super(behaviours); + } + + @Nullable + @Override + protected ExtendedBehaviour pickBehaviour( + ServerLevel level, + E entity, + long gameTime, + SBLShufflingList> extendedBehaviours + ) { + extendedBehaviours.shuffle(); + + for (ExtendedBehaviour behaviour : extendedBehaviours) { + if (behaviour.tryStart(level, entity, gameTime)) + return behaviour; + } + + return null; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/SequentialBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/SequentialBehaviour.java index b4e901005..c7fabf3fc 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/SequentialBehaviour.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/SequentialBehaviour.java @@ -1,72 +1,80 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour; import com.mojang.datafixers.util.Pair; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; -import mod.azure.azurelib.sblforked.object.SBLShufflingList; import org.jetbrains.annotations.Nullable; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.object.SBLShufflingList; + /** * Group behaviour that runs all child behaviours in order, one after another.
    * Restarts from the first behaviour upon reaching the end of the list + * * @param The entity */ public final class SequentialBehaviour extends GroupBehaviour { - private Predicate> earlyResetPredicate = behaviour -> false; - private ExtendedBehaviour lastRun = null; - public SequentialBehaviour(Pair, Integer>... behaviours) { - super(behaviours); - } + private Predicate> earlyResetPredicate = behaviour -> false; + + private ExtendedBehaviour lastRun = null; + + public SequentialBehaviour(Pair, Integer>... behaviours) { + super(behaviours); + } - public SequentialBehaviour(ExtendedBehaviour... behaviours) { - super(behaviours); - } + public SequentialBehaviour(ExtendedBehaviour... behaviours) { + super(behaviours); + } - /** - * Adds an early short-circuit predicate to reset back to the start of the child behaviours at any time - */ - public SequentialBehaviour resetIf(Predicate> predicate) { - this.earlyResetPredicate = predicate; + /** + * Adds an early short-circuit predicate to reset back to the start of the child behaviours at any time + */ + public SequentialBehaviour resetIf(Predicate> predicate) { + this.earlyResetPredicate = predicate; - return this; - } + return this; + } - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour(ServerLevel level, E entity, long gameTime, SBLShufflingList> extendedBehaviours) { - boolean pickNext = this.lastRun == null; + @Nullable + @Override + protected ExtendedBehaviour pickBehaviour( + ServerLevel level, + E entity, + long gameTime, + SBLShufflingList> extendedBehaviours + ) { + boolean pickNext = this.lastRun == null; - if (this.lastRun != null && this.earlyResetPredicate.test(this.lastRun)) { - pickNext = true; - this.lastRun = null; - } + if (this.lastRun != null && this.earlyResetPredicate.test(this.lastRun)) { + pickNext = true; + this.lastRun = null; + } - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (pickNext) { - if (behaviour.tryStart(level, entity, gameTime)) { - this.lastRun = behaviour; + for (ExtendedBehaviour behaviour : extendedBehaviours) { + if (pickNext) { + if (behaviour.tryStart(level, entity, gameTime)) { + this.lastRun = behaviour; - return behaviour; - } + return behaviour; + } - return null; - } + return null; + } - if (behaviour == this.lastRun) - pickNext = true; - } + if (behaviour == this.lastRun) + pickNext = true; + } - this.lastRun = null; + this.lastRun = null; - return null; - } + return null; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableMeleeAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableMeleeAttack.java index 51c3c9e9e..ecc824a50 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableMeleeAttack.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableMeleeAttack.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; @@ -15,77 +14,89 @@ import net.minecraft.world.entity.ai.behavior.BehaviorUtils; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.Function; +import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Extended behaviour for melee attacking. Natively supports animation hit delays or other delays.
    * Defaults: *
      - *
    • 20 tick attack interval
    • + *
    • 20 tick attack interval
    • *
    + * * @param The entity */ public class AnimatableMeleeAttack extends DelayedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT)); - - protected Function attackIntervalSupplier = entity -> 20; - - @Nullable - protected LivingEntity target = null; - - public AnimatableMeleeAttack(int delayTicks) { - super(delayTicks); - } - - /** - * Set the time between attacks. - * @param supplier The tick value provider - * @return this - */ - public AnimatableMeleeAttack attackInterval(Function supplier) { - this.attackIntervalSupplier = supplier; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.target = BrainUtils.getTargetOfEntity(entity); - - return entity.getSensing().hasLineOfSight(this.target) && entity.isWithinMeleeAttackRange(this.target); - } - - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); - BehaviorUtils.lookAtEntity(entity, this.target); - } - - @Override - protected void stop(E entity) { - this.target = null; - } - - @Override - protected void doDelayedAction(E entity) { - BrainUtils.setForgettableMemory(entity, MemoryModuleType.ATTACK_COOLING_DOWN, true, this.attackIntervalSupplier.apply(entity)); - - if (this.target == null) - return; - - if (!entity.getSensing().hasLineOfSight(this.target) || !entity.isWithinMeleeAttackRange(this.target)) - return; - entity.doHurtTarget(this.target); - } + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), + Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT) + ); + + protected Function attackIntervalSupplier = entity -> 20; + + @Nullable + protected LivingEntity target = null; + + public AnimatableMeleeAttack(int delayTicks) { + super(delayTicks); + } + + /** + * Set the time between attacks. + * + * @param supplier The tick value provider + * @return this + */ + public AnimatableMeleeAttack attackInterval(Function supplier) { + this.attackIntervalSupplier = supplier; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + this.target = BrainUtils.getTargetOfEntity(entity); + + return entity.getSensing().hasLineOfSight(this.target) && entity.isWithinMeleeAttackRange(this.target); + } + + @Override + protected void start(E entity) { + entity.swing(InteractionHand.MAIN_HAND); + BehaviorUtils.lookAtEntity(entity, this.target); + } + + @Override + protected void stop(E entity) { + this.target = null; + } + + @Override + protected void doDelayedAction(E entity) { + BrainUtils.setForgettableMemory( + entity, + MemoryModuleType.ATTACK_COOLING_DOWN, + true, + this.attackIntervalSupplier.apply(entity) + ); + + if (this.target == null) + return; + + if (!entity.getSensing().hasLineOfSight(this.target) || !entity.isWithinMeleeAttackRange(this.target)) + return; + + entity.doHurtTarget(this.target); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableRangedAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableRangedAttack.java index f614123a1..340a5ac28 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableRangedAttack.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableRangedAttack.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; @@ -16,91 +15,106 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.monster.RangedAttackMob; -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.Function; +import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** - * Extended behaviour for ranged attacking. Natively supports animation hit delays or other delays. - * Defaults: + * Extended behaviour for ranged attacking. Natively supports animation hit delays or other delays. Defaults: *
      - *
    • 40-tick firing interval, decreased to 20 ticks when on {@link Difficulty Hard Difficulty}
    • - *
    • 16-block firing radius
    • + *
    • 40-tick firing interval, decreased to 20 ticks when on {@link Difficulty Hard Difficulty}
    • + *
    • 16-block firing radius
    • *
    + * * @param */ public class AnimatableRangedAttack extends DelayedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT)); - - protected Function attackIntervalSupplier = entity -> entity.level().getDifficulty() == Difficulty.HARD ? 20 : 40; - protected float attackRadius; - - @Nullable - protected LivingEntity target = null; - - public AnimatableRangedAttack(int delayTicks) { - super(delayTicks); - - attackRadius(16); - } - - /** - * Set the time between attacks. - * @param supplier The tick value provider - * @return this - */ - public AnimatableRangedAttack attackInterval(Function supplier) { - this.attackIntervalSupplier = supplier; - - return this; - } - - /** - * Set the radius in blocks that the entity should be able to fire on targets. - * @param radius The radius, in blocks - * @return this - */ - public AnimatableRangedAttack attackRadius(float radius) { - this.attackRadius = radius * radius; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.target = BrainUtils.getTargetOfEntity(entity); - - return BrainUtils.canSee(entity, this.target) && entity.distanceToSqr(this.target) <= this.attackRadius; - } - - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); - BehaviorUtils.lookAtEntity(entity, this.target); - } - - @Override - protected void stop(E entity) { - this.target = null; - } - - @Override - protected void doDelayedAction(E entity) { - if (this.target == null) - return; - - if (!BrainUtils.canSee(entity, this.target) || entity.distanceToSqr(this.target) > this.attackRadius) - return; - - entity.performRangedAttack(this.target, 1); - BrainUtils.setForgettableMemory(entity, MemoryModuleType.ATTACK_COOLING_DOWN, true, this.attackIntervalSupplier.apply(entity)); - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), + Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT) + ); + + protected Function attackIntervalSupplier = entity -> entity.level().getDifficulty() == Difficulty.HARD + ? 20 + : 40; + + protected float attackRadius; + + @Nullable + protected LivingEntity target = null; + + public AnimatableRangedAttack(int delayTicks) { + super(delayTicks); + + attackRadius(16); + } + + /** + * Set the time between attacks. + * + * @param supplier The tick value provider + * @return this + */ + public AnimatableRangedAttack attackInterval(Function supplier) { + this.attackIntervalSupplier = supplier; + + return this; + } + + /** + * Set the radius in blocks that the entity should be able to fire on targets. + * + * @param radius The radius, in blocks + * @return this + */ + public AnimatableRangedAttack attackRadius(float radius) { + this.attackRadius = radius * radius; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + this.target = BrainUtils.getTargetOfEntity(entity); + + return BrainUtils.canSee(entity, this.target) && entity.distanceToSqr(this.target) <= this.attackRadius; + } + + @Override + protected void start(E entity) { + entity.swing(InteractionHand.MAIN_HAND); + BehaviorUtils.lookAtEntity(entity, this.target); + } + + @Override + protected void stop(E entity) { + this.target = null; + } + + @Override + protected void doDelayedAction(E entity) { + if (this.target == null) + return; + + if (!BrainUtils.canSee(entity, this.target) || entity.distanceToSqr(this.target) > this.attackRadius) + return; + + entity.performRangedAttack(this.target, 1); + BrainUtils.setForgettableMemory( + entity, + MemoryModuleType.ATTACK_COOLING_DOWN, + true, + this.attackIntervalSupplier.apply(entity) + ); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/BowAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/BowAttack.java index 376811667..9aec7a803 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/BowAttack.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/BowAttack.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; @@ -13,35 +12,41 @@ import net.minecraft.world.entity.projectile.ProjectileUtil; import net.minecraft.world.item.BowItem; import net.minecraft.world.item.Items; + import mod.azure.azurelib.sblforked.util.BrainUtils; /** - * Extended behaviour for charging and firing a - * {@link BowItem bow}. - * + * Extended behaviour for charging and firing a {@link BowItem bow}. + * * @param */ public class BowAttack extends AnimatableRangedAttack { - public BowAttack(int delayTicks) { - super(delayTicks); - } - - @Override - protected void start(E entity) { - BehaviorUtils.lookAtEntity(entity, this.target); - entity.startUsingItem(ProjectileUtil.getWeaponHoldingHand(entity, Items.BOW)); - } - - @Override - protected void doDelayedAction(E entity) { - if (this.target == null) - return; - - if (!BrainUtils.canSee(entity, this.target) || entity.distanceToSqr(this.target) > this.attackRadius) - return; - - entity.performRangedAttack(this.target, BowItem.getPowerForTime(entity.getTicksUsingItem())); - entity.stopUsingItem(); - BrainUtils.setForgettableMemory(entity, MemoryModuleType.ATTACK_COOLING_DOWN, true, this.attackIntervalSupplier.apply(entity)); - } + + public BowAttack(int delayTicks) { + super(delayTicks); + } + + @Override + protected void start(E entity) { + BehaviorUtils.lookAtEntity(entity, this.target); + entity.startUsingItem(ProjectileUtil.getWeaponHoldingHand(entity, Items.BOW)); + } + + @Override + protected void doDelayedAction(E entity) { + if (this.target == null) + return; + + if (!BrainUtils.canSee(entity, this.target) || entity.distanceToSqr(this.target) > this.attackRadius) + return; + + entity.performRangedAttack(this.target, BowItem.getPowerForTime(entity.getTicksUsingItem())); + entity.stopUsingItem(); + BrainUtils.setForgettableMemory( + entity, + MemoryModuleType.ATTACK_COOLING_DOWN, + true, + this.attackIntervalSupplier.apply(entity) + ); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessAttack.java index 9142d83f6..e24c395f8 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessAttack.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessAttack.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; @@ -14,9 +13,6 @@ import net.minecraft.world.entity.ai.behavior.BehaviorUtils; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -24,86 +20,105 @@ import java.util.function.Function; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** - * Attack behaviour that doesn't require line of sight or proximity to target, or to even have a target at all. This is useful for special attacks.
    + * Attack behaviour that doesn't require line of sight or proximity to target, or to even have a target at all. This is + * useful for special attacks.
    * Set the actual condition for activation via {@link ExtendedBehaviour#startCondition(Predicate)} + * * @param The entity */ public class ConditionlessAttack extends DelayedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT)); - - protected Function attackIntervalSupplier = entity -> 20; - protected boolean requireTarget = false; - protected Consumer effect = entity -> {}; - - @Nullable - protected LivingEntity target = null; - - public ConditionlessAttack(int delayTicks) { - super(delayTicks); - } - - /** - * Set the time between attacks. - * @param supplier The tick value provider - * @return this - */ - public ConditionlessAttack attackInterval(Function supplier) { - this.attackIntervalSupplier = supplier; - - return this; - } - - /** - * Set that the attack requires that the entity have an attack target set to activate. - * @return this - */ - public ConditionlessAttack requiresTarget() { - this.requireTarget = true; - - return this; - } - - /** - * Set the callback for the actual attack when the delay time has elapsed - * @param consumer The callback - * @return this - */ - public ConditionlessAttack attack(Consumer consumer) { - this.effect = consumer; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!this.requireTarget) - return true; - - this.target = BrainUtils.getTargetOfEntity(entity); - - return this.target != null; - } - - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); - - if (this.requireTarget) - BehaviorUtils.lookAtEntity(entity, this.target); - } - - @Override - protected void doDelayedAction(E entity) { - if (this.requireTarget && this.target == null) - return; - - this.effect.accept(entity); - BrainUtils.setForgettableMemory(entity, MemoryModuleType.ATTACK_COOLING_DOWN, true, this.attackIntervalSupplier.apply(entity)); - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT) + ); + + protected Function attackIntervalSupplier = entity -> 20; + + protected boolean requireTarget = false; + + protected Consumer effect = entity -> {}; + + @Nullable + protected LivingEntity target = null; + + public ConditionlessAttack(int delayTicks) { + super(delayTicks); + } + + /** + * Set the time between attacks. + * + * @param supplier The tick value provider + * @return this + */ + public ConditionlessAttack attackInterval(Function supplier) { + this.attackIntervalSupplier = supplier; + + return this; + } + + /** + * Set that the attack requires that the entity have an attack target set to activate. + * + * @return this + */ + public ConditionlessAttack requiresTarget() { + this.requireTarget = true; + + return this; + } + + /** + * Set the callback for the actual attack when the delay time has elapsed + * + * @param consumer The callback + * @return this + */ + public ConditionlessAttack attack(Consumer consumer) { + this.effect = consumer; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + if (!this.requireTarget) + return true; + + this.target = BrainUtils.getTargetOfEntity(entity); + + return this.target != null; + } + + @Override + protected void start(E entity) { + entity.swing(InteractionHand.MAIN_HAND); + + if (this.requireTarget) + BehaviorUtils.lookAtEntity(entity, this.target); + } + + @Override + protected void doDelayedAction(E entity) { + if (this.requireTarget && this.target == null) + return; + + this.effect.accept(entity); + BrainUtils.setForgettableMemory( + entity, + MemoryModuleType.ATTACK_COOLING_DOWN, + true, + this.attackIntervalSupplier.apply(entity) + ); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessHeldAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessHeldAttack.java index b0bb1b2b5..e091eeec8 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessHeldAttack.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessHeldAttack.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; @@ -14,63 +13,71 @@ import net.minecraft.world.entity.ai.behavior.BehaviorUtils; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.HeldBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; +import mod.azure.azurelib.sblforked.api.core.behaviour.HeldBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** - * Attack behaviour for held attacks that doesn't require line of sight or proximity to target, or to even have a target at all. - * This is useful for special attacks.
    - * Set the actual condition for activation via {@link mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour#startCondition ExtendedBehaviour.startCondition} + * Attack behaviour for held attacks that doesn't require line of sight or proximity to target, or to even have a target + * at all. This is useful for special attacks.
    + * Set the actual condition for activation via + * {@link mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour#startCondition + * ExtendedBehaviour.startCondition} + * * @param The entity */ public class ConditionlessHeldAttack extends HeldBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT)); - protected boolean requireTarget = false; + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT) + ); + + protected boolean requireTarget = false; - @Nullable - protected LivingEntity target = null; + @Nullable + protected LivingEntity target = null; - /** - * Set that the attack requires that the entity have an attack target set to activate. - * @return this - */ - public ConditionlessHeldAttack requiresTarget() { - this.requireTarget = true; + /** + * Set that the attack requires that the entity have an attack target set to activate. + * + * @return this + */ + public ConditionlessHeldAttack requiresTarget() { + this.requireTarget = true; - return this; - } + return this; + } - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!this.requireTarget) - return true; + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + if (!this.requireTarget) + return true; - this.target = BrainUtils.getTargetOfEntity(entity); + this.target = BrainUtils.getTargetOfEntity(entity); - return this.target != null; - } + return this.target != null; + } - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); + @Override + protected void start(E entity) { + entity.swing(InteractionHand.MAIN_HAND); - if (this.requireTarget) - BehaviorUtils.lookAtEntity(entity, this.target); - } + if (this.requireTarget) + BehaviorUtils.lookAtEntity(entity, this.target); + } - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - super.stop(level, entity, gameTime); + @Override + protected void stop(ServerLevel level, E entity, long gameTime) { + super.stop(level, entity, gameTime); - this.target = null; - } + this.target = null; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtAttackTarget.java index e5cbd6f3f..0f67ce298 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtAttackTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtAttackTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.look; @@ -13,40 +12,51 @@ import net.minecraft.world.entity.ai.behavior.EntityTracker; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** - * Set the {@link MemoryModuleType#LOOK_TARGET} of the brain owner to the current {@link MemoryModuleType#ATTACK_TARGET}, replacing the existing look target.
    - * This is mostly superceded by {@link mod.azure.azurelib.sblforked.api.core.behaviour.custom.path.SetWalkTargetToAttackTarget SetWalkTargetToAttackTarget}, but can be useful if you want the brain owner to look at the target without pathing to it + * Set the {@link MemoryModuleType#LOOK_TARGET} of the brain owner to the current + * {@link MemoryModuleType#ATTACK_TARGET}, replacing the existing look target.
    + * This is mostly superceded by + * {@link mod.azure.azurelib.sblforked.api.core.behaviour.custom.path.SetWalkTargetToAttackTarget + * SetWalkTargetToAttackTarget}, but can be useful if you want the brain owner to look at the target without pathing to + * it + * * @param The entity */ public class LookAtAttackTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED)); - private LivingEntity target = null; + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), + Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED) + ); + + private LivingEntity target = null; - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.target = BrainUtils.getTargetOfEntity(entity); + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + this.target = BrainUtils.getTargetOfEntity(entity); - return !(BrainUtils.getMemory(entity, MemoryModuleType.LOOK_TARGET) instanceof EntityTracker entityTracker) || entityTracker.getEntity() != this.target; - } + return !(BrainUtils.getMemory(entity, MemoryModuleType.LOOK_TARGET) instanceof EntityTracker entityTracker) + || entityTracker.getEntity() != this.target; + } - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(this.target, true)); - } + @Override + protected void start(E entity) { + BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(this.target, true)); + } - @Override - protected void stop(E entity) { - this.target = null; - } + @Override + protected void stop(E entity) { + this.target = null; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtTarget.java index 0cb302d98..23b9e90c3 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.look; @@ -11,34 +10,43 @@ import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Look at the look target for as long as it is present + * * @param The entity */ public class LookAtTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_PRESENT)); - - public LookAtTarget() { - noTimeout(); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.LOOK_TARGET); - } - - @Override - protected void tick(E entity) { - BrainUtils.withMemory(entity, MemoryModuleType.LOOK_TARGET, target -> entity.getLookControl().setLookAt(target.currentPosition())); - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_PRESENT) + ); + + public LookAtTarget() { + noTimeout(); + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return BrainUtils.hasMemory(entity, MemoryModuleType.LOOK_TARGET); + } + + @Override + protected void tick(E entity) { + BrainUtils.withMemory( + entity, + MemoryModuleType.LOOK_TARGET, + target -> entity.getLookControl().setLookAt(target.currentPosition()) + ); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/AvoidSun.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/AvoidSun.java index 857192957..4be6e7ff3 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/AvoidSun.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/AvoidSun.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -13,32 +12,37 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; import java.util.List; -/** Avoid the sun if not wearing a hat +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; + +/** + * Avoid the sun if not wearing a hat + * * @param The entity */ public class AvoidSun extends ExtendedBehaviour { - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return level.isDay() && entity.getItemBySlot(EquipmentSlot.HEAD).isEmpty() && entity.getNavigation() instanceof GroundPathNavigation; - } - - @Override - protected void start(E entity) { - ((GroundPathNavigation)entity.getNavigation()).setAvoidSun(true); - } - - @Override - protected void stop(E entity) { - if (entity.getNavigation() instanceof GroundPathNavigation groundNavigation) - groundNavigation.setAvoidSun(true); - } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return List.of(); + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + return level.isDay() && entity.getItemBySlot(EquipmentSlot.HEAD).isEmpty() && entity + .getNavigation() instanceof GroundPathNavigation; + } + + @Override + protected void start(E entity) { + ((GroundPathNavigation) entity.getNavigation()).setAvoidSun(true); + } + + @Override + protected void stop(E entity) { + if (entity.getNavigation() instanceof GroundPathNavigation groundNavigation) + groundNavigation.setAvoidSun(true); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BlockWithShield.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BlockWithShield.java index ad088c304..cdb4b3ef2 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BlockWithShield.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BlockWithShield.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -13,72 +12,74 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.item.UseAnim; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; import java.util.List; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; + /** * Makes the entity use (block) using a shield if it's currently in the entity's hands */ public class BlockWithShield extends ExtendedBehaviour { - protected InteractionHand hand = InteractionHand.MAIN_HAND; - - protected Predicate stopCondition = entity -> false; - - /** - * Sets the condition for when the entity should stop blocking.
    - * Deprecated, use {@link ExtendedBehaviour#stopIf} - * @param predicate The predicate - * @return this - */ - @Deprecated(forRemoval = true) - public BlockWithShield stopWhen(Predicate predicate) { - this.stopCondition = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (entity.getMainHandItem().getUseAnimation() == UseAnim.BLOCK) { - this.hand = InteractionHand.MAIN_HAND; - - return true; - } - else if (entity.getOffhandItem().getUseAnimation() == UseAnim.BLOCK) { - this.hand = InteractionHand.OFF_HAND; - - return true; - } - - return false; - } - - @Override - protected void start(E entity) { - entity.startUsingItem(this.hand); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - if (!entity.isUsingItem()) - return false; - - if (!(entity.getUseItem().getUseAnimation() == UseAnim.BLOCK)) - return false; - - return !this.stopCondition.test(entity); - } - - @Override - protected void stop(E entity) { - if (entity.getUseItem().getUseAnimation() == UseAnim.BLOCK) - entity.stopUsingItem(); - } -} \ No newline at end of file + + protected InteractionHand hand = InteractionHand.MAIN_HAND; + + protected Predicate stopCondition = entity -> false; + + /** + * Sets the condition for when the entity should stop blocking.
    + * Deprecated, use {@link ExtendedBehaviour#stopIf} + * + * @param predicate The predicate + * @return this + */ + @Deprecated(forRemoval = true) + public BlockWithShield stopWhen(Predicate predicate) { + this.stopCondition = predicate; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return List.of(); + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + if (entity.getMainHandItem().getUseAnimation() == UseAnim.BLOCK) { + this.hand = InteractionHand.MAIN_HAND; + + return true; + } else if (entity.getOffhandItem().getUseAnimation() == UseAnim.BLOCK) { + this.hand = InteractionHand.OFF_HAND; + + return true; + } + + return false; + } + + @Override + protected void start(E entity) { + entity.startUsingItem(this.hand); + } + + @Override + protected boolean shouldKeepRunning(E entity) { + if (!entity.isUsingItem()) + return false; + + if (!(entity.getUseItem().getUseAnimation() == UseAnim.BLOCK)) + return false; + + return !this.stopCondition.test(entity); + } + + @Override + protected void stop(E entity) { + if (entity.getUseItem().getUseAnimation() == UseAnim.BLOCK) + entity.stopUsingItem(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreakBlock.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreakBlock.java index 54845b881..1776c6218 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreakBlock.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreakBlock.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -17,126 +16,150 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.LevelEvent; import net.minecraft.world.level.block.state.BlockState; +import org.apache.commons.lang3.function.TriFunction; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; import mod.azure.azurelib.sblforked.object.TriPredicate; import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.apache.commons.lang3.function.TriFunction; - -import java.util.List; /** * Gradually breaks then destroys a block.
    * Finds blocks based on the {@link SBLMemoryTypes#NEARBY_BLOCKS} memory module.
    * Defaults: *
      - *
    • Breaks doors
    • - *
    • Takes 240 ticks to break the block
    • + *
    • Breaks doors
    • + *
    • Takes 240 ticks to break the block
    • *
    */ public class BreakBlock extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(SBLMemoryTypes.NEARBY_BLOCKS.get(), MemoryStatus.VALUE_PRESENT)); - - protected TriPredicate targetBlockPredicate = (entity, pos, state) -> state.is(BlockTags.DOORS); - protected TriPredicate stopPredicate = (entity, pos, state) -> false; - protected TriFunction digTimePredicate = (entity, pos, state) -> 240; - - protected BlockPos pos = null; - protected BlockState state = null; - protected int timeToBreak = 0; - protected int breakTime = 0; - protected int breakProgress = -1; - - /** - * Set the condition for when the entity should stop breaking the block. - * @param predicate The predicate - * @return this - */ - public BreakBlock stopBreakingIf(TriPredicate predicate) { - this.stopPredicate = predicate; - - return this; - } - - /** - * Sets the predicate for valid blocks to break. - * @param predicate The predicate - * @return this - */ - public BreakBlock forBlocks(TriPredicate predicate) { - this.targetBlockPredicate = predicate; - - return this; - } - - /** - * Determines the amount of time (in ticks) it takes to break the given block. - * @param function The function - * @return this - */ - public BreakBlock timeToBreak(TriFunction function) { - this.digTimePredicate = function; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean timedOut(long gameTime) { - return this.breakProgress < 0 && super.timedOut(gameTime); - } - - @Override - protected void stop(E entity) { - entity.level().destroyBlockProgress(entity.getId(), this.pos, -1); - - this.state = null; - this.pos = null; - this.timeToBreak = 0; - this.breakTime = 0; - this.breakProgress = -1; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - for (Pair pair : BrainUtils.getMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get())) { - if (this.targetBlockPredicate.test(entity, pair.getFirst(), pair.getSecond())) { - this.pos = pair.getFirst(); - this.state = pair.getSecond(); - this.timeToBreak = this.digTimePredicate.apply(entity, this.pos, this.state); - - return true; - } - } - - return false; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.breakTime <= this.timeToBreak && this.targetBlockPredicate.test(entity, this.pos, entity.level().getBlockState(this.pos)) && !this.stopPredicate.test(entity, this.pos, this.state); - } - - @Override - protected void tick(E entity) { - this.breakTime++; - int progress = (int)(this.breakTime / (float)this.timeToBreak * 10); - - if (progress != this.breakProgress) { - entity.level().destroyBlockProgress(entity.getId(), this.pos, progress); - - this.breakProgress = progress; - } - - if (this.breakTime >= this.timeToBreak) { - entity.level().removeBlock(this.pos, false); - entity.level().levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, this.pos, Block.getId(entity.level().getBlockState(this.pos))); - - doStop((ServerLevel)entity.level(), entity, entity.level().getGameTime()); - } - } -} \ No newline at end of file + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(SBLMemoryTypes.NEARBY_BLOCKS.get(), MemoryStatus.VALUE_PRESENT) + ); + + protected TriPredicate targetBlockPredicate = (entity, pos, state) -> state.is( + BlockTags.DOORS + ); + + protected TriPredicate stopPredicate = (entity, pos, state) -> false; + + protected TriFunction digTimePredicate = (entity, pos, state) -> 240; + + protected BlockPos pos = null; + + protected BlockState state = null; + + protected int timeToBreak = 0; + + protected int breakTime = 0; + + protected int breakProgress = -1; + + /** + * Set the condition for when the entity should stop breaking the block. + * + * @param predicate The predicate + * @return this + */ + public BreakBlock stopBreakingIf(TriPredicate predicate) { + this.stopPredicate = predicate; + + return this; + } + + /** + * Sets the predicate for valid blocks to break. + * + * @param predicate The predicate + * @return this + */ + public BreakBlock forBlocks(TriPredicate predicate) { + this.targetBlockPredicate = predicate; + + return this; + } + + /** + * Determines the amount of time (in ticks) it takes to break the given block. + * + * @param function The function + * @return this + */ + public BreakBlock timeToBreak(TriFunction function) { + this.digTimePredicate = function; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + @Override + protected boolean timedOut(long gameTime) { + return this.breakProgress < 0 && super.timedOut(gameTime); + } + + @Override + protected void stop(E entity) { + entity.level().destroyBlockProgress(entity.getId(), this.pos, -1); + + this.state = null; + this.pos = null; + this.timeToBreak = 0; + this.breakTime = 0; + this.breakProgress = -1; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + for (Pair pair : BrainUtils.getMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get())) { + if (this.targetBlockPredicate.test(entity, pair.getFirst(), pair.getSecond())) { + this.pos = pair.getFirst(); + this.state = pair.getSecond(); + this.timeToBreak = this.digTimePredicate.apply(entity, this.pos, this.state); + + return true; + } + } + + return false; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return this.breakTime <= this.timeToBreak && this.targetBlockPredicate.test( + entity, + this.pos, + entity.level().getBlockState(this.pos) + ) && !this.stopPredicate.test(entity, this.pos, this.state); + } + + @Override + protected void tick(E entity) { + this.breakTime++; + int progress = (int) (this.breakTime / (float) this.timeToBreak * 10); + + if (progress != this.breakProgress) { + entity.level().destroyBlockProgress(entity.getId(), this.pos, progress); + + this.breakProgress = progress; + } + + if (this.breakTime >= this.timeToBreak) { + entity.level().removeBlock(this.pos, false); + entity.level() + .levelEvent( + LevelEvent.PARTICLES_DESTROY_BLOCK, + this.pos, + Block.getId(entity.level().getBlockState(this.pos)) + ); + + doStop((ServerLevel) entity.level(), entity, entity.level().getGameTime()); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreedWithPartner.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreedWithPartner.java index 2d1b8a2e0..dd0920e6c 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreedWithPartner.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreedWithPartner.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -13,8 +12,6 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.animal.Animal; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -22,105 +19,151 @@ import java.util.function.BiPredicate; import java.util.function.ToIntBiFunction; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Functional replacement for vanilla's {@link net.minecraft.world.entity.ai.behavior.AnimalMakeLove AnimalMakeLove}. - *

    Makes the entity find, move to, and breed with its target mate, producing offspring.

    + *

    + * Makes the entity find, move to, and breed with its target mate, producing offspring. + *

    * Defaults: *
      - *
    • 1x walk speed modifier when moving to its breeding partner
    • - *
    • Spend between 3 and 5.5 seconds to create the offspring
    • + *
    • 1x walk speed modifier when moving to its breeding partner
    • + *
    • Spend between 3 and 5.5 seconds to create the offspring
    • *
    */ public class BreedWithPartner extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.BREED_TARGET, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT)); - - protected BiFunction speedMod = (entity, partner) -> 1f; - protected ToIntBiFunction closeEnoughDist = (entity, partner) -> 2; - protected BiFunction breedTime = (entity, partner) -> entity.getRandom().nextInt(60, 110); - protected BiPredicate partnerPredicate = (entity, partner) -> entity.getType() == partner.getType() && entity.canMate(partner); - - protected int childBreedTick = -1; - protected Animal partner = null; - - public BreedWithPartner() { - runFor(entity -> Integer.MAX_VALUE); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the movespeed modifier for the entity when moving to their partner. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public BreedWithPartner speedMod(final BiFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Sets the amount (in blocks) that the animal can be considered 'close enough' to their partner that they can stop pathfinding - * @param closeEnoughDist The distance function - * @return this - */ - public BreedWithPartner closeEnoughDist(final ToIntBiFunction closeEnoughDist) { - this.closeEnoughDist = closeEnoughDist; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!entity.isInLove()) - return false; - - this.partner = findPartner(entity); - - return this.partner != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.partner != null && this.partner.isAlive() && entity.tickCount <= this.childBreedTick && BehaviorUtils.entityIsVisible(entity.getBrain(), this.partner) && this.partnerPredicate.test(entity, this.partner); - } - - @Override - protected void start(E entity) { - this.childBreedTick = entity.tickCount + this.breedTime.apply(entity, this.partner); - - BrainUtils.setMemory(entity, MemoryModuleType.BREED_TARGET, this.partner); - BrainUtils.setMemory(this.partner, MemoryModuleType.BREED_TARGET, entity); - BehaviorUtils.lockGazeAndWalkToEachOther(entity, this.partner, this.speedMod.apply(entity, this.partner), this.closeEnoughDist.applyAsInt(entity, this.partner)); - } - - @Override - protected void tick(E entity) { - BehaviorUtils.lockGazeAndWalkToEachOther(entity, this.partner, this.speedMod.apply(entity, this.partner), this.closeEnoughDist.applyAsInt(entity, this.partner)); - - if (entity.closerThan(this.partner, 3) && entity.tickCount == this.childBreedTick) { - entity.spawnChildFromBreeding((ServerLevel)entity.level(), this.partner); - BrainUtils.clearMemory(entity, MemoryModuleType.BREED_TARGET); - BrainUtils.clearMemory(this.partner, MemoryModuleType.BREED_TARGET); - } - } - - @Override - protected void stop(E entity) { - BrainUtils.clearMemories(entity, MemoryModuleType.BREED_TARGET, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET); - - if (this.partner != null) - BrainUtils.clearMemories(this.partner, MemoryModuleType.BREED_TARGET, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET); - - this.childBreedTick = -1; - this.partner = null; - } - - @Nullable - protected Animal findPartner(E entity) { - return BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).findClosest(entity2 -> entity2 instanceof Animal partner && this.partnerPredicate.test(entity, partner)).map(Animal.class::cast).orElse(null); - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.BREED_TARGET, MemoryStatus.VALUE_ABSENT), + Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT) + ); + + protected BiFunction speedMod = (entity, partner) -> 1f; + + protected ToIntBiFunction closeEnoughDist = (entity, partner) -> 2; + + protected BiFunction breedTime = (entity, partner) -> entity.getRandom().nextInt(60, 110); + + protected BiPredicate partnerPredicate = (entity, partner) -> entity.getType() == partner.getType() + && entity.canMate(partner); + + protected int childBreedTick = -1; + + protected Animal partner = null; + + public BreedWithPartner() { + runFor(entity -> Integer.MAX_VALUE); + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + /** + * Set the movespeed modifier for the entity when moving to their partner. + * + * @param speedModifier The movespeed modifier/multiplier + * @return this + */ + public BreedWithPartner speedMod(final BiFunction speedModifier) { + this.speedMod = speedModifier; + + return this; + } + + /** + * Sets the amount (in blocks) that the animal can be considered 'close enough' to their partner that they can stop + * pathfinding + * + * @param closeEnoughDist The distance function + * @return this + */ + public BreedWithPartner closeEnoughDist(final ToIntBiFunction closeEnoughDist) { + this.closeEnoughDist = closeEnoughDist; + + return this; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + if (!entity.isInLove()) + return false; + + this.partner = findPartner(entity); + + return this.partner != null; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return this.partner != null && this.partner.isAlive() && entity.tickCount <= this.childBreedTick + && BehaviorUtils.entityIsVisible(entity.getBrain(), this.partner) && this.partnerPredicate.test( + entity, + this.partner + ); + } + + @Override + protected void start(E entity) { + this.childBreedTick = entity.tickCount + this.breedTime.apply(entity, this.partner); + + BrainUtils.setMemory(entity, MemoryModuleType.BREED_TARGET, this.partner); + BrainUtils.setMemory(this.partner, MemoryModuleType.BREED_TARGET, entity); + BehaviorUtils.lockGazeAndWalkToEachOther( + entity, + this.partner, + this.speedMod.apply(entity, this.partner), + this.closeEnoughDist.applyAsInt(entity, this.partner) + ); + } + + @Override + protected void tick(E entity) { + BehaviorUtils.lockGazeAndWalkToEachOther( + entity, + this.partner, + this.speedMod.apply(entity, this.partner), + this.closeEnoughDist.applyAsInt(entity, this.partner) + ); + + if (entity.closerThan(this.partner, 3) && entity.tickCount == this.childBreedTick) { + entity.spawnChildFromBreeding((ServerLevel) entity.level(), this.partner); + BrainUtils.clearMemory(entity, MemoryModuleType.BREED_TARGET); + BrainUtils.clearMemory(this.partner, MemoryModuleType.BREED_TARGET); + } + } + + @Override + protected void stop(E entity) { + BrainUtils.clearMemories( + entity, + MemoryModuleType.BREED_TARGET, + MemoryModuleType.LOOK_TARGET, + MemoryModuleType.WALK_TARGET + ); + + if (this.partner != null) + BrainUtils.clearMemories( + this.partner, + MemoryModuleType.BREED_TARGET, + MemoryModuleType.LOOK_TARGET, + MemoryModuleType.WALK_TARGET + ); + + this.childBreedTick = -1; + this.partner = null; + } + + @Nullable + protected Animal findPartner(E entity) { + return BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES) + .findClosest(entity2 -> entity2 instanceof Animal partner && this.partnerPredicate.test(entity, partner)) + .map(Animal.class::cast) + .orElse(null); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomBehaviour.java index 990f563fa..163ff75f4 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomBehaviour.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomBehaviour.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -10,41 +9,45 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; + /** * A behaviour module that invokes a callback.
    - * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth implementing into a full behaviour.
    + * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth + * implementing into a full behaviour.
    * Set the condition for running via {@link ExtendedBehaviour#startCondition(Predicate)} */ public final class CustomBehaviour extends ExtendedBehaviour { - private Consumer callback; - - public CustomBehaviour(Consumer callback) { - this.callback = callback; - } - - /** - * Replace the callback function - * @return this - */ - public CustomBehaviour callback(Consumer callback) { - this.callback = callback; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected void start(E entity) { - this.callback.accept(entity); - } + + private Consumer callback; + + public CustomBehaviour(Consumer callback) { + this.callback = callback; + } + + /** + * Replace the callback function + * + * @return this + */ + public CustomBehaviour callback(Consumer callback) { + this.callback = callback; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return List.of(); + } + + @Override + protected void start(E entity) { + this.callback.accept(entity); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomDelayedBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomDelayedBehaviour.java index 37f63be4d..9e4313394 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomDelayedBehaviour.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomDelayedBehaviour.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -10,24 +9,27 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; import java.util.List; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; + /** * A behaviour module that acts as a default implementation of {@link DelayedBehaviour}.
    - * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth implementing into a full behaviour.
    + * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth + * implementing into a full behaviour.
    * Set the condition for running via {@link ExtendedBehaviour#startCondition(Predicate)} */ public final class CustomDelayedBehaviour extends DelayedBehaviour { - public CustomDelayedBehaviour(int delayTicks) { - super(delayTicks); - } - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } + public CustomDelayedBehaviour(int delayTicks) { + super(delayTicks); + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return List.of(); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomHeldBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomHeldBehaviour.java index 7415e0584..ec506a28c 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomHeldBehaviour.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomHeldBehaviour.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -10,43 +9,47 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.api.core.behaviour.HeldBehaviour; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.api.core.behaviour.HeldBehaviour; + /** * A behaviour module that invokes a callback every tick until stopped.
    - * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth implementing into a full behaviour.
    + * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth + * implementing into a full behaviour.
    * Set the condition for running via {@link ExtendedBehaviour#startCondition(Predicate)}
    * Set the condition for stopping via {@link ExtendedBehaviour#stopIf(Predicate)} */ public final class CustomHeldBehaviour extends HeldBehaviour { - private Consumer callback; - - public CustomHeldBehaviour(Consumer callback) { - this.callback = callback; - } - - /** - * Replace the callback function - * @return this - */ - public CustomHeldBehaviour callback(Consumer callback) { - this.callback = callback; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected void tick(E entity) { - this.callback.accept(entity); - } + + private Consumer callback; + + public CustomHeldBehaviour(Consumer callback) { + this.callback = callback; + } + + /** + * Replace the callback function + * + * @return this + */ + public CustomHeldBehaviour callback(Consumer callback) { + this.callback = callback; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return List.of(); + } + + @Override + protected void tick(E entity) { + this.callback.accept(entity); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/HoldItem.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/HoldItem.java index 0ce689eff..0d1fca49f 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/HoldItem.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/HoldItem.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -12,80 +11,89 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.item.ItemStack; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; import java.util.List; import java.util.function.BiPredicate; import java.util.function.Function; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; + /** * Equips the entity with an item in its {@link InteractionHand hand}.
    * Can be set to an {@link ItemStack#EMPTY empty ItemStack} to act as unequipping.
    * Defaults: *
      - *
    • Equips to the main hand
    • - *
    • Deletes the item it was holding prior to equipping the new item
    • + *
    • Equips to the main hand
    • + *
    • Deletes the item it was holding prior to equipping the new item
    • *
    */ public class HoldItem extends ExtendedBehaviour { - protected Function stackFunction = entity -> ItemStack.EMPTY; - protected Function handDecider = entity -> InteractionHand.MAIN_HAND; - protected BiPredicate dropItemOnUnequip = (entity, stack) -> false; - - /** - * Sets the function to determine which hand to equip the item in. - * @param function The function - * @return this - */ - public HoldItem toHand(Function function) { - this.handDecider = function; - - return this; - } - - /** - * Sets the function to determine the item to equip. - * @param function The itemstack function - * @return this - */ - public HoldItem withStack(Function function) { - this.stackFunction = function; - - return this; - } - - /** - * Sets the behaviour to drop the previously equipped item when equipping the new item. - * @return this - */ - public HoldItem dropItemOnUnequip() { - return dropItemOnUnequip((entity, stack) -> true); - } - - /** - * Sets the predicate to determine whether the entity should drop the previously equipped item when equipping the new item. - * @param dropPredicate The predicate - * @return this - */ - public HoldItem dropItemOnUnequip(BiPredicate dropPredicate) { - this.dropItemOnUnequip = dropPredicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected void start(E entity) { - InteractionHand hand = this.handDecider.apply(entity); - ItemStack previousStack = entity.getItemInHand(hand); - - if (this.dropItemOnUnequip.test(entity, previousStack)) - entity.spawnAtLocation(previousStack); - - entity.setItemInHand(hand, this.stackFunction.apply(entity)); - } -} \ No newline at end of file + + protected Function stackFunction = entity -> ItemStack.EMPTY; + + protected Function handDecider = entity -> InteractionHand.MAIN_HAND; + + protected BiPredicate dropItemOnUnequip = (entity, stack) -> false; + + /** + * Sets the function to determine which hand to equip the item in. + * + * @param function The function + * @return this + */ + public HoldItem toHand(Function function) { + this.handDecider = function; + + return this; + } + + /** + * Sets the function to determine the item to equip. + * + * @param function The itemstack function + * @return this + */ + public HoldItem withStack(Function function) { + this.stackFunction = function; + + return this; + } + + /** + * Sets the behaviour to drop the previously equipped item when equipping the new item. + * + * @return this + */ + public HoldItem dropItemOnUnequip() { + return dropItemOnUnequip((entity, stack) -> true); + } + + /** + * Sets the predicate to determine whether the entity should drop the previously equipped item when equipping the + * new item. + * + * @param dropPredicate The predicate + * @return this + */ + public HoldItem dropItemOnUnequip(BiPredicate dropPredicate) { + this.dropItemOnUnequip = dropPredicate; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return List.of(); + } + + @Override + protected void start(E entity) { + InteractionHand hand = this.handDecider.apply(entity); + ItemStack previousStack = entity.getItemInHand(hand); + + if (this.dropItemOnUnequip.test(entity, previousStack)) + entity.spawnAtLocation(previousStack); + + entity.setItemInHand(hand, this.stackFunction.apply(entity)); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Idle.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Idle.java index c30f1e035..588bc338c 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Idle.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Idle.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -10,22 +9,25 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; import java.util.List; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; + /** * Do nothing at all. + * * @param The entity */ public class Idle extends ExtendedBehaviour { - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return true; - } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return List.of(); + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return true; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/InvalidateMemory.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/InvalidateMemory.java index 5dec830a6..8f0ae1ed4 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/InvalidateMemory.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/InvalidateMemory.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -10,62 +9,67 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Custom behaviour for conditionally invalidating/resetting existing memories.
    * This allows for custom handling of stored memories, and clearing them at will.
    *
    - * Invalidates the memory unconditionally once the behaviour runs. Use {@link InvalidateMemory#invalidateIf} and {@link ExtendedBehaviour#startCondition} to quantify its operating conditions + * Invalidates the memory unconditionally once the behaviour runs. Use {@link InvalidateMemory#invalidateIf} and + * {@link ExtendedBehaviour#startCondition} to quantify its operating conditions + * * @param The brain owner * @param The data type of the memory */ public class InvalidateMemory extends ExtendedBehaviour { - private List, MemoryStatus>> memoryRequirements; - protected BiPredicate customPredicate = (entity, target) -> true; - protected MemoryModuleType memory; + private List, MemoryStatus>> memoryRequirements; + + protected BiPredicate customPredicate = (entity, target) -> true; + + protected MemoryModuleType memory; - public InvalidateMemory(MemoryModuleType memory) { - super(); + public InvalidateMemory(MemoryModuleType memory) { + super(); - this.memory = memory; - this.memoryRequirements = List.of(Pair.of(this.memory, MemoryStatus.VALUE_PRESENT)); - } + this.memory = memory; + this.memoryRequirements = List.of(Pair.of(this.memory, MemoryStatus.VALUE_PRESENT)); + } - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return this.memoryRequirements == null ? List.of() : this.memoryRequirements; - } + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return this.memoryRequirements == null ? List.of() : this.memoryRequirements; + } - /** - * Sets the {@link MemoryModuleType memory} to check and invalidate. - */ - public InvalidateMemory forMemory(MemoryModuleType memory) { - this.memory = memory; - this.memoryRequirements = List.of(Pair.of(this.memory, MemoryStatus.VALUE_PRESENT)); + /** + * Sets the {@link MemoryModuleType memory} to check and invalidate. + */ + public InvalidateMemory forMemory(MemoryModuleType memory) { + this.memory = memory; + this.memoryRequirements = List.of(Pair.of(this.memory, MemoryStatus.VALUE_PRESENT)); - return this; - } + return this; + } - /** - * Sets a custom predicate to invalidate the memory if none of the previous checks invalidate it first. - */ - public InvalidateMemory invalidateIf(BiPredicate predicate) { - this.customPredicate = predicate; + /** + * Sets a custom predicate to invalidate the memory if none of the previous checks invalidate it first. + */ + public InvalidateMemory invalidateIf(BiPredicate predicate) { + this.customPredicate = predicate; - return this; - } + return this; + } - @Override - protected void start(E entity) { - M memory = BrainUtils.getMemory(entity, this.memory); + @Override + protected void start(E entity) { + M memory = BrainUtils.getMemory(entity, this.memory); - if (memory != null && this.customPredicate.test(entity, memory)) - BrainUtils.clearMemory(entity, this.memory); - } + if (memory != null && this.customPredicate.test(entity, memory)) + BrainUtils.clearMemory(entity, this.memory); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Panic.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Panic.java index 966b74aa1..398c11925 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Panic.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Panic.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -21,165 +20,210 @@ import net.minecraft.world.entity.ai.util.DefaultRandomPos; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.BiFunction; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.object.SquareRadius; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Functional equivalent of the goal system's {@link net.minecraft.world.entity.ai.goal.PanicGoal panic goal}.
    * Rapidly sets a runaway position based on its last damage.
    * Defaults: *
      - *
    • 1.25x Speed modifier when panicking
    • - *
    • Panics if freezing, on fire, or was recently hurt by a living entity
    • - *
    • Runs to a nearby location within 5x4 blocks radius
    • - *
    • Panics for a minimum of 5-6 seconds
    • + *
    • 1.25x Speed modifier when panicking
    • + *
    • Panics if freezing, on fire, or was recently hurt by a living entity
    • + *
    • Runs to a nearby location within 5x4 blocks radius
    • + *
    • Panics for a minimum of 5-6 seconds
    • *
    + * * @param The entity */ public class Panic extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.HURT_BY, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.IS_PANICKING, MemoryStatus.REGISTERED)); - - protected BiPredicate shouldPanicPredicate = (entity, damageSource) -> entity.isFreezing() || entity.isOnFire() || damageSource.getEntity() instanceof LivingEntity; - protected Object2FloatFunction speedMod = entity -> 1.25f; - protected SquareRadius radius = new SquareRadius(5, 4); - protected BiFunction panicFor = (entity, damageSource) -> entity.getRandom().nextInt(100, 120); - - protected Vec3 targetPos = null; - protected int panicEndTime = 0; - - public Panic() { - noTimeout(); - } - - /** - * Set a custom predicate for if the entity should panic based on its current conditions. - * @param predicate The predicate - * @return this - */ - public Panic panicIf(final BiPredicate predicate) { - this.shouldPanicPredicate = predicate; - - return this; - } - - /** - * Determine the length of time (in ticks) that the entity should panic for once starting - * @param function The predicate - * @return this - */ - public Panic panicFor(final BiFunction function) { - this.panicFor = function; - - return this; - } - - /** - * Set the movespeed modifier for the entity when panicking. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public Panic speedMod(final Object2FloatFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Set the radius in which to look for walk positions. - * @param radius The coordinate radius, in blocks - * @return this - */ - public Panic setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for walk positions. - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public Panic setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!this.shouldPanicPredicate.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY))) - return false; - - setPanicTarget(entity); - - return this.targetPos != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return entity.tickCount < this.panicEndTime; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.targetPos, this.speedMod.apply(entity), 0)); - BrainUtils.setMemory(entity, MemoryModuleType.IS_PANICKING, true); - - this.panicEndTime = entity.tickCount + this.panicFor.apply(entity, BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY)); - } - - @Override - protected void tick(E entity) { - if (entity.getNavigation().isDone()) { - this.targetPos = null; - setPanicTarget(entity); - - if (this.targetPos != null) { - BrainUtils.clearMemory(entity, MemoryModuleType.PATH); - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.targetPos, this.speedMod.apply(entity), 1)); - } - } - } - - @Override - protected void stop(E entity) { - this.targetPos = null; - this.panicEndTime = 0; - - BrainUtils.setMemory(entity, MemoryModuleType.IS_PANICKING, false); - } - - @Nullable - protected Vec3 findNearbyWater(E entity) { - final BlockPos pos = entity.blockPosition(); - final Level level = entity.level(); - - return !level.getBlockState(pos).getCollisionShape(level, pos).isEmpty() ? null : BlockPos.findClosestMatch(entity.blockPosition(), (int)this.radius.xzRadius(), (int)this.radius.yRadius(), checkPos -> level.getFluidState(checkPos).is(FluidTags.WATER)).map(Vec3::atBottomCenterOf).orElse(null); - } - - protected void setPanicTarget(E entity) { - if (entity.isOnFire()) - this.targetPos = findNearbyWater(entity); - - if (this.targetPos == null) { - final DamageSource lastDamage = BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY); - - if (lastDamage != null && lastDamage.getEntity() instanceof LivingEntity attacker) - this.targetPos = DefaultRandomPos.getPosAway(entity, (int)this.radius.xzRadius(), (int)this.radius.yRadius(), attacker.position()); - - if (this.targetPos == null) - this.targetPos = DefaultRandomPos.getPos(entity, (int)this.radius.xzRadius(), (int)this.radius.yRadius()); - } - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.HURT_BY, MemoryStatus.VALUE_PRESENT), + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.IS_PANICKING, MemoryStatus.REGISTERED) + ); + + protected BiPredicate shouldPanicPredicate = (entity, damageSource) -> entity.isFreezing() + || entity.isOnFire() || damageSource.getEntity() instanceof LivingEntity; + + protected Object2FloatFunction speedMod = entity -> 1.25f; + + protected SquareRadius radius = new SquareRadius(5, 4); + + protected BiFunction panicFor = (entity, damageSource) -> entity.getRandom() + .nextInt(100, 120); + + protected Vec3 targetPos = null; + + protected int panicEndTime = 0; + + public Panic() { + noTimeout(); + } + + /** + * Set a custom predicate for if the entity should panic based on its current conditions. + * + * @param predicate The predicate + * @return this + */ + public Panic panicIf(final BiPredicate predicate) { + this.shouldPanicPredicate = predicate; + + return this; + } + + /** + * Determine the length of time (in ticks) that the entity should panic for once starting + * + * @param function The predicate + * @return this + */ + public Panic panicFor(final BiFunction function) { + this.panicFor = function; + + return this; + } + + /** + * Set the movespeed modifier for the entity when panicking. + * + * @param speedModifier The movespeed modifier/multiplier + * @return this + */ + public Panic speedMod(final Object2FloatFunction speedModifier) { + this.speedMod = speedModifier; + + return this; + } + + /** + * Set the radius in which to look for walk positions. + * + * @param radius The coordinate radius, in blocks + * @return this + */ + public Panic setRadius(double radius) { + return setRadius(radius, radius); + } + + /** + * Set the radius in which to look for walk positions. + * + * @param xz The X/Z coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks + * @return this + */ + public Panic setRadius(double xz, double y) { + this.radius = new SquareRadius(xz, y); + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + if (!this.shouldPanicPredicate.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY))) + return false; + + setPanicTarget(entity); + + return this.targetPos != null; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return entity.tickCount < this.panicEndTime; + } + + @Override + protected void start(E entity) { + BrainUtils.setMemory( + entity, + MemoryModuleType.WALK_TARGET, + new WalkTarget(this.targetPos, this.speedMod.apply(entity), 0) + ); + BrainUtils.setMemory(entity, MemoryModuleType.IS_PANICKING, true); + + this.panicEndTime = entity.tickCount + this.panicFor.apply( + entity, + BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY) + ); + } + + @Override + protected void tick(E entity) { + if (entity.getNavigation().isDone()) { + this.targetPos = null; + setPanicTarget(entity); + + if (this.targetPos != null) { + BrainUtils.clearMemory(entity, MemoryModuleType.PATH); + BrainUtils.setMemory( + entity, + MemoryModuleType.WALK_TARGET, + new WalkTarget(this.targetPos, this.speedMod.apply(entity), 1) + ); + } + } + } + + @Override + protected void stop(E entity) { + this.targetPos = null; + this.panicEndTime = 0; + + BrainUtils.setMemory(entity, MemoryModuleType.IS_PANICKING, false); + } + + @Nullable + protected Vec3 findNearbyWater(E entity) { + final BlockPos pos = entity.blockPosition(); + final Level level = entity.level(); + + return !level.getBlockState(pos).getCollisionShape(level, pos).isEmpty() + ? null + : BlockPos.findClosestMatch( + entity.blockPosition(), + (int) this.radius.xzRadius(), + (int) this.radius.yRadius(), + checkPos -> level.getFluidState(checkPos).is(FluidTags.WATER) + ).map(Vec3::atBottomCenterOf).orElse(null); + } + + protected void setPanicTarget(E entity) { + if (entity.isOnFire()) + this.targetPos = findNearbyWater(entity); + + if (this.targetPos == null) { + final DamageSource lastDamage = BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY); + + if (lastDamage != null && lastDamage.getEntity() instanceof LivingEntity attacker) + this.targetPos = DefaultRandomPos.getPosAway( + entity, + (int) this.radius.xzRadius(), + (int) this.radius.yRadius(), + attacker.position() + ); + + if (this.targetPos == null) + this.targetPos = DefaultRandomPos.getPos( + entity, + (int) this.radius.xzRadius(), + (int) this.radius.yRadius() + ); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/ReactToUnreachableTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/ReactToUnreachableTarget.java index 39dd4149f..2ea8e411e 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/ReactToUnreachableTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/ReactToUnreachableTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; @@ -11,76 +10,85 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; import java.util.List; import java.util.function.BiConsumer; import java.util.function.Function; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Calls a callback when the entity has been obstructed for a given period of time. + * * @param The entity */ public class ReactToUnreachableTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.VALUE_PRESENT), Pair.of(SBLMemoryTypes.TARGET_UNREACHABLE.get(), MemoryStatus.VALUE_PRESENT)); - - protected Function ticksToReact = entity -> 100; - protected BiConsumer callback = (entity, towering) -> {}; - - protected long reactAtTime = 0; - - /** - * Set the amount of ticks that the target should be unreachable before reacting. - * @param ticksToReact The function to provide the time to wait before reacting - * @return this - */ - public ReactToUnreachableTarget timeBeforeReacting(Function ticksToReact) { - this.ticksToReact = ticksToReact; - - return this; - } - - /** - * Set the function to run when the given time has elapsed and the target is still unreachable. - * @param callback The function to run - * @return this - */ - public ReactToUnreachableTarget reaction(BiConsumer callback) { - this.callback = callback; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean timedOut(long gameTime) { - return this.reactAtTime == 0 || this.reactAtTime < gameTime; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return hasRequiredMemories(entity); - } - - @Override - protected void start(E entity) { - this.reactAtTime = entity.level().getGameTime() + this.ticksToReact.apply(entity); - } - - @Override - protected void stop(E entity) { - this.reactAtTime = 0; - } - - @Override - protected void tick(E entity) { - if (entity.level().getGameTime() == this.reactAtTime) - this.callback.accept(entity, BrainUtils.getMemory(entity, SBLMemoryTypes.TARGET_UNREACHABLE.get())); - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.VALUE_PRESENT), + Pair.of(SBLMemoryTypes.TARGET_UNREACHABLE.get(), MemoryStatus.VALUE_PRESENT) + ); + + protected Function ticksToReact = entity -> 100; + + protected BiConsumer callback = (entity, towering) -> {}; + + protected long reactAtTime = 0; + + /** + * Set the amount of ticks that the target should be unreachable before reacting. + * + * @param ticksToReact The function to provide the time to wait before reacting + * @return this + */ + public ReactToUnreachableTarget timeBeforeReacting(Function ticksToReact) { + this.ticksToReact = ticksToReact; + + return this; + } + + /** + * Set the function to run when the given time has elapsed and the target is still unreachable. + * + * @param callback The function to run + * @return this + */ + public ReactToUnreachableTarget reaction(BiConsumer callback) { + this.callback = callback; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + @Override + protected boolean timedOut(long gameTime) { + return this.reactAtTime == 0 || this.reactAtTime < gameTime; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return hasRequiredMemories(entity); + } + + @Override + protected void start(E entity) { + this.reactAtTime = entity.level().getGameTime() + this.ticksToReact.apply(entity); + } + + @Override + protected void stop(E entity) { + this.reactAtTime = 0; + } + + @Override + protected void tick(E entity) { + if (entity.level().getGameTime() == this.reactAtTime) + this.callback.accept(entity, BrainUtils.getMemory(entity, SBLMemoryTypes.TARGET_UNREACHABLE.get())); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/AvoidEntity.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/AvoidEntity.java index e74cf174a..99384a7e1 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/AvoidEntity.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/AvoidEntity.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; @@ -16,122 +15,134 @@ import net.minecraft.world.entity.ai.util.DefaultRandomPos; import net.minecraft.world.level.pathfinder.Path; import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; import java.util.Optional; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Try to move away from certain entities when they get too close.
    * Defaults: *
      - *
    • 3 block minimum distance
    • - *
    • 7 block maximum distance
    • - *
    • 1x move speed modifier
    • + *
    • 3 block minimum distance
    • + *
    • 7 block maximum distance
    • + *
    • 1x move speed modifier
    • *
    */ public class AvoidEntity extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT)); - - protected Predicate avoidingPredicate = target -> false; - protected float noCloserThanSqr = 9f; - protected float stopAvoidingAfterSqr = 49f; - protected float speedModifier = 1; - - private Path runPath = null; - - public AvoidEntity() { - noTimeout(); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the minimum distance the target entity should be allowed to come before the entity starts retreating. - * @param blocks The distance, in blocks - * @return this - */ - public AvoidEntity noCloserThan(float blocks) { - this.noCloserThanSqr = blocks * blocks; - - return this; - } - - /** - * Set the maximum distance the target entity should be before the entity stops retreating. - * @param blocks The distance, in blocks - * @return this - */ - public AvoidEntity stopCaringAfter(float blocks) { - this.stopAvoidingAfterSqr = blocks * blocks; - - return this; - } - - /** - * Sets the predicate for entities to avoid. - * @param predicate The predicate - * @return this - */ - public AvoidEntity avoiding(Predicate predicate) { - this.avoidingPredicate = predicate; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is running away. - * @param mod The speed multiplier modifier - * @return this - */ - public AvoidEntity speedModifier(float mod) { - this.speedModifier = mod; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - Optional target = BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).findClosest(this.avoidingPredicate); - - if (target.isEmpty()) - return false; - - LivingEntity avoidingEntity = target.get(); - double distToTarget = avoidingEntity.distanceToSqr(entity); - - if (distToTarget > this.noCloserThanSqr) - return false; - - Vec3 runPos = DefaultRandomPos.getPosAway(entity, 16, 7, avoidingEntity.position()); - - if (runPos == null || avoidingEntity.distanceToSqr(runPos.x, runPos.y, runPos.z) < distToTarget) - return false; - - this.runPath = entity.getNavigation().createPath(runPos.x, runPos.y, runPos.z, 0); - - return this.runPath != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return !this.runPath.isDone(); - } - - @Override - protected void start(E entity) { - entity.getNavigation().moveTo(this.runPath, this.speedModifier); - } - - @Override - protected void stop(E entity) { - this.runPath = null; - - entity.getNavigation().setSpeedModifier(1); - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT) + ); + + protected Predicate avoidingPredicate = target -> false; + + protected float noCloserThanSqr = 9f; + + protected float stopAvoidingAfterSqr = 49f; + + protected float speedModifier = 1; + + private Path runPath = null; + + public AvoidEntity() { + noTimeout(); + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + /** + * Set the minimum distance the target entity should be allowed to come before the entity starts retreating. + * + * @param blocks The distance, in blocks + * @return this + */ + public AvoidEntity noCloserThan(float blocks) { + this.noCloserThanSqr = blocks * blocks; + + return this; + } + + /** + * Set the maximum distance the target entity should be before the entity stops retreating. + * + * @param blocks The distance, in blocks + * @return this + */ + public AvoidEntity stopCaringAfter(float blocks) { + this.stopAvoidingAfterSqr = blocks * blocks; + + return this; + } + + /** + * Sets the predicate for entities to avoid. + * + * @param predicate The predicate + * @return this + */ + public AvoidEntity avoiding(Predicate predicate) { + this.avoidingPredicate = predicate; + + return this; + } + + /** + * Set the movespeed modifier for when the entity is running away. + * + * @param mod The speed multiplier modifier + * @return this + */ + public AvoidEntity speedModifier(float mod) { + this.speedModifier = mod; + + return this; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + Optional target = BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES) + .findClosest(this.avoidingPredicate); + + if (target.isEmpty()) + return false; + + LivingEntity avoidingEntity = target.get(); + double distToTarget = avoidingEntity.distanceToSqr(entity); + + if (distToTarget > this.noCloserThanSqr) + return false; + + Vec3 runPos = DefaultRandomPos.getPosAway(entity, 16, 7, avoidingEntity.position()); + + if (runPos == null || avoidingEntity.distanceToSqr(runPos.x, runPos.y, runPos.z) < distToTarget) + return false; + + this.runPath = entity.getNavigation().createPath(runPos.x, runPos.y, runPos.z, 0); + + return this.runPath != null; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return !this.runPath.isDone(); + } + + @Override + protected void start(E entity) { + entity.getNavigation().moveTo(this.runPath, this.speedModifier); + } + + @Override + protected void stop(E entity) { + this.runPath = null; + + entity.getNavigation().setSpeedModifier(1); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/EscapeSun.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/EscapeSun.java index e7f586d40..71c1f8855 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/EscapeSun.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/EscapeSun.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; @@ -17,96 +16,109 @@ import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.ai.memory.WalkTarget; import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Sets the {@link MemoryModuleType#WALK_TARGET walk target} to a safe position if caught in the sun.
    * Defaults: *
      - *
    • Only if not currently fighting something
    • - *
    • Only if already burning from the sun
    • + *
    • Only if not currently fighting something
    • + *
    • Only if already burning from the sun
    • *
    + * * @param The entity */ public class EscapeSun extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED)); - protected float speedModifier = 1; + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED) + ); + + protected float speedModifier = 1; - protected Vec3 hidePos = null; + protected Vec3 hidePos = null; - public EscapeSun() { - noTimeout(); - } + public EscapeSun() { + noTimeout(); + } - /** - * Set the movespeed modifier for when the entity tries to escape the sun - * @param speedMod The speed modifier - * @return this - */ - public EscapeSun speedModifier(float speedMod) { - this.speedModifier = speedMod; + /** + * Set the movespeed modifier for when the entity tries to escape the sun + * + * @param speedMod The speed modifier + * @return this + */ + public EscapeSun speedModifier(float speedMod) { + this.speedModifier = speedMod; - return this; - } + return this; + } - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!level.isDay() || !entity.isOnFire() || !level.canSeeSky(entity.blockPosition())) - return false; + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + if (!level.isDay() || !entity.isOnFire() || !level.canSeeSky(entity.blockPosition())) + return false; - if (!entity.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) - return false; + if (!entity.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) + return false; - this.hidePos = getHidePos(entity); + this.hidePos = getHidePos(entity); - return this.hidePos != null; - } + return this.hidePos != null; + } - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.hidePos, this.speedModifier, 0)); - } + @Override + protected void start(E entity) { + BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.hidePos, this.speedModifier, 0)); + } - @Override - protected boolean shouldKeepRunning(E entity) { - if (this.hidePos == null) - return false; + @Override + protected boolean shouldKeepRunning(E entity) { + if (this.hidePos == null) + return false; - WalkTarget walkTarget = BrainUtils.getMemory(entity, MemoryModuleType.WALK_TARGET); + WalkTarget walkTarget = BrainUtils.getMemory(entity, MemoryModuleType.WALK_TARGET); - if (walkTarget == null) - return false; + if (walkTarget == null) + return false; - return walkTarget.getTarget().currentBlockPosition().equals(BlockPos.containing(this.hidePos)) && !entity.getNavigation().isDone(); - } + return walkTarget.getTarget().currentBlockPosition().equals(BlockPos.containing(this.hidePos)) && !entity + .getNavigation() + .isDone(); + } - @Override - protected void stop(E entity) { - this.hidePos = null; - } + @Override + protected void stop(E entity) { + this.hidePos = null; + } - @Nullable - protected Vec3 getHidePos(E entity) { - RandomSource randomsource = entity.getRandom(); - BlockPos entityPos = entity.blockPosition(); + @Nullable + protected Vec3 getHidePos(E entity) { + RandomSource randomsource = entity.getRandom(); + BlockPos entityPos = entity.blockPosition(); - for(int i = 0; i < 10; ++i) { - BlockPos hidePos = entityPos.offset(randomsource.nextInt(20) - 10, randomsource.nextInt(6) - 3, randomsource.nextInt(20) - 10); + for (int i = 0; i < 10; ++i) { + BlockPos hidePos = entityPos.offset( + randomsource.nextInt(20) - 10, + randomsource.nextInt(6) - 3, + randomsource.nextInt(20) - 10 + ); - if (!entity.level().canSeeSky(hidePos) && entity.getWalkTargetValue(hidePos) < 0.0F) - return Vec3.atBottomCenterOf(hidePos); - } + if (!entity.level().canSeeSky(hidePos) && entity.getWalkTargetValue(hidePos) < 0.0F) + return Vec3.atBottomCenterOf(hidePos); + } - return null; - } + return null; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FleeTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FleeTarget.java index 0e42c98a2..cbe9b707a 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FleeTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FleeTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; @@ -16,89 +15,97 @@ import net.minecraft.world.entity.ai.util.DefaultRandomPos; import net.minecraft.world.level.pathfinder.Path; import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Flee the current attack target.
    * Defaults: *
      - *
    • 20 block flee distance
    • - *
    • 1x move speed modifier
    • + *
    • 20 block flee distance
    • + *
    • 1x move speed modifier
    • *
    + * * @param The entity */ public class FleeTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT)); - - protected int fleeDistance = 20; - protected float speedModifier = 1; - - protected Path runPath = null; - - public FleeTarget() { - noTimeout(); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the maximum distance the entity should try to flee to - * @param blocks The distance, in blocks - * @return this - */ - public FleeTarget fleeDistance(int blocks) { - this.fleeDistance = blocks; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is running away. - * @param mod The speed multiplier modifier - * @return this - */ - public FleeTarget speedModifier(float mod) { - this.speedModifier = mod; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - double distToTarget = entity.distanceToSqr(target); - Vec3 runPos = DefaultRandomPos.getPosAway(entity, this.fleeDistance, 10, target.position()); - - if (runPos == null || target.distanceToSqr(runPos.x, runPos.y, runPos.z) < distToTarget) - return false; - - this.runPath = entity.getNavigation().createPath(runPos.x, runPos.y, runPos.z, 0); - - return this.runPath != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return entity.getNavigation().getPath() == this.runPath && !entity.getNavigation().isDone(); - } - - @Override - protected void start(E entity) { - entity.getNavigation().moveTo(this.runPath, this.speedModifier); - BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } - - @Override - protected void stop(E entity) { - if (entity.getNavigation().getPath() == this.runPath) - entity.getNavigation().setSpeedModifier(1); - - this.runPath = null; - } -} \ No newline at end of file + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT) + ); + + protected int fleeDistance = 20; + + protected float speedModifier = 1; + + protected Path runPath = null; + + public FleeTarget() { + noTimeout(); + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + /** + * Set the maximum distance the entity should try to flee to + * + * @param blocks The distance, in blocks + * @return this + */ + public FleeTarget fleeDistance(int blocks) { + this.fleeDistance = blocks; + + return this; + } + + /** + * Set the movespeed modifier for when the entity is running away. + * + * @param mod The speed multiplier modifier + * @return this + */ + public FleeTarget speedModifier(float mod) { + this.speedModifier = mod; + + return this; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + LivingEntity target = BrainUtils.getTargetOfEntity(entity); + double distToTarget = entity.distanceToSqr(target); + Vec3 runPos = DefaultRandomPos.getPosAway(entity, this.fleeDistance, 10, target.position()); + + if (runPos == null || target.distanceToSqr(runPos.x, runPos.y, runPos.z) < distToTarget) + return false; + + this.runPath = entity.getNavigation().createPath(runPos.x, runPos.y, runPos.z, 0); + + return this.runPath != null; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return entity.getNavigation().getPath() == this.runPath && !entity.getNavigation().isDone(); + } + + @Override + protected void start(E entity) { + entity.getNavigation().moveTo(this.runPath, this.speedModifier); + BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); + } + + @Override + protected void stop(E entity) { + if (entity.getNavigation().getPath() == this.runPath) + entity.getNavigation().setSpeedModifier(1); + + this.runPath = null; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FloatToSurfaceOfFluid.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FloatToSurfaceOfFluid.java index b025ece6f..c5e9fbb2a 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FloatToSurfaceOfFluid.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FloatToSurfaceOfFluid.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; @@ -12,51 +11,55 @@ import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; import java.util.List; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; + /** - * Replacement for {@link net.minecraft.world.entity.ai.goal.FloatGoal} or {@link net.minecraft.world.entity.ai.behavior.Swim}.
    - * Causes the entity to rise to the surface of water and float at the surface. - * Defaults: + * Replacement for {@link net.minecraft.world.entity.ai.goal.FloatGoal} or + * {@link net.minecraft.world.entity.ai.behavior.Swim}.
    + * Causes the entity to rise to the surface of water and float at the surface. Defaults: *
      - *
    • 80% chance per tick to jump
    • - *
    • Applies to water
    • + *
    • 80% chance per tick to jump
    • + *
    • Applies to water
    • *
    */ public class FloatToSurfaceOfFluid extends ExtendedBehaviour { - protected float riseChance = 0.8f; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - /** - * Set the chance per tick that the entity will 'jump' in water, rising up towards the surface. - * @param chance The chance, between 0 and 1 (inclusive) - * @return this - */ - public FloatToSurfaceOfFluid riseChance(float chance) { - this.riseChance = chance; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return entity.isInWater() && entity.getFluidHeight(FluidTags.WATER) > entity.getFluidJumpThreshold() || entity.isInLava(); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return checkExtraStartConditions((ServerLevel)entity.level(), entity); - } - - @Override - protected void tick(E entity) { - if (entity.getRandom().nextFloat() < this.riseChance) - entity.getJumpControl().jump(); - } -} \ No newline at end of file + + protected float riseChance = 0.8f; + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return List.of(); + } + + /** + * Set the chance per tick that the entity will 'jump' in water, rising up towards the surface. + * + * @param chance The chance, between 0 and 1 (inclusive) + * @return this + */ + public FloatToSurfaceOfFluid riseChance(float chance) { + this.riseChance = chance; + + return this; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + return entity.isInWater() && entity.getFluidHeight(FluidTags.WATER) > entity.getFluidJumpThreshold() || entity + .isInLava(); + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return checkExtraStartConditions((ServerLevel) entity.level(), entity); + } + + @Override + protected void tick(E entity) { + if (entity.getRandom().nextFloat() < this.riseChance) + entity.getJumpControl().jump(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowEntity.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowEntity.java index 72840a6c4..d069595d2 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowEntity.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowEntity.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; @@ -19,192 +18,229 @@ import net.minecraft.world.level.pathfinder.PathType; import net.minecraft.world.level.pathfinder.PathfindingContext; import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.RandomUtil; import java.util.List; import java.util.function.BiFunction; import java.util.function.Function; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; +import mod.azure.azurelib.sblforked.util.RandomUtil; + /** * A movement behaviour for automatically following a given entity.
    * Defaults: *
      - *
    • Will stop attempting to move closer than 2 blocks from the target
    • - *
    • Won't attempt to follow until the target is more than 10 blocks away
    • - *
    • Won't teleport to the target if it gets too far away
    • - *
    • 1x movespeed modifier for following
    • + *
    • Will stop attempting to move closer than 2 blocks from the target
    • + *
    • Won't attempt to follow until the target is more than 10 blocks away
    • + *
    • Won't teleport to the target if it gets too far away
    • + *
    • 1x movespeed modifier for following
    • *
    + * * @param The owner of the brain * @param The minimum common class of the entity expected to be following */ public class FollowEntity extends ExtendedBehaviour { - protected Function followingEntityProvider = entity -> null; - - protected BiFunction teleportDistance = (entity, target) -> Double.MAX_VALUE; - protected BiFunction followDistMin = (entity, target) -> 4d; - protected BiFunction speedMod = (entity, target) -> 1f; - - protected float oldWaterPathMalus = 0; - protected float oldLavaPathMalus = 0; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - /** - * Determines the entity that the brain owner should follow. - * @param following The function that provides the entity to follow - * @return this - */ - public FollowEntity following(Function following) { - this.followingEntityProvider = following; - - return this; - } - - /** - * Determines the distance (in blocks) after which the entity should just attempt to teleport closer to the target entity - * @param distance The function to provide the distance to teleport after - * @return this - */ - public FollowEntity teleportToTargetAfter(double distance) { - return teleportToTargetAfter((entity, target) -> distance); - } - - /** - * Determines the distance (in blocks) after which the entity should just attempt to teleport closer to the target entity - * @param distanceProvider The function to provide the distance to teleport after - * @return this - */ - public FollowEntity teleportToTargetAfter(BiFunction distanceProvider) { - this.teleportDistance = distanceProvider; - - return this; - } - - /** - * Determines the distance (in blocks) within which the entity will stop pathing and will do other activities - * @param distance The distance to stop following within - * @return this - */ - public FollowEntity stopFollowingWithin(double distance) { - return stopFollowingWithin((entity, target) -> distance); - } - - /** - * Determines the distance (in blocks) within which the entity will stop pathing and will do other activities - * @param distanceProvider The function to provide the distance to stop following within - * @return this - */ - public FollowEntity stopFollowingWithin(BiFunction distanceProvider) { - this.followDistMin = distanceProvider; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * @param modifier The multiplier for movement speed - * @return this - */ - public FollowEntity speedMod(float modifier) { - return speedMod((entity, target) -> modifier); - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * @param modifier The multiplier function for movement speed - * @return this - */ - public FollowEntity speedMod(BiFunction modifier) { - this.speedMod = modifier; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - T target = this.followingEntityProvider.apply(entity); - - if (target == null || target.isSpectator()) - return false; - - double minDist = this.followDistMin.apply(entity, target); - - return entity.distanceToSqr(target) > minDist * minDist; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - T target = this.followingEntityProvider.apply(entity); - - if (target == null) - return false; - - double dist = entity.distanceToSqr(target); - double minDist = this.followDistMin.apply(entity, target); - - return dist > minDist * minDist; - } - - @Override - protected void start(E entity) { - T target = this.followingEntityProvider.apply(entity); - double minDist = this.followDistMin.apply(entity, target); - float speedMod = this.speedMod.apply(entity, target); - this.oldWaterPathMalus = entity.getPathfindingMalus(PathType.WATER); - - if (entity.fireImmune()) { - this.oldLavaPathMalus = entity.getPathfindingMalus(PathType.LAVA); - - entity.setPathfindingMalus(PathType.LAVA, 0); - } - - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(target, speedMod, (int)minDist)); - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); - entity.setPathfindingMalus(PathType.WATER, 0); - } - - @Override - protected void stop(E entity) { - entity.setPathfindingMalus(PathType.WATER, this.oldWaterPathMalus); - - if (entity.fireImmune()) - entity.setPathfindingMalus(PathType.LAVA, this.oldLavaPathMalus); - - entity.getNavigation().stop(); - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - - @Override - protected void tick(E entity) { - T target = this.followingEntityProvider.apply(entity); - double teleportDist = this.teleportDistance.apply(entity, target); - - if (entity.distanceToSqr(target) >= teleportDist * teleportDist) - teleportToTarget(entity, target); - } - - protected void teleportToTarget(E entity, T target) { - Level level = entity.level(); - BlockPos entityPos = target.blockPosition(); - - BlockPos pos = RandomUtil.getRandomPositionWithinRange(entityPos, 5, 5, 5, 1, 1, 1, true, level, 10, (state, statePos) -> { - PathType pathTypes = entity.getNavigation().getNodeEvaluator().getPathType(new PathfindingContext(level, entity), statePos.getX(), statePos.getY(), statePos.getZ()); - - if (pathTypes != PathType.WALKABLE) - return false; - - return level.noCollision(entity, entity.getBoundingBox().move(Vec3.atBottomCenterOf(statePos).subtract(entity.position()))); - }); - - if (pos != entityPos) { - entity.moveTo(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, entity.getYRot(), entity.getXRot()); - entity.getNavigation().stop(); - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - } -} \ No newline at end of file + + protected Function followingEntityProvider = entity -> null; + + protected BiFunction teleportDistance = (entity, target) -> Double.MAX_VALUE; + + protected BiFunction followDistMin = (entity, target) -> 4d; + + protected BiFunction speedMod = (entity, target) -> 1f; + + protected float oldWaterPathMalus = 0; + + protected float oldLavaPathMalus = 0; + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return List.of(); + } + + /** + * Determines the entity that the brain owner should follow. + * + * @param following The function that provides the entity to follow + * @return this + */ + public FollowEntity following(Function following) { + this.followingEntityProvider = following; + + return this; + } + + /** + * Determines the distance (in blocks) after which the entity should just attempt to teleport closer to the target + * entity + * + * @param distance The function to provide the distance to teleport after + * @return this + */ + public FollowEntity teleportToTargetAfter(double distance) { + return teleportToTargetAfter((entity, target) -> distance); + } + + /** + * Determines the distance (in blocks) after which the entity should just attempt to teleport closer to the target + * entity + * + * @param distanceProvider The function to provide the distance to teleport after + * @return this + */ + public FollowEntity teleportToTargetAfter(BiFunction distanceProvider) { + this.teleportDistance = distanceProvider; + + return this; + } + + /** + * Determines the distance (in blocks) within which the entity will stop pathing and will do other activities + * + * @param distance The distance to stop following within + * @return this + */ + public FollowEntity stopFollowingWithin(double distance) { + return stopFollowingWithin((entity, target) -> distance); + } + + /** + * Determines the distance (in blocks) within which the entity will stop pathing and will do other activities + * + * @param distanceProvider The function to provide the distance to stop following within + * @return this + */ + public FollowEntity stopFollowingWithin(BiFunction distanceProvider) { + this.followDistMin = distanceProvider; + + return this; + } + + /** + * Set the movespeed modifier for when the entity is strafing. + * + * @param modifier The multiplier for movement speed + * @return this + */ + public FollowEntity speedMod(float modifier) { + return speedMod((entity, target) -> modifier); + } + + /** + * Set the movespeed modifier for when the entity is strafing. + * + * @param modifier The multiplier function for movement speed + * @return this + */ + public FollowEntity speedMod(BiFunction modifier) { + this.speedMod = modifier; + + return this; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + T target = this.followingEntityProvider.apply(entity); + + if (target == null || target.isSpectator()) + return false; + + double minDist = this.followDistMin.apply(entity, target); + + return entity.distanceToSqr(target) > minDist * minDist; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + T target = this.followingEntityProvider.apply(entity); + + if (target == null) + return false; + + double dist = entity.distanceToSqr(target); + double minDist = this.followDistMin.apply(entity, target); + + return dist > minDist * minDist; + } + + @Override + protected void start(E entity) { + T target = this.followingEntityProvider.apply(entity); + double minDist = this.followDistMin.apply(entity, target); + float speedMod = this.speedMod.apply(entity, target); + this.oldWaterPathMalus = entity.getPathfindingMalus(PathType.WATER); + + if (entity.fireImmune()) { + this.oldLavaPathMalus = entity.getPathfindingMalus(PathType.LAVA); + + entity.setPathfindingMalus(PathType.LAVA, 0); + } + + BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(target, speedMod, (int) minDist)); + BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); + entity.setPathfindingMalus(PathType.WATER, 0); + } + + @Override + protected void stop(E entity) { + entity.setPathfindingMalus(PathType.WATER, this.oldWaterPathMalus); + + if (entity.fireImmune()) + entity.setPathfindingMalus(PathType.LAVA, this.oldLavaPathMalus); + + entity.getNavigation().stop(); + BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); + } + + @Override + protected void tick(E entity) { + T target = this.followingEntityProvider.apply(entity); + double teleportDist = this.teleportDistance.apply(entity, target); + + if (entity.distanceToSqr(target) >= teleportDist * teleportDist) + teleportToTarget(entity, target); + } + + protected void teleportToTarget(E entity, T target) { + Level level = entity.level(); + BlockPos entityPos = target.blockPosition(); + + BlockPos pos = RandomUtil.getRandomPositionWithinRange( + entityPos, + 5, + 5, + 5, + 1, + 1, + 1, + true, + level, + 10, + (state, statePos) -> { + PathType pathTypes = entity.getNavigation() + .getNodeEvaluator() + .getPathType( + new PathfindingContext(level, entity), + statePos.getX(), + statePos.getY(), + statePos.getZ() + ); + + if (pathTypes != PathType.WALKABLE) + return false; + + return level.noCollision( + entity, + entity.getBoundingBox().move(Vec3.atBottomCenterOf(statePos).subtract(entity.position())) + ); + } + ); + + if (pos != entityPos) { + entity.moveTo(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, entity.getYRot(), entity.getXRot()); + entity.getNavigation().stop(); + BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowOwner.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowOwner.java index 7ab3510fa..660308c86 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowOwner.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowOwner.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; @@ -11,23 +10,25 @@ /** * A movement behaviour for automatically following the owner of a {@link TamableAnimal TameableAnimal}.
    + * * @param The owner of the brain */ public class FollowOwner extends FollowEntity { - protected LivingEntity owner = null; - public FollowOwner() { - following(this::getOwner); - teleportToTargetAfter(12); - } + protected LivingEntity owner = null; - protected LivingEntity getOwner(E entity) { - if (this.owner == null) - this.owner = entity.getOwner(); + public FollowOwner() { + following(this::getOwner); + teleportToTargetAfter(12); + } - if (this.owner != null && this.owner.isRemoved()) - this.owner = null; + protected LivingEntity getOwner(E entity) { + if (this.owner == null) + this.owner = entity.getOwner(); - return this.owner; - } + if (this.owner != null && this.owner.isRemoved()) + this.owner = null; + + return this.owner; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowParent.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowParent.java index f9eed1fce..c2f6dbd9c 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowParent.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowParent.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; @@ -12,48 +11,60 @@ import net.minecraft.world.entity.AgeableMob; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * A movement behaviour for automatically following the parent of an {@link AgeableMob AgeableMob}. - *

    Note that because vanilla animals do not store a reference to their parent or child, by default this behaviour just grabs the nearest - * animal of the same class and presumes it is the parent.

    + *

    + * Note that because vanilla animals do not store a reference to their parent or child, by default this behaviour just + * grabs the nearest animal of the same class and presumes it is the parent. + *

    */ public class FollowParent extends FollowEntity { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT)); - - private BiPredicate parentPredicate = (entity, other) -> entity.getClass() == other.getClass() && other.getAge() >= 0; - - public FollowParent() { - following(this::getParent); - stopFollowingWithin(2); - } - - /** - * Set the predicate that determines whether a given entity is a suitable 'parent' to follow - */ - public FollowParent parentPredicate(BiPredicate predicate) { - this.parentPredicate = predicate; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return entity.getAge() < 0 && super.checkExtraStartConditions(level, entity); - } - - @Override - public List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Nullable - protected AgeableMob getParent(E entity) { - return BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).findClosest(other -> other instanceof AgeableMob ageableMob && this.parentPredicate.test(entity, ageableMob)).map(AgeableMob.class::cast).orElse(null); - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT) + ); + + private BiPredicate parentPredicate = (entity, other) -> entity.getClass() == other.getClass() + && other.getAge() >= 0; + + public FollowParent() { + following(this::getParent); + stopFollowingWithin(2); + } + + /** + * Set the predicate that determines whether a given entity is a suitable 'parent' to follow + */ + public FollowParent parentPredicate(BiPredicate predicate) { + this.parentPredicate = predicate; + + return this; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + return entity.getAge() < 0 && super.checkExtraStartConditions(level, entity); + } + + @Override + public List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + @Nullable + protected AgeableMob getParent(E entity) { + return BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES) + .findClosest( + other -> other instanceof AgeableMob ageableMob && this.parentPredicate.test(entity, ageableMob) + ) + .map(AgeableMob.class::cast) + .orElse(null); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowTemptation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowTemptation.java index 454107215..c72936619 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowTemptation.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowTemptation.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; @@ -17,129 +16,161 @@ import net.minecraft.world.entity.ai.memory.WalkTarget; import net.minecraft.world.entity.animal.Animal; import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; import java.util.function.BiFunction; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** - * {@link ExtendedBehaviour ExtendedBehaviour} equivalent of vanilla's {@link net.minecraft.world.entity.ai.behavior.FollowTemptation FollowTemptation}.
    + * {@link ExtendedBehaviour ExtendedBehaviour} equivalent of vanilla's + * {@link net.minecraft.world.entity.ai.behavior.FollowTemptation FollowTemptation}.
    * Has the entity follow a relevant temptation target (I.E. a player holding a tempting item).
    * Will continue running for as long as the entity is being tempted.
    * Defaults: *
      - *
    • Follows the temptation target indefinitely
    • - *
    • Will stop following if panicked or if it has an active breed target
    • - *
    • Will not follow a temptation target again for 5 seconds after stopping
    • - *
    • Considers 2.5 blocks 'close enough' for the purposes of following temptation
    • - *
    • 1x speed modifier while following
    • + *
    • Follows the temptation target indefinitely
    • + *
    • Will stop following if panicked or if it has an active breed target
    • + *
    • Will not follow a temptation target again for 5 seconds after stopping
    • + *
    • Considers 2.5 blocks 'close enough' for the purposes of following temptation
    • + *
    • 1x speed modifier while following
    • *
    */ public class FollowTemptation extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.IS_TEMPTED, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.TEMPTING_PLAYER, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.IS_PANICKING, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.BREED_TARGET, MemoryStatus.REGISTERED)); - - protected BiFunction speedMod = (entity, temptingPlayer) -> 1f; - protected BiPredicate shouldFollow = (entity, temptingPlayer) -> (!(entity instanceof Animal animal) || animal.getAge() == 0) && !BrainUtils.memoryOrDefault(entity, MemoryModuleType.IS_PANICKING, () -> false); - protected BiFunction closeEnoughWhen = (owner, temptingPlayer) -> 2.5f; - protected Object2IntFunction temptationCooldown = entity -> 100; - - public FollowTemptation() { - super(); - - this.runFor(entity -> Integer.MAX_VALUE); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the movespeed modifier for the entity when following the tempting player. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public FollowTemptation speedMod(final BiFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Determine whether the entity should follow the tempting player or not - * @param predicate The temptation predicate - * @return this - */ - public FollowTemptation followIf(final BiPredicate predicate) { - this.shouldFollow = predicate; - - return this; - } - - /** - * Sets the amount (in blocks) that the mob can be considered 'close enough' to their temptation that they can stop pathfinding - * @param closeEnoughMod The distance modifier - * @return this - */ - public FollowTemptation closeEnoughDist(final BiFunction closeEnoughMod) { - this.closeEnoughWhen = closeEnoughMod; - - return this; - } - - /** - * Sets the length of time (in ticks) the entity should ignore temptation after having previously been tempted.
    - * NOTE: This could be ignored if the {@link FollowTemptation#followIf} predicate has been overriden - * @param cooldownFunction The cooldown function - * @return this - */ - public FollowTemptation temptationCooldown(final Object2IntFunction cooldownFunction) { - this.temptationCooldown = cooldownFunction; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return this.shouldFollow.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER)); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.TEMPTING_PLAYER) && - !BrainUtils.hasMemory(entity, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS) && - !BrainUtils.hasMemory(entity, MemoryModuleType.BREED_TARGET) && - this.shouldFollow.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER)); - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.IS_TEMPTED, true); - } - - @Override - protected void tick(E entity) { - final Player temptingPlayer = BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER); - final float closeEnough = this.closeEnoughWhen.apply(entity, temptingPlayer); - - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(temptingPlayer, true)); - - if (entity.distanceToSqr(temptingPlayer) < closeEnough * closeEnough) { - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(new EntityTracker(temptingPlayer, false), this.speedMod.apply(entity, temptingPlayer), (int)closeEnough)); - } - } - - @Override - protected void stop(E entity) { - final int cooldownTicks = this.temptationCooldown.apply(entity); - - BrainUtils.setForgettableMemory(entity, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, cooldownTicks, cooldownTicks); - BrainUtils.setMemory(entity, MemoryModuleType.IS_TEMPTED, false); - BrainUtils.clearMemories(entity, MemoryModuleType.WALK_TARGET, MemoryModuleType.LOOK_TARGET); - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryStatus.VALUE_ABSENT), + Pair.of(MemoryModuleType.IS_TEMPTED, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.TEMPTING_PLAYER, MemoryStatus.VALUE_PRESENT), + Pair.of(MemoryModuleType.IS_PANICKING, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.BREED_TARGET, MemoryStatus.REGISTERED) + ); + + protected BiFunction speedMod = (entity, temptingPlayer) -> 1f; + + protected BiPredicate shouldFollow = (entity, temptingPlayer) -> (!(entity instanceof Animal animal) + || animal.getAge() == 0) && !BrainUtils.memoryOrDefault(entity, MemoryModuleType.IS_PANICKING, () -> false); + + protected BiFunction closeEnoughWhen = (owner, temptingPlayer) -> 2.5f; + + protected Object2IntFunction temptationCooldown = entity -> 100; + + public FollowTemptation() { + super(); + + this.runFor(entity -> Integer.MAX_VALUE); + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + /** + * Set the movespeed modifier for the entity when following the tempting player. + * + * @param speedModifier The movespeed modifier/multiplier + * @return this + */ + public FollowTemptation speedMod(final BiFunction speedModifier) { + this.speedMod = speedModifier; + + return this; + } + + /** + * Determine whether the entity should follow the tempting player or not + * + * @param predicate The temptation predicate + * @return this + */ + public FollowTemptation followIf(final BiPredicate predicate) { + this.shouldFollow = predicate; + + return this; + } + + /** + * Sets the amount (in blocks) that the mob can be considered 'close enough' to their temptation that they can stop + * pathfinding + * + * @param closeEnoughMod The distance modifier + * @return this + */ + public FollowTemptation closeEnoughDist(final BiFunction closeEnoughMod) { + this.closeEnoughWhen = closeEnoughMod; + + return this; + } + + /** + * Sets the length of time (in ticks) the entity should ignore temptation after having previously been tempted.
    + * NOTE: This could be ignored if the {@link FollowTemptation#followIf} predicate has been overriden + * + * @param cooldownFunction The cooldown function + * @return this + */ + public FollowTemptation temptationCooldown(final Object2IntFunction cooldownFunction) { + this.temptationCooldown = cooldownFunction; + + return this; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + return this.shouldFollow.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER)); + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return BrainUtils.hasMemory(entity, MemoryModuleType.TEMPTING_PLAYER) && + !BrainUtils.hasMemory(entity, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS) && + !BrainUtils.hasMemory(entity, MemoryModuleType.BREED_TARGET) && + this.shouldFollow.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER)); + } + + @Override + protected void start(E entity) { + BrainUtils.setMemory(entity, MemoryModuleType.IS_TEMPTED, true); + } + + @Override + protected void tick(E entity) { + final Player temptingPlayer = BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER); + final float closeEnough = this.closeEnoughWhen.apply(entity, temptingPlayer); + + BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(temptingPlayer, true)); + + if (entity.distanceToSqr(temptingPlayer) < closeEnough * closeEnough) { + BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); + } else { + BrainUtils.setMemory( + entity, + MemoryModuleType.WALK_TARGET, + new WalkTarget( + new EntityTracker(temptingPlayer, false), + this.speedMod.apply(entity, temptingPlayer), + (int) closeEnough + ) + ); + } + } + + @Override + protected void stop(E entity) { + final int cooldownTicks = this.temptationCooldown.apply(entity); + + BrainUtils.setForgettableMemory( + entity, + MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, + cooldownTicks, + cooldownTicks + ); + BrainUtils.setMemory(entity, MemoryModuleType.IS_TEMPTED, false); + BrainUtils.clearMemories(entity, MemoryModuleType.WALK_TARGET, MemoryModuleType.LOOK_TARGET); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/MoveToWalkTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/MoveToWalkTarget.java index 41d186f33..954948eeb 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/MoveToWalkTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/MoveToWalkTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; @@ -19,140 +18,157 @@ import net.minecraft.world.entity.ai.util.DefaultRandomPos; import net.minecraft.world.level.pathfinder.Path; import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + public class MoveToWalkTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.PATH, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_PRESENT)); - @Nullable - protected Path path; - @Nullable - protected BlockPos lastTargetPos; - protected float speedModifier; + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.PATH, MemoryStatus.VALUE_ABSENT), + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_PRESENT) + ); + + @Nullable + protected Path path; + + @Nullable + protected BlockPos lastTargetPos; + + protected float speedModifier; - public MoveToWalkTarget() { - runFor(entity -> entity.getRandom().nextInt(100) + 150); - cooldownFor(entity -> entity.getRandom().nextInt(40)); - } + public MoveToWalkTarget() { + runFor(entity -> entity.getRandom().nextInt(100) + 150); + cooldownFor(entity -> entity.getRandom().nextInt(40)); + } - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - WalkTarget walkTarget = BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET); + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + Brain brain = entity.getBrain(); + WalkTarget walkTarget = BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET); - if (!hasReachedTarget(entity, walkTarget) && attemptNewPath(entity, walkTarget, false)) { - this.lastTargetPos = walkTarget.getTarget().currentBlockPosition(); + if (!hasReachedTarget(entity, walkTarget) && attemptNewPath(entity, walkTarget, false)) { + this.lastTargetPos = walkTarget.getTarget().currentBlockPosition(); - return true; - } + return true; + } - BrainUtils.clearMemory(brain, MemoryModuleType.WALK_TARGET); - BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); + BrainUtils.clearMemory(brain, MemoryModuleType.WALK_TARGET); + BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - return false; - } + return false; + } - @Override - protected boolean shouldKeepRunning(E entity) { - if (this.path == null || this.lastTargetPos == null) - return false; + @Override + protected boolean shouldKeepRunning(E entity) { + if (this.path == null || this.lastTargetPos == null) + return false; - if (entity.getNavigation().isDone()) - return false; + if (entity.getNavigation().isDone()) + return false; - WalkTarget walkTarget = BrainUtils.getMemory(entity, MemoryModuleType.WALK_TARGET); + WalkTarget walkTarget = BrainUtils.getMemory(entity, MemoryModuleType.WALK_TARGET); - return walkTarget != null && !hasReachedTarget(entity, walkTarget); - } + return walkTarget != null && !hasReachedTarget(entity, walkTarget); + } - @Override - protected void start(E entity) { - startOnNewPath(entity); - } + @Override + protected void start(E entity) { + startOnNewPath(entity); + } - @Override - protected void tick(E entity) { - Path path = entity.getNavigation().getPath(); - Brain brain = entity.getBrain(); + @Override + protected void tick(E entity) { + Path path = entity.getNavigation().getPath(); + Brain brain = entity.getBrain(); - if (this.path != path) { - this.path = path; + if (this.path != path) { + this.path = path; - BrainUtils.setMemory(brain, MemoryModuleType.PATH, path); - } + BrainUtils.setMemory(brain, MemoryModuleType.PATH, path); + } - if (path != null && this.lastTargetPos != null) { - WalkTarget walkTarget = BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET); + if (path != null && this.lastTargetPos != null) { + WalkTarget walkTarget = BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET); - if (walkTarget.getTarget().currentBlockPosition().distSqr(this.lastTargetPos) > 4 && attemptNewPath(entity, walkTarget, hasReachedTarget(entity, walkTarget))) { - this.lastTargetPos = walkTarget.getTarget().currentBlockPosition(); + if ( + walkTarget.getTarget().currentBlockPosition().distSqr(this.lastTargetPos) > 4 && attemptNewPath( + entity, + walkTarget, + hasReachedTarget(entity, walkTarget) + ) + ) { + this.lastTargetPos = walkTarget.getTarget().currentBlockPosition(); - startOnNewPath(entity); - } - } - } + startOnNewPath(entity); + } + } + } - @Override - protected void stop(E entity) { - Brain brain = entity.getBrain(); + @Override + protected void stop(E entity) { + Brain brain = entity.getBrain(); - if (!entity.getNavigation().isStuck() || !BrainUtils.hasMemory(brain, MemoryModuleType.WALK_TARGET) || hasReachedTarget(entity, BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET))) - this.cooldownFinishedAt = 0; + if ( + !entity.getNavigation().isStuck() || !BrainUtils.hasMemory(brain, MemoryModuleType.WALK_TARGET) + || hasReachedTarget(entity, BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET)) + ) + this.cooldownFinishedAt = 0; - entity.getNavigation().stop(); - BrainUtils.clearMemories(brain, MemoryModuleType.WALK_TARGET, MemoryModuleType.PATH); + entity.getNavigation().stop(); + BrainUtils.clearMemories(brain, MemoryModuleType.WALK_TARGET, MemoryModuleType.PATH); - this.path = null; - } + this.path = null; + } - protected boolean attemptNewPath(E entity, WalkTarget walkTarget, boolean reachedCurrentTarget) { - Brain brain = entity.getBrain(); - BlockPos pos = walkTarget.getTarget().currentBlockPosition(); - this.path = entity.getNavigation().createPath(pos, 0); - this.speedModifier = walkTarget.getSpeedModifier(); + protected boolean attemptNewPath(E entity, WalkTarget walkTarget, boolean reachedCurrentTarget) { + Brain brain = entity.getBrain(); + BlockPos pos = walkTarget.getTarget().currentBlockPosition(); + this.path = entity.getNavigation().createPath(pos, 0); + this.speedModifier = walkTarget.getSpeedModifier(); - if (reachedCurrentTarget) { - BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); + if (reachedCurrentTarget) { + BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - return false; - } + return false; + } - if (this.path != null && this.path.canReach()) { - BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - } - else { - BrainUtils.setMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, entity.level().getGameTime()); - } + if (this.path != null && this.path.canReach()) { + BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); + } else { + BrainUtils.setMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, entity.level().getGameTime()); + } - if (this.path != null) - return true; + if (this.path != null) + return true; - Vec3 newTargetPos = DefaultRandomPos.getPosTowards(entity, 10, 7, Vec3.atBottomCenterOf(pos), Mth.HALF_PI); + Vec3 newTargetPos = DefaultRandomPos.getPosTowards(entity, 10, 7, Vec3.atBottomCenterOf(pos), Mth.HALF_PI); - if (newTargetPos != null) { - this.path = entity.getNavigation().createPath(newTargetPos.x(), newTargetPos.y(), newTargetPos.z(), 0); + if (newTargetPos != null) { + this.path = entity.getNavigation().createPath(newTargetPos.x(), newTargetPos.y(), newTargetPos.z(), 0); - return this.path != null; - } + return this.path != null; + } - return false; - } + return false; + } - protected boolean hasReachedTarget(E entity, WalkTarget target) { - return target.getTarget().currentBlockPosition().distManhattan(entity.blockPosition()) <= target.getCloseEnoughDist(); - } + protected boolean hasReachedTarget(E entity, WalkTarget target) { + return target.getTarget().currentBlockPosition().distManhattan(entity.blockPosition()) <= target + .getCloseEnoughDist(); + } - protected void startOnNewPath(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.PATH, this.path); - entity.getNavigation().moveTo(this.path, this.speedModifier); - } + protected void startOnNewPath(E entity) { + BrainUtils.setMemory(entity, MemoryModuleType.PATH, this.path); + entity.getNavigation().moveTo(this.path, this.speedModifier); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StayWithinDistanceOfAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StayWithinDistanceOfAttackTarget.java index 021645e3e..67574a566 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StayWithinDistanceOfAttackTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StayWithinDistanceOfAttackTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; @@ -18,145 +17,160 @@ import net.minecraft.world.entity.ai.navigation.PathNavigation; import net.minecraft.world.entity.ai.util.DefaultRandomPos; import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; import java.util.function.BiFunction; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Movement behaviour to handle proximal strafing. Will run away if too close, or run towards if too far.
    * Useful for ranged attackers.
    * Defaults: *
      - *
    • Continues strafing until the target is no longer in memory
    • - *
    • Stays between 5 and 20 blocks of the target
    • - *
    • Normal strafing speed
    • - *
    • 30% speed boost to repositioning
    • + *
    • Continues strafing until the target is no longer in memory
    • + *
    • Stays between 5 and 20 blocks of the target
    • + *
    • Normal strafing speed
    • + *
    • 30% speed boost to repositioning
    • *
    + * * @param The entity */ public class StayWithinDistanceOfAttackTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected BiFunction distMax = (entity, target) -> 20f; - protected BiFunction distMin = (entity, target) -> 5f; - protected Predicate stopWhen = entity -> false; - protected float speedMod = 1; - protected float repositionSpeedMod = 1.3f; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set how far the entity should attempt to stay away from the target at a minimum. - * @param distance The distance, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget minDistance(float distance) { - return minDistance((entity, target) -> distance); - } - - /** - * Set how far the entity should attempt to stay away from the target at a minimum. - * @param distance The distance function, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget minDistance(BiFunction distance) { - this.distMin = distance; - - return this; - } - - /** - * Set how far the entity should attempt to stay away from the target at most. - * @param distance The distance, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget maxDistance(float distance) { - return maxDistance((entity, target) -> distance); - } - - /** - * Set how far the entity should attempt to stay away from the target at most. - * @param distance The distance function, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget maxDistance(BiFunction distance) { - this.distMax = distance; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * @param modifier The multiplier for movement speed - * @return this - */ - public StayWithinDistanceOfAttackTarget speedMod(float modifier) { - this.speedMod = modifier; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is repositioning due to being too close or too far. - * @param modifier The multiplier for movement speed - * @return this - */ - public StayWithinDistanceOfAttackTarget repositionSpeedMod(float modifier) { - this.speedMod = modifier; - - return this; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.ATTACK_TARGET) && !this.stopWhen.test(entity); - } - - @Override - protected void tick(E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - double distanceToTarget = target.distanceToSqr(entity); - float maxDist = this.distMax.apply(entity, target); - double maxDistSq = Math.pow(maxDist, 2); - double minDistSq = Math.pow(this.distMin.apply(entity, target), 2); - PathNavigation navigation = entity.getNavigation(); - - if (distanceToTarget > maxDistSq || !entity.hasLineOfSight(target)) { - if (navigation.isDone()) - navigation.moveTo(target, this.repositionSpeedMod); - - return; - } - - if (distanceToTarget < minDistSq) { - if (navigation.isDone()) { - Vec3 runPos = DefaultRandomPos.getPosAway(entity, (int)maxDist, 5, target.position()); - - if (runPos != null) - navigation.moveTo(navigation.createPath(BlockPos.containing(runPos), 1), this.repositionSpeedMod); - } - - return; - } - - if (navigation instanceof GroundPathNavigation) - navigation.stop(); - - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); - - if (distanceToTarget > maxDistSq * 0.5f) { - entity.lookAt(target, 30, 30); - entity.getMoveControl().strafe(0.5f * this.speedMod, 0); - } - else if (distanceToTarget < minDistSq * 3f) { - entity.lookAt(target, 30, 30); - entity.getMoveControl().strafe(-0.5f * this.speedMod, 0); - } - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) + ); + + protected BiFunction distMax = (entity, target) -> 20f; + + protected BiFunction distMin = (entity, target) -> 5f; + + protected Predicate stopWhen = entity -> false; + + protected float speedMod = 1; + + protected float repositionSpeedMod = 1.3f; + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + /** + * Set how far the entity should attempt to stay away from the target at a minimum. + * + * @param distance The distance, in blocks + * @return this + */ + public StayWithinDistanceOfAttackTarget minDistance(float distance) { + return minDistance((entity, target) -> distance); + } + + /** + * Set how far the entity should attempt to stay away from the target at a minimum. + * + * @param distance The distance function, in blocks + * @return this + */ + public StayWithinDistanceOfAttackTarget minDistance(BiFunction distance) { + this.distMin = distance; + + return this; + } + + /** + * Set how far the entity should attempt to stay away from the target at most. + * + * @param distance The distance, in blocks + * @return this + */ + public StayWithinDistanceOfAttackTarget maxDistance(float distance) { + return maxDistance((entity, target) -> distance); + } + + /** + * Set how far the entity should attempt to stay away from the target at most. + * + * @param distance The distance function, in blocks + * @return this + */ + public StayWithinDistanceOfAttackTarget maxDistance(BiFunction distance) { + this.distMax = distance; + + return this; + } + + /** + * Set the movespeed modifier for when the entity is strafing. + * + * @param modifier The multiplier for movement speed + * @return this + */ + public StayWithinDistanceOfAttackTarget speedMod(float modifier) { + this.speedMod = modifier; + + return this; + } + + /** + * Set the movespeed modifier for when the entity is repositioning due to being too close or too far. + * + * @param modifier The multiplier for movement speed + * @return this + */ + public StayWithinDistanceOfAttackTarget repositionSpeedMod(float modifier) { + this.speedMod = modifier; + + return this; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return BrainUtils.hasMemory(entity, MemoryModuleType.ATTACK_TARGET) && !this.stopWhen.test(entity); + } + + @Override + protected void tick(E entity) { + LivingEntity target = BrainUtils.getTargetOfEntity(entity); + double distanceToTarget = target.distanceToSqr(entity); + float maxDist = this.distMax.apply(entity, target); + double maxDistSq = Math.pow(maxDist, 2); + double minDistSq = Math.pow(this.distMin.apply(entity, target), 2); + PathNavigation navigation = entity.getNavigation(); + + if (distanceToTarget > maxDistSq || !entity.hasLineOfSight(target)) { + if (navigation.isDone()) + navigation.moveTo(target, this.repositionSpeedMod); + + return; + } + + if (distanceToTarget < minDistSq) { + if (navigation.isDone()) { + Vec3 runPos = DefaultRandomPos.getPosAway(entity, (int) maxDist, 5, target.position()); + + if (runPos != null) + navigation.moveTo(navigation.createPath(BlockPos.containing(runPos), 1), this.repositionSpeedMod); + } + + return; + } + + if (navigation instanceof GroundPathNavigation) + navigation.stop(); + + BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); + + if (distanceToTarget > maxDistSq * 0.5f) { + entity.lookAt(target, 30, 30); + entity.getMoveControl().strafe(0.5f * this.speedMod, 0); + } else if (distanceToTarget < minDistSq * 3f) { + entity.lookAt(target, 30, 30); + entity.getMoveControl().strafe(-0.5f * this.speedMod, 0); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StrafeTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StrafeTarget.java index ecef83daa..ced37a23b 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StrafeTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StrafeTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; @@ -12,108 +11,119 @@ import net.minecraft.world.entity.PathfinderMob; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Movement behaviour to handle strafing.
    * Defaults: *
      - *
    • Continues strafing until the target is no longer in memory
    • + *
    • Continues strafing until the target is no longer in memory
    • *
    + * * @param The entity */ public class StrafeTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected boolean strafingLaterally = false; - protected boolean strafingBack = false; - protected int strafeCounter = -1; - - protected float strafeDistanceSqr = 244; - protected Predicate stopStrafingWhen = entity -> false; - protected float speedMod = 1; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set a custom condition for when the strafing should end. - * @param predicate The predicate - * @return this - */ - public StrafeTarget stopStrafingWhen(Predicate predicate) { - this.stopStrafingWhen = predicate; - - return this; - } - - /** - * Set how far the entity should attempt to stay away from the target whilst strafing. - * @param distance The distance, in blocks - * @return this - */ - public StrafeTarget strafeDistance(float distance) { - this.strafeDistanceSqr = distance * distance; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * @param modifier The multiplier for movement speed - * @return this - */ - public StrafeTarget speedMod(float modifier) { - this.speedMod = modifier; - - return this; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.ATTACK_TARGET) && !this.stopStrafingWhen.test(entity); - } - - @Override - protected void tick(E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - double distanceToTarget = target.distanceToSqr(entity); - - if (distanceToTarget <= this.strafeDistanceSqr) { - entity.getNavigation().stop(); - this.strafeCounter++; - } - else { - entity.getNavigation().moveTo(target, this.speedMod); - this.strafeCounter = -1; - } - - if (this.strafeCounter >= 20) { - if (entity.getRandom().nextFloat() < 0.3) - this.strafingLaterally = !this.strafingLaterally; - - if (entity.getRandom().nextFloat() < 0.3) - this.strafingBack = !this.strafingBack; - - this.strafeCounter = 0; - } - - if (this.strafeCounter > -1) { - if (distanceToTarget > this.strafeDistanceSqr * 0.75f) { - this.strafingBack = false; - } - else if (distanceToTarget < this.strafeDistanceSqr * 0.25f) { - this.strafingBack = true; - } - - entity.lookAt(target, 30, 30); - entity.getMoveControl().strafe(this.strafingBack ? -0.5f : 0.5f, this.strafingLaterally ? 0.5f : -0.5f); - } - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) + ); + + protected boolean strafingLaterally = false; + + protected boolean strafingBack = false; + + protected int strafeCounter = -1; + + protected float strafeDistanceSqr = 244; + + protected Predicate stopStrafingWhen = entity -> false; + + protected float speedMod = 1; + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + /** + * Set a custom condition for when the strafing should end. + * + * @param predicate The predicate + * @return this + */ + public StrafeTarget stopStrafingWhen(Predicate predicate) { + this.stopStrafingWhen = predicate; + + return this; + } + + /** + * Set how far the entity should attempt to stay away from the target whilst strafing. + * + * @param distance The distance, in blocks + * @return this + */ + public StrafeTarget strafeDistance(float distance) { + this.strafeDistanceSqr = distance * distance; + + return this; + } + + /** + * Set the movespeed modifier for when the entity is strafing. + * + * @param modifier The multiplier for movement speed + * @return this + */ + public StrafeTarget speedMod(float modifier) { + this.speedMod = modifier; + + return this; + } + + @Override + protected boolean shouldKeepRunning(E entity) { + return BrainUtils.hasMemory(entity, MemoryModuleType.ATTACK_TARGET) && !this.stopStrafingWhen.test(entity); + } + + @Override + protected void tick(E entity) { + LivingEntity target = BrainUtils.getTargetOfEntity(entity); + double distanceToTarget = target.distanceToSqr(entity); + + if (distanceToTarget <= this.strafeDistanceSqr) { + entity.getNavigation().stop(); + this.strafeCounter++; + } else { + entity.getNavigation().moveTo(target, this.speedMod); + this.strafeCounter = -1; + } + + if (this.strafeCounter >= 20) { + if (entity.getRandom().nextFloat() < 0.3) + this.strafingLaterally = !this.strafingLaterally; + + if (entity.getRandom().nextFloat() < 0.3) + this.strafingBack = !this.strafingBack; + + this.strafeCounter = 0; + } + + if (this.strafeCounter > -1) { + if (distanceToTarget > this.strafeDistanceSqr * 0.75f) { + this.strafingBack = false; + } else if (distanceToTarget < this.strafeDistanceSqr * 0.25f) { + this.strafingBack = true; + } + + entity.lookAt(target, 30, 30); + entity.getMoveControl().strafe(this.strafingBack ? -0.5f : 0.5f, this.strafingLaterally ? 0.5f : -0.5f); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/WalkOrRunToWalkTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/WalkOrRunToWalkTarget.java index 47a96cd7e..acd8fdf33 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/WalkOrRunToWalkTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/WalkOrRunToWalkTarget.java @@ -1,33 +1,35 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; import net.minecraft.world.entity.PathfinderMob; import net.minecraft.world.entity.ai.memory.MemoryModuleType; + import mod.azure.azurelib.sblforked.util.BrainUtils; /** - * Extension of MoveToWalkTarget, but auto-marking the sprinting flag depending on the movespeed. - * This can be useful for using sprint animations on the client. + * Extension of MoveToWalkTarget, but auto-marking the sprinting flag depending on the movespeed. This can be useful for + * using sprint animations on the client. + * * @param */ public class WalkOrRunToWalkTarget extends MoveToWalkTarget { - @Override - protected void startOnNewPath(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.PATH, this.path); - if (entity.getNavigation().moveTo(this.path, this.speedModifier)) - entity.setSharedFlag(3, this.speedModifier > 1); - } + @Override + protected void startOnNewPath(E entity) { + BrainUtils.setMemory(entity, MemoryModuleType.PATH, this.path); + + if (entity.getNavigation().moveTo(this.path, this.speedModifier)) + entity.setSharedFlag(3, this.speedModifier > 1); + } - @Override - protected void stop(E entity) { - super.stop(entity); + @Override + protected void stop(E entity) { + super.stop(entity); - entity.setSharedFlag(3, false); - } -} \ No newline at end of file + entity.setSharedFlag(3, false); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SeekRandomNearbyPosition.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SeekRandomNearbyPosition.java index 3369afecc..78f6a7c8c 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SeekRandomNearbyPosition.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SeekRandomNearbyPosition.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; @@ -16,10 +15,6 @@ import net.minecraft.world.entity.ai.memory.WalkTarget; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.RandomUtil; -import mod.azure.azurelib.sblforked.object.SquareRadius; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -27,121 +22,156 @@ import java.util.function.BiPredicate; import java.util.function.Function; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.object.SquareRadius; +import mod.azure.azurelib.sblforked.util.BrainUtils; +import mod.azure.azurelib.sblforked.util.RandomUtil; + /** * Walk target class that finds a random position nearby and sets it as the walk target if applicable.
    * Useful for finding quick alternate paths for specific purposes.
    * Defaults: *
      - *
    • 10x6 block search radius
    • - *
    • 1x Movespeed modifier
    • - *
    • 10 Attempts at finding a position before giving up
    • + *
    • 10x6 block search radius
    • + *
    • 1x Movespeed modifier
    • + *
    • 10 Attempts at finding a position before giving up
    • *
    + * * @param The entity */ public class SeekRandomNearbyPosition extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORIES = ObjectArrayList.of(Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected BiPredicate validPosition = (entity, state) -> false; - protected BiFunction speedModifier = (entity, targetPos) -> 1f; - protected SquareRadius radius = new SquareRadius(10, 6); - protected Function tries = entity -> 10; - - protected Vec3 targetPos = null; - - /** - * Set the radius in which to look for walk positions. - * @param radius The coordinate radius, in blocks - * @return this - */ - public SeekRandomNearbyPosition setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for walk positions. - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SeekRandomNearbyPosition setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param modifier The movespeed modifier/multiplier - * @return this - */ - public SeekRandomNearbyPosition speedModifier(float modifier) { - return speedModifier((entity, targetPos) -> modifier); - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param function The movespeed modifier/multiplier function - * @return this - */ - public SeekRandomNearbyPosition speedModifier(BiFunction function) { - this.speedModifier = function; - - return this; - } - - /** - * Sets the number of positions to check before giving up on finding a valid target. - * @param attempts The number of attempts - * @return this - */ - public SeekRandomNearbyPosition attempts(int attempts) { - return attempts(entity -> attempts); - } - - /** - * Sets the number of positions to check before giving up on finding a valid target. - * @param function The attempts function - * @return this - */ - public SeekRandomNearbyPosition attempts(Function function) { - this.tries = function; - - return this; - } - - /** - * Set the predicate that determines the validity of positions when searching - * @param predicate The predicate - * @return this - */ - public SeekRandomNearbyPosition validPositions(BiPredicate predicate) { - this.validPosition = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORIES; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.targetPos = getTargetPos(entity); - - return this.targetPos != null; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.targetPos, this.speedModifier.apply(entity, this.targetPos), 0)); - } - - @Nullable - protected Vec3 getTargetPos(E entity) { - BlockPos entityPos = entity.blockPosition(); - BlockPos targetPos = RandomUtil.getRandomPositionWithinRange(entityPos, (int)this.radius.xzRadius(), (int)this.radius.yRadius(), (int)this.radius.xzRadius(), 0, 0, 0, false, entity.level(), 10, (state, pos) -> this.validPosition.test(entity, state)); - - return targetPos == entityPos ? null : Vec3.atBottomCenterOf(targetPos); - } -} \ No newline at end of file + + private static final List, MemoryStatus>> MEMORIES = ObjectArrayList.of( + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) + ); + + protected BiPredicate validPosition = (entity, state) -> false; + + protected BiFunction speedModifier = (entity, targetPos) -> 1f; + + protected SquareRadius radius = new SquareRadius(10, 6); + + protected Function tries = entity -> 10; + + protected Vec3 targetPos = null; + + /** + * Set the radius in which to look for walk positions. + * + * @param radius The coordinate radius, in blocks + * @return this + */ + public SeekRandomNearbyPosition setRadius(double radius) { + return setRadius(radius, radius); + } + + /** + * Set the radius in which to look for walk positions. + * + * @param xz The X/Z coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks + * @return this + */ + public SeekRandomNearbyPosition setRadius(double xz, double y) { + this.radius = new SquareRadius(xz, y); + + return this; + } + + /** + * Set the movespeed modifier for the path when chosen. + * + * @param modifier The movespeed modifier/multiplier + * @return this + */ + public SeekRandomNearbyPosition speedModifier(float modifier) { + return speedModifier((entity, targetPos) -> modifier); + } + + /** + * Set the movespeed modifier for the path when chosen. + * + * @param function The movespeed modifier/multiplier function + * @return this + */ + public SeekRandomNearbyPosition speedModifier(BiFunction function) { + this.speedModifier = function; + + return this; + } + + /** + * Sets the number of positions to check before giving up on finding a valid target. + * + * @param attempts The number of attempts + * @return this + */ + public SeekRandomNearbyPosition attempts(int attempts) { + return attempts(entity -> attempts); + } + + /** + * Sets the number of positions to check before giving up on finding a valid target. + * + * @param function The attempts function + * @return this + */ + public SeekRandomNearbyPosition attempts(Function function) { + this.tries = function; + + return this; + } + + /** + * Set the predicate that determines the validity of positions when searching + * + * @param predicate The predicate + * @return this + */ + public SeekRandomNearbyPosition validPositions(BiPredicate predicate) { + this.validPosition = predicate; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORIES; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + this.targetPos = getTargetPos(entity); + + return this.targetPos != null; + } + + @Override + protected void start(E entity) { + BrainUtils.setMemory( + entity, + MemoryModuleType.WALK_TARGET, + new WalkTarget(this.targetPos, this.speedModifier.apply(entity, this.targetPos), 0) + ); + } + + @Nullable + protected Vec3 getTargetPos(E entity) { + BlockPos entityPos = entity.blockPosition(); + BlockPos targetPos = RandomUtil.getRandomPositionWithinRange( + entityPos, + (int) this.radius.xzRadius(), + (int) this.radius.yRadius(), + (int) this.radius.xzRadius(), + 0, + 0, + 0, + false, + entity.level(), + 10, + (state, pos) -> this.validPosition.test(entity, state) + ); + + return targetPos == entityPos ? null : Vec3.atBottomCenterOf(targetPos); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomFlyingTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomFlyingTarget.java index e4a8522e9..316146806 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomFlyingTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomFlyingTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; @@ -17,9 +16,12 @@ /** * Extension of {@link SetRandomHoverTarget}, with a configurable weight to allow for more 'flying'-like movement - *

    Additionally expands the vertical path search radius to 10, over the default of 7

    + *

    + * Additionally expands the vertical path search radius to 10, over the default of 7 + *

    */ public class SetRandomFlyingTarget extends SetRandomHoverTarget { + protected ToIntFunction verticalWeight = entity -> -2; public SetRandomFlyingTarget() { @@ -29,6 +31,7 @@ public SetRandomFlyingTarget() { /** * Sets the function that determines a vertical position offset for target positions.
    * Flight patterns will tend towards this direction, with bigger values pulling more strongly + * * @param function The function * @return this */ @@ -42,11 +45,28 @@ public SetRandomFlyingTarget verticalWeight(ToIntFunction function) { @Override protected Vec3 getTargetPos(E entity) { Vec3 entityFacing = entity.getViewVector(0); - Vec3 hoverPos = HoverRandomPos.getPos(entity, (int)(Math.ceil(this.radius.xzRadius())), (int)Math.ceil(this.radius.yRadius()), entityFacing.x, entityFacing.z, Mth.HALF_PI, 3, 1); + Vec3 hoverPos = HoverRandomPos.getPos( + entity, + (int) (Math.ceil(this.radius.xzRadius())), + (int) Math.ceil(this.radius.yRadius()), + entityFacing.x, + entityFacing.z, + Mth.HALF_PI, + 3, + 1 + ); if (hoverPos != null) return hoverPos; - return AirAndWaterRandomPos.getPos(entity, (int)(Math.ceil(this.radius.xzRadius())), (int)Math.ceil(this.radius.yRadius()), this.verticalWeight.applyAsInt(entity), entityFacing.x, entityFacing.z, Mth.HALF_PI); + return AirAndWaterRandomPos.getPos( + entity, + (int) (Math.ceil(this.radius.xzRadius())), + (int) Math.ceil(this.radius.yRadius()), + this.verticalWeight.applyAsInt(entity), + entityFacing.x, + entityFacing.z, + Mth.HALF_PI + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomHoverTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomHoverTarget.java index 6adf5b847..9893c87e4 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomHoverTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomHoverTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; @@ -16,113 +15,145 @@ import net.minecraft.world.entity.ai.util.AirAndWaterRandomPos; import net.minecraft.world.entity.ai.util.HoverRandomPos; import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.BiFunction; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.object.SquareRadius; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Set a random position to fly to, taking into account the entity's current heading.
    * Keeps the entity roughly near ground level, encouraging hover-flight rather than floating off into the sky.
    * Defaults: *
      - *
    • 1x movespeed modifier
    • - *
    • 10-block lateral radius
    • - *
    • 7-block vertical radius
    • + *
    • 1x movespeed modifier
    • + *
    • 10-block lateral radius
    • + *
    • 7-block vertical radius
    • *
    + * * @param */ public class SetRandomHoverTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected BiFunction speedModifier = (entity, targetPos) -> 1f; - protected SquareRadius radius = new SquareRadius(10, 7); - protected BiPredicate positionPredicate = (entity, pos) -> true; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the radius in which to look for flight positions. - * @param radius The coordinate radius, in blocks - * @return this - */ - public SetRandomHoverTarget setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for flight positions. - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SetRandomHoverTarget setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param modifier The movespeed modifier/multiplier - * @return this - */ - public SetRandomHoverTarget speedModifier(float modifier) { - return speedModifier((entity, targetPos) -> modifier); - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param function The movespeed modifier/multiplier function - * @return this - */ - public SetRandomHoverTarget speedModifier(BiFunction function) { - this.speedModifier = function; - - return this; - } - - /** - * Sets a predicate to check whether the target movement position is valid or not - * @param predicate The predicate - * @return this - */ - public SetRandomHoverTarget flightTargetPredicate(BiPredicate predicate) { - this.positionPredicate = predicate; - - return this; - } - - @Override - protected void start(E entity) { - Vec3 targetPos = getTargetPos(entity); - - if (!this.positionPredicate.test(entity, targetPos)) - targetPos = null; - - if (targetPos == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0)); - } - } - - @Nullable - protected Vec3 getTargetPos(E entity) { - Vec3 entityFacing = entity.getViewVector(0); - Vec3 hoverPos = HoverRandomPos.getPos(entity, (int)(Math.ceil(this.radius.xzRadius())), (int)Math.ceil(this.radius.yRadius()), entityFacing.x, entityFacing.z, Mth.HALF_PI, 3, 1); - - if (hoverPos != null) - return hoverPos; - - return AirAndWaterRandomPos.getPos(entity, (int)(Math.ceil(this.radius.xzRadius())), (int)Math.ceil(this.radius.yRadius()), -2, entityFacing.x, entityFacing.z, Mth.HALF_PI); - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) + ); + + protected BiFunction speedModifier = (entity, targetPos) -> 1f; + + protected SquareRadius radius = new SquareRadius(10, 7); + + protected BiPredicate positionPredicate = (entity, pos) -> true; + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + /** + * Set the radius in which to look for flight positions. + * + * @param radius The coordinate radius, in blocks + * @return this + */ + public SetRandomHoverTarget setRadius(double radius) { + return setRadius(radius, radius); + } + + /** + * Set the radius in which to look for flight positions. + * + * @param xz The X/Z coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks + * @return this + */ + public SetRandomHoverTarget setRadius(double xz, double y) { + this.radius = new SquareRadius(xz, y); + + return this; + } + + /** + * Set the movespeed modifier for the path when chosen. + * + * @param modifier The movespeed modifier/multiplier + * @return this + */ + public SetRandomHoverTarget speedModifier(float modifier) { + return speedModifier((entity, targetPos) -> modifier); + } + + /** + * Set the movespeed modifier for the path when chosen. + * + * @param function The movespeed modifier/multiplier function + * @return this + */ + public SetRandomHoverTarget speedModifier(BiFunction function) { + this.speedModifier = function; + + return this; + } + + /** + * Sets a predicate to check whether the target movement position is valid or not + * + * @param predicate The predicate + * @return this + */ + public SetRandomHoverTarget flightTargetPredicate(BiPredicate predicate) { + this.positionPredicate = predicate; + + return this; + } + + @Override + protected void start(E entity) { + Vec3 targetPos = getTargetPos(entity); + + if (!this.positionPredicate.test(entity, targetPos)) + targetPos = null; + + if (targetPos == null) { + BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); + } else { + BrainUtils.setMemory( + entity, + MemoryModuleType.WALK_TARGET, + new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0) + ); + } + } + + @Nullable + protected Vec3 getTargetPos(E entity) { + Vec3 entityFacing = entity.getViewVector(0); + Vec3 hoverPos = HoverRandomPos.getPos( + entity, + (int) (Math.ceil(this.radius.xzRadius())), + (int) Math.ceil(this.radius.yRadius()), + entityFacing.x, + entityFacing.z, + Mth.HALF_PI, + 3, + 1 + ); + + if (hoverPos != null) + return hoverPos; + + return AirAndWaterRandomPos.getPos( + entity, + (int) (Math.ceil(this.radius.xzRadius())), + (int) Math.ceil(this.radius.yRadius()), + -2, + entityFacing.x, + entityFacing.z, + Mth.HALF_PI + ); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomSwimTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomSwimTarget.java index b4f27e2a7..e579e9ce2 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomSwimTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomSwimTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; @@ -14,30 +13,37 @@ import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.ai.memory.WalkTarget; import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.BiFunction; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.object.SquareRadius; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Set a random position to swim to.
    * Defaults: *
      - *
    • 1x movespeed modifier
    • - *
    • 10-block lateral radius
    • - *
    • 10-block vertical radius
    • + *
    • 1x movespeed modifier
    • + *
    • 10-block lateral radius
    • + *
    • 10-block vertical radius
    • *
    + * * @param */ public class SetRandomSwimTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) + ); protected BiFunction speedModifier = (entity, targetPos) -> 1f; + protected SquareRadius radius = new SquareRadius(10, 7); + protected BiPredicate positionPredicate = (entity, pos) -> true; @Override @@ -47,6 +53,7 @@ protected List, MemoryStatus>> getMemoryRequirements() /** * Set the radius in which to look for swim positions. + * * @param radius The coordinate radius, in blocks * @return this */ @@ -56,8 +63,9 @@ public SetRandomSwimTarget setRadius(double radius) { /** * Set the radius in which to look for swim positions. + * * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks * @return this */ public SetRandomSwimTarget setRadius(double xz, double y) { @@ -68,6 +76,7 @@ public SetRandomSwimTarget setRadius(double xz, double y) { /** * Set the movespeed modifier for the path when chosen. + * * @param modifier The movespeed modifier/multiplier * @return this */ @@ -77,6 +86,7 @@ public SetRandomSwimTarget speedModifier(float modifier) { /** * Set the movespeed modifier for the path when chosen. + * * @param function The movespeed modifier/multiplier function * @return this */ @@ -88,6 +98,7 @@ public SetRandomSwimTarget speedModifier(BiFunction function) /** * Sets a predicate to check whether the target movement position is valid or not + * * @param predicate The predicate * @return this */ @@ -106,14 +117,17 @@ protected void start(E entity) { if (targetPos == null) { BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0)); + } else { + BrainUtils.setMemory( + entity, + MemoryModuleType.WALK_TARGET, + new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0) + ); } } @Nullable protected Vec3 getTargetPos(E entity) { - return BehaviorUtils.getRandomSwimmablePos(entity, (int)this.radius.xzRadius(), (int)this.radius.yRadius()); + return BehaviorUtils.getRandomSwimmablePos(entity, (int) this.radius.xzRadius(), (int) this.radius.yRadius()); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomWalkTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomWalkTarget.java index 7a86c2deb..561844bdd 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomWalkTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomWalkTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; @@ -15,9 +14,6 @@ import net.minecraft.world.entity.ai.util.DefaultRandomPos; import net.minecraft.world.entity.ai.util.LandRandomPos; import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.object.SquareRadius; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -25,124 +21,144 @@ import java.util.function.BiPredicate; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.object.SquareRadius; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Set a random position to walk to.
    * Defaults: *
      - *
    • 1x movespeed modifier
    • - *
    • 10-block lateral radius
    • - *
    • 7-block vertical radius
    • - *
    • Avoids walk targets with fluid
    • + *
    • 1x movespeed modifier
    • + *
    • 10-block lateral radius
    • + *
    • 7-block vertical radius
    • + *
    • Avoids walk targets with fluid
    • *
    + * * @param */ public class SetRandomWalkTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected BiFunction speedModifier = (entity, targetPos) -> 1f; - protected Predicate avoidWaterPredicate = entity -> true; - protected SquareRadius radius = new SquareRadius(10, 7); - protected BiPredicate positionPredicate = (entity, pos) -> true; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the radius in which to look for walk positions. - * @param radius The coordinate radius, in blocks - * @return this - */ - public SetRandomWalkTarget setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for walk positions. - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SetRandomWalkTarget setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param modifier The movespeed modifier/multiplier - * @return this - */ - public SetRandomWalkTarget speedModifier(float modifier) { - return speedModifier((entity, targetPos) -> modifier); - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param function The movespeed modifier/multiplier function - * @return this - */ - public SetRandomWalkTarget speedModifier(BiFunction function) { - this.speedModifier = function; - - return this; - } - - /** - * Sets a predicate to check whether the target movement position is valid or not - * @param predicate The predicate - * @return this - */ - public SetRandomWalkTarget walkTargetPredicate(BiPredicate predicate) { - this.positionPredicate = predicate; - - return this; - } - - /** - * Sets the behaviour to allow finding of positions that might be in water.
    - * Useful for hybrid or water-based entities. - * @return this - */ - public SetRandomWalkTarget dontAvoidWater() { - return avoidWaterWhen(entity -> false); - } - - /** - * Set the predicate to determine when the entity should avoid water walk targets; - * @param predicate The predicate - * @return this - */ - public SetRandomWalkTarget avoidWaterWhen(Predicate predicate) { - this.avoidWaterPredicate = predicate; - - return this; - } - - @Override - protected void start(E entity) { - Vec3 targetPos = getTargetPos(entity); - - if (!this.positionPredicate.test(entity, targetPos)) - targetPos = null; - - if (targetPos == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0)); - } - } - - @Nullable - protected Vec3 getTargetPos(E entity) { - if (this.avoidWaterPredicate.test(entity)) { - return LandRandomPos.getPos(entity, (int)this.radius.xzRadius(), (int)this.radius.yRadius()); - } - else { - return DefaultRandomPos.getPos(entity, (int)this.radius.xzRadius(), (int)this.radius.yRadius()); - } - } -} \ No newline at end of file + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) + ); + + protected BiFunction speedModifier = (entity, targetPos) -> 1f; + + protected Predicate avoidWaterPredicate = entity -> true; + + protected SquareRadius radius = new SquareRadius(10, 7); + + protected BiPredicate positionPredicate = (entity, pos) -> true; + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + /** + * Set the radius in which to look for walk positions. + * + * @param radius The coordinate radius, in blocks + * @return this + */ + public SetRandomWalkTarget setRadius(double radius) { + return setRadius(radius, radius); + } + + /** + * Set the radius in which to look for walk positions. + * + * @param xz The X/Z coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks + * @return this + */ + public SetRandomWalkTarget setRadius(double xz, double y) { + this.radius = new SquareRadius(xz, y); + + return this; + } + + /** + * Set the movespeed modifier for the path when chosen. + * + * @param modifier The movespeed modifier/multiplier + * @return this + */ + public SetRandomWalkTarget speedModifier(float modifier) { + return speedModifier((entity, targetPos) -> modifier); + } + + /** + * Set the movespeed modifier for the path when chosen. + * + * @param function The movespeed modifier/multiplier function + * @return this + */ + public SetRandomWalkTarget speedModifier(BiFunction function) { + this.speedModifier = function; + + return this; + } + + /** + * Sets a predicate to check whether the target movement position is valid or not + * + * @param predicate The predicate + * @return this + */ + public SetRandomWalkTarget walkTargetPredicate(BiPredicate predicate) { + this.positionPredicate = predicate; + + return this; + } + + /** + * Sets the behaviour to allow finding of positions that might be in water.
    + * Useful for hybrid or water-based entities. + * + * @return this + */ + public SetRandomWalkTarget dontAvoidWater() { + return avoidWaterWhen(entity -> false); + } + + /** + * Set the predicate to determine when the entity should avoid water walk targets; + * + * @param predicate The predicate + * @return this + */ + public SetRandomWalkTarget avoidWaterWhen(Predicate predicate) { + this.avoidWaterPredicate = predicate; + + return this; + } + + @Override + protected void start(E entity) { + Vec3 targetPos = getTargetPos(entity); + + if (!this.positionPredicate.test(entity, targetPos)) + targetPos = null; + + if (targetPos == null) { + BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); + } else { + BrainUtils.setMemory( + entity, + MemoryModuleType.WALK_TARGET, + new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0) + ); + } + } + + @Nullable + protected Vec3 getTargetPos(E entity) { + if (this.avoidWaterPredicate.test(entity)) { + return LandRandomPos.getPos(entity, (int) this.radius.xzRadius(), (int) this.radius.yRadius()); + } else { + return DefaultRandomPos.getPos(entity, (int) this.radius.xzRadius(), (int) this.radius.yRadius()); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToAttackTarget.java index 369402c91..52f402ab9 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToAttackTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToAttackTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; @@ -16,73 +15,93 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.ai.memory.WalkTarget; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; import java.util.function.BiFunction; import java.util.function.ToIntBiFunction; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Set the walk target of the entity to its current attack target. + * * @param The entity */ public class SetWalkTargetToAttackTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT)); - - @Deprecated(forRemoval = true) - protected float speedModifier = 1; - protected BiFunction speedMod = (owner, target) -> 1f; - protected ToIntBiFunction closeEnoughWhen = (owner, target) -> 0; - - /** - * Set the movespeed modifier for the entity when moving to the target. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - @Deprecated(forRemoval = true) - public SetWalkTargetToAttackTarget speedMod(float speedModifier) { - return speedMod((owner, target) -> speedModifier); - } - - /** - * Set the movespeed modifier for the entity when moving to the target. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public SetWalkTargetToAttackTarget speedMod(BiFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Sets the amount (in blocks) that the mob can be considered 'close enough' to their target that they can stop pathfinding - * @param closeEnoughMod The distance modifier - * @return this - */ - public SetWalkTargetToAttackTarget closeEnoughDist(ToIntBiFunction closeEnoughMod) { - this.closeEnoughWhen = closeEnoughMod; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected void start(E entity) { - Brain brain = entity.getBrain(); - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - - if (entity.getSensing().hasLineOfSight(target) && BehaviorUtils.isWithinAttackRange(entity, target, 1)) { - BrainUtils.clearMemory(brain, MemoryModuleType.WALK_TARGET); - } - else { - BrainUtils.setMemory(brain, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); - BrainUtils.setMemory(brain, MemoryModuleType.WALK_TARGET, new WalkTarget(new EntityTracker(target, false), this.speedMod.apply(entity, target), this.closeEnoughWhen.applyAsInt(entity, target))); - } - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT) + ); + + @Deprecated(forRemoval = true) + protected float speedModifier = 1; + + protected BiFunction speedMod = (owner, target) -> 1f; + + protected ToIntBiFunction closeEnoughWhen = (owner, target) -> 0; + + /** + * Set the movespeed modifier for the entity when moving to the target. + * + * @param speedModifier The movespeed modifier/multiplier + * @return this + */ + @Deprecated(forRemoval = true) + public SetWalkTargetToAttackTarget speedMod(float speedModifier) { + return speedMod((owner, target) -> speedModifier); + } + + /** + * Set the movespeed modifier for the entity when moving to the target. + * + * @param speedModifier The movespeed modifier/multiplier + * @return this + */ + public SetWalkTargetToAttackTarget speedMod(BiFunction speedModifier) { + this.speedMod = speedModifier; + + return this; + } + + /** + * Sets the amount (in blocks) that the mob can be considered 'close enough' to their target that they can stop + * pathfinding + * + * @param closeEnoughMod The distance modifier + * @return this + */ + public SetWalkTargetToAttackTarget closeEnoughDist(ToIntBiFunction closeEnoughMod) { + this.closeEnoughWhen = closeEnoughMod; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + @Override + protected void start(E entity) { + Brain brain = entity.getBrain(); + LivingEntity target = BrainUtils.getTargetOfEntity(entity); + + if (entity.getSensing().hasLineOfSight(target) && BehaviorUtils.isWithinAttackRange(entity, target, 1)) { + BrainUtils.clearMemory(brain, MemoryModuleType.WALK_TARGET); + } else { + BrainUtils.setMemory(brain, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); + BrainUtils.setMemory( + brain, + MemoryModuleType.WALK_TARGET, + new WalkTarget( + new EntityTracker(target, false), + this.speedMod.apply(entity, target), + this.closeEnoughWhen.applyAsInt(entity, target) + ) + ); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToBlock.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToBlock.java index f931516e4..fac1f01ec 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToBlock.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToBlock.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; @@ -16,86 +15,104 @@ import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.ai.memory.WalkTarget; import net.minecraft.world.level.block.state.BlockState; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; import java.util.function.BiFunction; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Path setting behaviour for walking to/near a block position. + * * @param The entity */ public class SetWalkTargetToBlock extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(SBLMemoryTypes.NEARBY_BLOCKS.get(), MemoryStatus.VALUE_PRESENT)); - - protected BiPredicate> predicate = (entity, block) -> true; - protected BiFunction, Float> speedMod = (owner, pos) -> 1f; - protected BiFunction, Integer> closeEnoughDist = (entity, pos) -> 2; - - protected Pair target = null; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the predicate to determine whether a given position/state should be the target path - * @param predicate The predicate - * @return this - */ - public SetWalkTargetToBlock predicate(final BiPredicate> predicate) { - this.predicate = predicate; - - return this; - } - - /** - * Set the movespeed modifier for the entity when moving to the target. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public SetWalkTargetToBlock speedMod(BiFunction, Float> speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Set the distance (in blocks) that is 'close enough' for the entity to be considered at the target position - * @param function The function - * @return this - */ - public SetWalkTargetToBlock closeEnoughWhen(final BiFunction, Integer> function) { - this.closeEnoughDist = function; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - for (Pair position : BrainUtils.getMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get())) { - if (this.predicate.test(entity, position)) { - this.target = position; - - break; - } - } - - return this.target != null; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.target.getFirst(), this.speedMod.apply(entity, this.target), this.closeEnoughDist.apply(entity, this.target))); - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new BlockPosTracker(this.target.getFirst())); - } - - @Override - protected void stop(E entity) { - this.target = null; - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(SBLMemoryTypes.NEARBY_BLOCKS.get(), MemoryStatus.VALUE_PRESENT) + ); + + protected BiPredicate> predicate = (entity, block) -> true; + + protected BiFunction, Float> speedMod = (owner, pos) -> 1f; + + protected BiFunction, Integer> closeEnoughDist = (entity, pos) -> 2; + + protected Pair target = null; + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + /** + * Set the predicate to determine whether a given position/state should be the target path + * + * @param predicate The predicate + * @return this + */ + public SetWalkTargetToBlock predicate(final BiPredicate> predicate) { + this.predicate = predicate; + + return this; + } + + /** + * Set the movespeed modifier for the entity when moving to the target. + * + * @param speedModifier The movespeed modifier/multiplier + * @return this + */ + public SetWalkTargetToBlock speedMod(BiFunction, Float> speedModifier) { + this.speedMod = speedModifier; + + return this; + } + + /** + * Set the distance (in blocks) that is 'close enough' for the entity to be considered at the target position + * + * @param function The function + * @return this + */ + public SetWalkTargetToBlock closeEnoughWhen(final BiFunction, Integer> function) { + this.closeEnoughDist = function; + + return this; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + for (Pair position : BrainUtils.getMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get())) { + if (this.predicate.test(entity, position)) { + this.target = position; + + break; + } + } + + return this.target != null; + } + + @Override + protected void start(E entity) { + BrainUtils.setMemory( + entity, + MemoryModuleType.WALK_TARGET, + new WalkTarget( + this.target.getFirst(), + this.speedMod.apply(entity, this.target), + this.closeEnoughDist.apply(entity, this.target) + ) + ); + BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new BlockPosTracker(this.target.getFirst())); + } + + @Override + protected void stop(E entity) { + this.target = null; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/InvalidateAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/InvalidateAttackTarget.java index 69a084f6b..bf7192cbc 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/InvalidateAttackTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/InvalidateAttackTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; @@ -12,87 +11,96 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Invalidates the current {@link MemoryModuleType#ATTACK_TARGET attack target} if the given conditions are met.
    * Defaults: *
      - *
    • Will give up trying to path to the target if it hasn't been able to reach it in 200 ticks
    • - *
    • Invalidates the target if it's a creative or spectator mode player
    • + *
    • Will give up trying to path to the target if it hasn't been able to reach it in 200 ticks
    • + *
    • Invalidates the target if it's a creative or spectator mode player
    • *
    */ public class InvalidateAttackTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.REGISTERED)); - - protected BiPredicate customPredicate = (entity, target) -> target instanceof Player pl && (pl.isCreative() || pl.isSpectator()); - protected long pathfindingAttentionSpan = 200; - - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Sets a custom predicate to invalidate the attack target if none of the previous checks invalidate it first.
    - * Overrides the default player gamemode check - */ - public InvalidateAttackTarget invalidateIf(BiPredicate predicate) { - this.customPredicate = predicate; - - return this; - } - - /** - * Skips the check to see if the entity has been unable to path to its target for a while - */ - public InvalidateAttackTarget ignoreFailedPathfinding() { - return stopTryingToPathAfter(0); - } - - /** - * Sets the attention span for the brain owner's pathfinding. If the entity has been unable to find a good path to - * the target after this time, it will invalidate the target. - */ - public InvalidateAttackTarget stopTryingToPathAfter(long ticks) { - this.pathfindingAttentionSpan = ticks; - - return this; - } - - @Override - protected void start(E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - - if (target == null) - return; - - if (isTargetInvalid(entity, target) || !canAttack(entity, target) || - isTiredOfPathing(entity) || this.customPredicate.test(entity, target)) { - BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } - } - - protected boolean isTargetInvalid(E entity, LivingEntity target) { - if (entity.level() != target.level()) - return true; - - return target.isDeadOrDying() || target.isRemoved(); - } - - protected boolean canAttack(E entity, LivingEntity target) { - return entity.canAttack(target); - } - - protected boolean isTiredOfPathing(E entity) { - if (this.pathfindingAttentionSpan <= 0) - return false; - - Long time = BrainUtils.getMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - return time != null && entity.level().getGameTime() - time > this.pathfindingAttentionSpan; - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), + Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.REGISTERED) + ); + + protected BiPredicate customPredicate = (entity, target) -> target instanceof Player pl && (pl + .isCreative() || pl.isSpectator()); + + protected long pathfindingAttentionSpan = 200; + + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + /** + * Sets a custom predicate to invalidate the attack target if none of the previous checks invalidate it first.
    + * Overrides the default player gamemode check + */ + public InvalidateAttackTarget invalidateIf(BiPredicate predicate) { + this.customPredicate = predicate; + + return this; + } + + /** + * Skips the check to see if the entity has been unable to path to its target for a while + */ + public InvalidateAttackTarget ignoreFailedPathfinding() { + return stopTryingToPathAfter(0); + } + + /** + * Sets the attention span for the brain owner's pathfinding. If the entity has been unable to find a good path to + * the target after this time, it will invalidate the target. + */ + public InvalidateAttackTarget stopTryingToPathAfter(long ticks) { + this.pathfindingAttentionSpan = ticks; + + return this; + } + + @Override + protected void start(E entity) { + LivingEntity target = BrainUtils.getTargetOfEntity(entity); + + if (target == null) + return; + + if ( + isTargetInvalid(entity, target) || !canAttack(entity, target) || + isTiredOfPathing(entity) || this.customPredicate.test(entity, target) + ) { + BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); + } + } + + protected boolean isTargetInvalid(E entity, LivingEntity target) { + if (entity.level() != target.level()) + return true; + + return target.isDeadOrDying() || target.isRemoved(); + } + + protected boolean canAttack(E entity, LivingEntity target) { + return entity.canAttack(target); + } + + protected boolean isTiredOfPathing(E entity) { + if (this.pathfindingAttentionSpan <= 0) + return false; + + Long time = BrainUtils.getMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); + + return time != null && entity.level().getGameTime() - time > this.pathfindingAttentionSpan; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAdditionalAttackTargets.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAdditionalAttackTargets.java index 4ddf6f4ba..11eec504e 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAdditionalAttackTargets.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAdditionalAttackTargets.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; @@ -16,122 +15,152 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.TriPredicate; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.apache.logging.log4j.util.TriConsumer; import java.util.Iterator; import java.util.List; import java.util.Set; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.object.TriPredicate; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Special-case behaviour for setting secondary, tertiary, etc attack targets.
    - * This is useful for entities that concurrently target multiple entities, and use additional memory modules to store the additional targets.
    - * Uses {@link MemoryModuleType#NEAREST_PLAYERS} and {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} for its retrieval of additional targets.
    - * This behaviour will skip the usual pathing and alerting functionality as it is assumed they will be handled under the primary target.
    + * This is useful for entities that concurrently target multiple entities, and use additional memory modules to store + * the additional targets.
    + * Uses {@link MemoryModuleType#NEAREST_PLAYERS} and {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} for its + * retrieval of additional targets.
    + * This behaviour will skip the usual pathing and alerting functionality as it is assumed they will be handled under the + * primary target.
    *
    * Defaults:
    *
      - *
    • Will target any not-invulnerable player
    • - *
    • Avoids setting memories if a previous memory in the list is already set to the same target, and including {@link MemoryModuleType#ATTACK_TARGET}
    • + *
    • Will target any not-invulnerable player
    • + *
    • Avoids setting memories if a previous memory in the list is already set to the same target, and including + * {@link MemoryModuleType#ATTACK_TARGET}
    • *
    */ public class SetAdditionalAttackTargets extends ExtendedBehaviour { - private final List> targetingMemories = new ObjectArrayList<>(); - - protected TriPredicate, LivingEntity> canAttackPredicate = (owner, memory, target) -> target.isAlive() && target instanceof Player player && !player.getAbilities().invulnerable; - protected TriConsumer, LivingEntity> targetCallback = (owner, memory, target) -> {}; - protected boolean avoidDuplicateTargets = true; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - /** - * Set the predicate to determine whether a given entity should be targeted or not. - * @param predicate The predicate - * @return this - */ - public SetAdditionalAttackTargets attackablePredicate(TriPredicate, LivingEntity> predicate) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Sets the callback for when a target is being successfully set to a memory. - */ - public SetAdditionalAttackTargets whenTargeting(TriConsumer, LivingEntity> callback) { - this.targetCallback = callback; - - return this; - } - - /** - * Add {@link MemoryModuleType memories} to the list of tertiary memories to set targets for.
    - * This appends to any existing memories already added to this behaviour, and the functionality of this behaviour is order-dependent. - */ - public SetAdditionalAttackTargets withMemories(MemoryModuleType... targetMemories) { - this.targetingMemories.addAll(List.of(targetMemories)); - - return this; - } - - /** - * Allow for the tertiary target memories to be set to the same as the previous modules if no new target is available - */ - public SetAdditionalAttackTargets allowDuplicateTargeting() { - this.avoidDuplicateTargets = false; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - - for (MemoryModuleType memory : this.targetingMemories) { - if (!BrainUtils.hasMemory(brain, memory)) - return true; - } - - return BrainUtils.hasMemory(brain, MemoryModuleType.NEAREST_PLAYERS) || BrainUtils.hasMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); - } - - @Override - protected void start(E entity) { - Brain brain = entity.getBrain(); - Set targetPool = new ObjectOpenHashSet<>(); - - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_PLAYERS, targetPool::addAll); - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, memory -> memory.findAll(target -> true).forEach(targetPool::add)); - - if (targetPool.isEmpty()) - return; - - for (MemoryModuleType memory : this.targetingMemories) { - LivingEntity target = BrainUtils.getMemory(brain, memory); - - if (target == null) { - LivingEntity newTarget = null; - - for (Iterator iterator = targetPool.iterator(); iterator.hasNext(); newTarget = null) { - newTarget = iterator.next(); - - if (this.canAttackPredicate.test(entity, memory, newTarget)) { - BrainUtils.setMemory(brain, (MemoryModuleType)memory, newTarget); - this.targetCallback.accept(entity, memory, newTarget); - iterator.remove(); - - break; - } - } - - if (newTarget != null && !this.avoidDuplicateTargets) - targetPool.add(newTarget); - } - } - } + + private final List> targetingMemories = new ObjectArrayList<>(); + + protected TriPredicate, LivingEntity> canAttackPredicate = ( + owner, + memory, + target + ) -> target.isAlive() && target instanceof Player player && !player.getAbilities().invulnerable; + + protected TriConsumer, LivingEntity> targetCallback = ( + owner, + memory, + target + ) -> {}; + + protected boolean avoidDuplicateTargets = true; + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return List.of(); + } + + /** + * Set the predicate to determine whether a given entity should be targeted or not. + * + * @param predicate The predicate + * @return this + */ + public SetAdditionalAttackTargets attackablePredicate( + TriPredicate, LivingEntity> predicate + ) { + this.canAttackPredicate = predicate; + + return this; + } + + /** + * Sets the callback for when a target is being successfully set to a memory. + */ + public SetAdditionalAttackTargets whenTargeting( + TriConsumer, LivingEntity> callback + ) { + this.targetCallback = callback; + + return this; + } + + /** + * Add {@link MemoryModuleType memories} to the list of tertiary memories to set targets for.
    + * This appends to any existing memories already added to this behaviour, and the functionality of this behaviour is + * order-dependent. + */ + public SetAdditionalAttackTargets withMemories(MemoryModuleType... targetMemories) { + this.targetingMemories.addAll(List.of(targetMemories)); + + return this; + } + + /** + * Allow for the tertiary target memories to be set to the same as the previous modules if no new target is + * available + */ + public SetAdditionalAttackTargets allowDuplicateTargeting() { + this.avoidDuplicateTargets = false; + + return this; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + Brain brain = entity.getBrain(); + + for (MemoryModuleType memory : this.targetingMemories) { + if (!BrainUtils.hasMemory(brain, memory)) + return true; + } + + return BrainUtils.hasMemory(brain, MemoryModuleType.NEAREST_PLAYERS) || BrainUtils.hasMemory( + brain, + MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES + ); + } + + @Override + protected void start(E entity) { + Brain brain = entity.getBrain(); + Set targetPool = new ObjectOpenHashSet<>(); + + BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_PLAYERS, targetPool::addAll); + BrainUtils.withMemory( + brain, + MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, + memory -> memory.findAll(target -> true).forEach(targetPool::add) + ); + + if (targetPool.isEmpty()) + return; + + for (MemoryModuleType memory : this.targetingMemories) { + LivingEntity target = BrainUtils.getMemory(brain, memory); + + if (target == null) { + LivingEntity newTarget = null; + + for (Iterator iterator = targetPool.iterator(); iterator.hasNext(); newTarget = null) { + newTarget = iterator.next(); + + if (this.canAttackPredicate.test(entity, memory, newTarget)) { + BrainUtils.setMemory(brain, (MemoryModuleType) memory, newTarget); + this.targetCallback.accept(entity, memory, newTarget); + iterator.remove(); + + break; + } + } + + if (newTarget != null && !this.avoidDuplicateTargets) + targetPool.add(newTarget); + } + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAttackTarget.java index 58c526ea2..ec9f29572 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAttackTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAttackTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; @@ -12,79 +11,94 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Sets the attack target of the entity if one is available.
    * Defaults: *
      - *
    • Will target anything set as the {@link MemoryModuleType#NEAREST_ATTACKABLE} memory
    • + *
    • Will target anything set as the {@link MemoryModuleType#NEAREST_ATTACKABLE} memory
    • *
    + * * @see net.minecraft.world.entity.ai.behavior.StartAttacking */ public class SetAttackTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.NEAREST_ATTACKABLE, MemoryStatus.VALUE_PRESENT)); - private static final List, MemoryStatus>> CUSTOM_TARGETING_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected final boolean usingNearestAttackable; - protected Predicate canAttackPredicate = entity -> true; - protected Function targetFinder = entity -> BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE); - - public SetAttackTarget() { - this(true); - } - - public SetAttackTarget(boolean usingNearestAttackable) { - this.usingNearestAttackable = usingNearestAttackable; - } - - /** - * Set the predicate to determine whether the entity is ready to attack or not. - * @param predicate The predicate - * @return this - */ - public SetAttackTarget attackPredicate(Predicate predicate) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Set the target finding function. If replacing the {@link MemoryModuleType#NEAREST_ATTACKABLE} memory retrieval, set false in the constructor of the behaviour. - * @param targetFindingFunction The function - * @return this - */ - public SetAttackTarget targetFinder(Function targetFindingFunction) { - this.targetFinder = targetFindingFunction; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return this.usingNearestAttackable ? MEMORY_REQUIREMENTS : CUSTOM_TARGETING_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return this.canAttackPredicate.test(entity); - } - - @Override - protected void start(E entity) { - LivingEntity target = this.targetFinder.apply(entity); - - if (target == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.ATTACK_TARGET, target); - BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - } - } + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), + Pair.of(MemoryModuleType.NEAREST_ATTACKABLE, MemoryStatus.VALUE_PRESENT) + ); + + private static final List, MemoryStatus>> CUSTOM_TARGETING_REQUIREMENTS = ObjectArrayList + .of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT)); + + protected final boolean usingNearestAttackable; + + protected Predicate canAttackPredicate = entity -> true; + + protected Function targetFinder = entity -> BrainUtils.getMemory( + entity, + MemoryModuleType.NEAREST_ATTACKABLE + ); + + public SetAttackTarget() { + this(true); + } + + public SetAttackTarget(boolean usingNearestAttackable) { + this.usingNearestAttackable = usingNearestAttackable; + } + + /** + * Set the predicate to determine whether the entity is ready to attack or not. + * + * @param predicate The predicate + * @return this + */ + public SetAttackTarget attackPredicate(Predicate predicate) { + this.canAttackPredicate = predicate; + + return this; + } + + /** + * Set the target finding function. If replacing the {@link MemoryModuleType#NEAREST_ATTACKABLE} memory retrieval, + * set false in the constructor of the behaviour. + * + * @param targetFindingFunction The function + * @return this + */ + public SetAttackTarget targetFinder(Function targetFindingFunction) { + this.targetFinder = targetFindingFunction; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return this.usingNearestAttackable ? MEMORY_REQUIREMENTS : CUSTOM_TARGETING_REQUIREMENTS; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + return this.canAttackPredicate.test(entity); + } + + @Override + protected void start(E entity) { + LivingEntity target = this.targetFinder.apply(entity); + + if (target == null) { + BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); + } else { + BrainUtils.setMemory(entity, MemoryModuleType.ATTACK_TARGET, target); + BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetPlayerLookTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetPlayerLookTarget.java index 7c59a63fb..59348cb7c 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetPlayerLookTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetPlayerLookTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; @@ -14,59 +13,66 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Set the {@link MemoryModuleType#LOOK_TARGET} of the brain owner from {@link MemoryModuleType#NEAREST_PLAYERS} + * * @param The entity */ public class SetPlayerLookTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.NEAREST_PLAYERS, MemoryStatus.VALUE_PRESENT)); - protected Predicate predicate = pl -> true; + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT), + Pair.of(MemoryModuleType.NEAREST_PLAYERS, MemoryStatus.VALUE_PRESENT) + ); + + protected Predicate predicate = pl -> true; - protected Player target = null; + protected Player target = null; - /** - * Set the predicate for the player to look at. - * @param predicate The predicate - * @return this - */ - public SetPlayerLookTarget predicate(Predicate predicate) { - this.predicate = predicate; + /** + * Set the predicate for the player to look at. + * + * @param predicate The predicate + * @return this + */ + public SetPlayerLookTarget predicate(Predicate predicate) { + this.predicate = predicate; - return this; - } + return this; + } - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - for (Player player : BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_PLAYERS)) { - if (this.predicate.test(player)) { - this.target = player; + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + for (Player player : BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_PLAYERS)) { + if (this.predicate.test(player)) { + this.target = player; - break; - } - } + break; + } + } - return this.target != null; - } + return this.target != null; + } - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(this.target, true)); - } + @Override + protected void start(E entity) { + BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(this.target, true)); + } - @Override - protected void stop(E entity) { - this.target = null; - } + @Override + protected void stop(E entity) { + this.target = null; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRandomLookTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRandomLookTarget.java index b5a58c917..652997b99 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRandomLookTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRandomLookTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; @@ -15,59 +14,72 @@ import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.object.FreePositionTracker; import java.util.List; import java.util.function.Function; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.object.FreePositionTracker; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** * Set the look target to a random nearby position + * * @param The entity */ public class SetRandomLookTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORIES = ObjectArrayList.of(Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT)); - protected FloatProvider runChance = ConstantFloat.of(0.02f); - protected Function lookTime = entity -> entity.getRandom().nextInt(20) + 20; + private static final List, MemoryStatus>> MEMORIES = ObjectArrayList.of( + Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT) + ); + + protected FloatProvider runChance = ConstantFloat.of(0.02f); + + protected Function lookTime = entity -> entity.getRandom().nextInt(20) + 20; - /** - * Set the value provider for the chance of the look target being set. - * @param chance The float provider - * @return this - */ - public SetRandomLookTarget lookChance(FloatProvider chance) { - this.runChance = chance; + /** + * Set the value provider for the chance of the look target being set. + * + * @param chance The float provider + * @return this + */ + public SetRandomLookTarget lookChance(FloatProvider chance) { + this.runChance = chance; - return this; - } + return this; + } - /** - * Set the value provider for how long the entity's look target should be set for - * @param function The tick providing function - * @return this - */ - public SetRandomLookTarget lookTime(Function function) { - this.lookTime = function; + /** + * Set the value provider for how long the entity's look target should be set for + * + * @param function The tick providing function + * @return this + */ + public SetRandomLookTarget lookTime(Function function) { + this.lookTime = function; - return this; - } + return this; + } - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return entity.getRandom().nextFloat() < this.runChance.sample(entity.getRandom()); - } + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E entity) { + return entity.getRandom().nextFloat() < this.runChance.sample(entity.getRandom()); + } - @Override - protected void start(E entity) { - double angle = Mth.TWO_PI * entity.getRandom().nextDouble(); + @Override + protected void start(E entity) { + double angle = Mth.TWO_PI * entity.getRandom().nextDouble(); - BrainUtils.setForgettableMemory(entity, MemoryModuleType.LOOK_TARGET, new FreePositionTracker(entity.getEyePosition().add(Math.cos(angle), 0, Math.sin(angle))), this.lookTime.apply(entity)); - } + BrainUtils.setForgettableMemory( + entity, + MemoryModuleType.LOOK_TARGET, + new FreePositionTracker(entity.getEyePosition().add(Math.cos(angle), 0, Math.sin(angle))), + this.lookTime.apply(entity) + ); + } - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORIES; - } + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORIES; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRetaliateTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRetaliateTarget.java index 0967202df..5205980fd 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRetaliateTarget.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRetaliateTarget.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; @@ -16,100 +15,126 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; import java.util.List; import java.util.function.BiPredicate; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; +import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; + /** * Sets the attack target of the entity based on the last entity to hurt it if a target isn't already set.
    * Defaults: *
      - *
    • Targets any live entity, as long as it's not a creative mode player
    • - *
    • Does not alert nearby allies when retaliating
    • - *
    • If enabled, only alerts allies of the same class, if they don't already have a target themselves
    • + *
    • Targets any live entity, as long as it's not a creative mode player
    • + *
    • Does not alert nearby allies when retaliating
    • + *
    • If enabled, only alerts allies of the same class, if they don't already have a target themselves
    • *
    + * * @param The entity */ public class SetRetaliateTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.HURT_BY_ENTITY, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected Predicate canAttackPredicate = entity -> entity.isAlive() && (!(entity instanceof Player player) || !player.isCreative()); - - protected LivingEntity toTarget = null; - protected BiPredicate alertAlliesPredicate = (owner, attacker) -> false; - protected BiPredicate allyPredicate = (owner, ally) -> owner.getClass().isAssignableFrom(ally.getClass()) && BrainUtils.getTargetOfEntity(ally) == null && (!(owner instanceof TamableAnimal pet) || pet.getOwner() == ((TamableAnimal)ally).getOwner()) && !ally.isAlliedTo(BrainUtils.getMemory(owner, MemoryModuleType.HURT_BY_ENTITY)); - - /** - * Set the predicate to determine whether a given entity should be targeted or not. - * @param predicate The predicate - * @return this - */ - public SetRetaliateTarget attackablePredicate(Predicate predicate) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Set the predicate to determine whether the brain owner should alert nearby allies of the same entity type when retaliating - * @param predicate The predicate - * @return this - */ - public SetRetaliateTarget alertAlliesWhen(BiPredicate predicate) { - this.alertAlliesPredicate = predicate; - - return this; - } - - /** - * Set the predicate to determine whether a given entity should be alerted to the target as an ally of the brain owner.
    - * Overriding replaces the default predicate, so be sure to include any portions of the default predicate in your own if applicable - * @param predicate The predicate - * @return this - */ - public SetRetaliateTarget isAllyIf(BiPredicate predicate) { - this.allyPredicate = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E owner) { - this.toTarget = BrainUtils.getMemory(owner, MemoryModuleType.HURT_BY_ENTITY); - - if (this.toTarget.isAlive() && this.toTarget.level() == level && this.canAttackPredicate.test(this.toTarget)) { - if (this.alertAlliesPredicate.test(owner, this.toTarget)) - alertAllies(level, owner); - - return true; - } - - return false; - } - - @Override - protected void start(E entity) { - BrainUtils.setTargetOfEntity(entity, this.toTarget); - BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - this.toTarget = null; - } - - protected void alertAllies(ServerLevel level, E owner) { - double followRange = owner.getAttributeValue(Attributes.FOLLOW_RANGE); - - for (LivingEntity ally : EntityRetrievalUtil.getEntities(level, owner.getBoundingBox().inflate(followRange, 10, followRange), - entity -> entity != owner && entity instanceof LivingEntity livingEntity && this.allyPredicate.test(owner, livingEntity))) { - BrainUtils.setTargetOfEntity(ally, this.toTarget); - } - } -} \ No newline at end of file + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.HURT_BY_ENTITY, MemoryStatus.VALUE_PRESENT), + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT) + ); + + protected Predicate canAttackPredicate = entity -> entity.isAlive() + && (!(entity instanceof Player player) || !player.isCreative()); + + protected LivingEntity toTarget = null; + + protected BiPredicate alertAlliesPredicate = (owner, attacker) -> false; + + protected BiPredicate allyPredicate = (owner, ally) -> owner.getClass() + .isAssignableFrom(ally.getClass()) && BrainUtils.getTargetOfEntity(ally) == null + && (!(owner instanceof TamableAnimal pet) || pet.getOwner() == ((TamableAnimal) ally).getOwner()) && !ally + .isAlliedTo(BrainUtils.getMemory(owner, MemoryModuleType.HURT_BY_ENTITY)); + + /** + * Set the predicate to determine whether a given entity should be targeted or not. + * + * @param predicate The predicate + * @return this + */ + public SetRetaliateTarget attackablePredicate(Predicate predicate) { + this.canAttackPredicate = predicate; + + return this; + } + + /** + * Set the predicate to determine whether the brain owner should alert nearby allies of the same entity type when + * retaliating + * + * @param predicate The predicate + * @return this + */ + public SetRetaliateTarget alertAlliesWhen(BiPredicate predicate) { + this.alertAlliesPredicate = predicate; + + return this; + } + + /** + * Set the predicate to determine whether a given entity should be alerted to the target as an ally of the brain + * owner.
    + * Overriding replaces the default predicate, so be sure to include any portions of the default predicate in your + * own if applicable + * + * @param predicate The predicate + * @return this + */ + public SetRetaliateTarget isAllyIf(BiPredicate predicate) { + this.allyPredicate = predicate; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E owner) { + this.toTarget = BrainUtils.getMemory(owner, MemoryModuleType.HURT_BY_ENTITY); + + if (this.toTarget.isAlive() && this.toTarget.level() == level && this.canAttackPredicate.test(this.toTarget)) { + if (this.alertAlliesPredicate.test(owner, this.toTarget)) + alertAllies(level, owner); + + return true; + } + + return false; + } + + @Override + protected void start(E entity) { + BrainUtils.setTargetOfEntity(entity, this.toTarget); + BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); + + this.toTarget = null; + } + + protected void alertAllies(ServerLevel level, E owner) { + double followRange = owner.getAttributeValue(Attributes.FOLLOW_RANGE); + + for ( + LivingEntity ally : EntityRetrievalUtil.getEntities( + level, + owner.getBoundingBox().inflate(followRange, 10, followRange), + entity -> entity != owner && entity instanceof LivingEntity livingEntity && this.allyPredicate.test( + owner, + livingEntity + ) + ) + ) { + BrainUtils.setTargetOfEntity(ally, this.toTarget); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/TargetOrRetaliate.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/TargetOrRetaliate.java index 68fc2aeed..3148ee11e 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/TargetOrRetaliate.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/TargetOrRetaliate.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; @@ -16,142 +15,171 @@ import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; import java.util.List; import java.util.function.BiPredicate; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; +import mod.azure.azurelib.sblforked.util.BrainUtils; +import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; + /** * Sets the attack target of the entity, utilising a few sources of targets.
    * In order: *
      - *
    1. The {@link MemoryModuleType#NEAREST_ATTACKABLE} memory value
    2. - *
    3. The {@link MemoryModuleType#HURT_BY_ENTITY} memory value
    4. - *
    5. The closest applicable entity from the {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory value
    6. + *
    7. The {@link MemoryModuleType#NEAREST_ATTACKABLE} memory value
    8. + *
    9. The {@link MemoryModuleType#HURT_BY_ENTITY} memory value
    10. + *
    11. The closest applicable entity from the {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory value
    12. *
    * Defaults: *
      - *
    • Targets any live entity, as long as it's not a creative-mode player
    • - *
    • Does not alert nearby allies when retaliating
    • - *
    • If enabled, only alerts allies of the same class, if they don't already have a target themselves
    • + *
    • Targets any live entity, as long as it's not a creative-mode player
    • + *
    • Does not alert nearby allies when retaliating
    • + *
    • If enabled, only alerts allies of the same class, if they don't already have a target themselves
    • *
    + * * @param The entity */ public class TargetOrRetaliate extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.HURT_BY, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.NEAREST_ATTACKABLE, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.REGISTERED)); - - protected Predicate canAttackPredicate = entity -> entity.isAlive() && (!(entity instanceof Player player) || !player.isCreative()); - protected BiPredicate alertAlliesPredicate = (owner, attacker) -> false; - protected BiPredicate allyPredicate = (owner, ally) -> { - if (!owner.getClass().isAssignableFrom(ally.getClass()) || BrainUtils.getTargetOfEntity(ally) != null) - return false; - - if (owner instanceof OwnableEntity pet && pet.getOwner() != ((OwnableEntity)ally).getOwner()) - return false; - - Entity lastHurtBy = BrainUtils.getMemory(ally, MemoryModuleType.HURT_BY_ENTITY); - - return lastHurtBy == null || !ally.isAlliedTo(lastHurtBy); - }; - - protected LivingEntity toTarget = null; - protected MemoryModuleType priorityTargetMemory = MemoryModuleType.NEAREST_ATTACKABLE; - - /** - * Set the predicate to determine whether a given entity should be targeted or not. - * @param predicate The predicate - * @return this - */ - public TargetOrRetaliate attackablePredicate(Predicate predicate) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Set the memory type that is checked first to target an entity. - * Useful for switching to player-only targeting - * @return this - */ - public TargetOrRetaliate useMemory(MemoryModuleType memory) { - this.priorityTargetMemory = memory; - - return this; - } - - /** - * Set the predicate to determine whether the brain owner should alert nearby allies of the same entity type when retaliating - * @param predicate The predicate - * @return this - */ - public TargetOrRetaliate alertAlliesWhen(BiPredicate predicate) { - this.alertAlliesPredicate = predicate; - - return this; - } - - /** - * Set the predicate to determine whether a given entity should be alerted to the target as an ally of the brain owner.
    - * Overriding replaces the default predicate, so be sure to include any portions of the default predicate in your own if applicable - * @param predicate The predicate - * @return this - */ - public TargetOrRetaliate isAllyIf(BiPredicate predicate) { - this.allyPredicate = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E owner) { - Brain brain = owner.getBrain(); - this.toTarget = BrainUtils.getMemory(brain, this.priorityTargetMemory); - - if (this.toTarget == null) { - this.toTarget = BrainUtils.getMemory(brain, MemoryModuleType.HURT_BY_ENTITY); - - if (this.toTarget == null) { - NearestVisibleLivingEntities nearbyEntities = BrainUtils.getMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); - - if (nearbyEntities != null) - this.toTarget = nearbyEntities.findClosest(this.canAttackPredicate).orElse(null); - - if (this.alertAlliesPredicate.test(owner, this.toTarget)) - alertAllies(level, owner); - - if (this.toTarget == null) - return false; - } - } - - if (this.alertAlliesPredicate.test(owner, this.toTarget)) - alertAllies(level, owner); - - return this.canAttackPredicate.test(this.toTarget); - } - - @Override - protected void start(E entity) { - BrainUtils.setTargetOfEntity(entity, this.toTarget); - BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - this.toTarget = null; - } - - protected void alertAllies(ServerLevel level, E owner) { - double followRange = owner.getAttributeValue(Attributes.FOLLOW_RANGE); - - for (LivingEntity ally : EntityRetrievalUtil.getEntities(level, owner.getBoundingBox().inflate(followRange, 10, followRange), - entity -> entity != owner && entity instanceof LivingEntity livingEntity && this.allyPredicate.test(owner, livingEntity))) { - BrainUtils.setTargetOfEntity(ally, this.toTarget); - } - } -} \ No newline at end of file + + private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( + Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), + Pair.of(MemoryModuleType.HURT_BY, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.NEAREST_ATTACKABLE, MemoryStatus.REGISTERED), + Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.REGISTERED) + ); + + protected Predicate canAttackPredicate = entity -> entity.isAlive() + && (!(entity instanceof Player player) || !player.isCreative()); + + protected BiPredicate alertAlliesPredicate = (owner, attacker) -> false; + + protected BiPredicate allyPredicate = (owner, ally) -> { + if (!owner.getClass().isAssignableFrom(ally.getClass()) || BrainUtils.getTargetOfEntity(ally) != null) + return false; + + if (owner instanceof OwnableEntity pet && pet.getOwner() != ((OwnableEntity) ally).getOwner()) + return false; + + Entity lastHurtBy = BrainUtils.getMemory(ally, MemoryModuleType.HURT_BY_ENTITY); + + return lastHurtBy == null || !ally.isAlliedTo(lastHurtBy); + }; + + protected LivingEntity toTarget = null; + + protected MemoryModuleType priorityTargetMemory = MemoryModuleType.NEAREST_ATTACKABLE; + + /** + * Set the predicate to determine whether a given entity should be targeted or not. + * + * @param predicate The predicate + * @return this + */ + public TargetOrRetaliate attackablePredicate(Predicate predicate) { + this.canAttackPredicate = predicate; + + return this; + } + + /** + * Set the memory type that is checked first to target an entity. Useful for switching to player-only targeting + * + * @return this + */ + public TargetOrRetaliate useMemory(MemoryModuleType memory) { + this.priorityTargetMemory = memory; + + return this; + } + + /** + * Set the predicate to determine whether the brain owner should alert nearby allies of the same entity type when + * retaliating + * + * @param predicate The predicate + * @return this + */ + public TargetOrRetaliate alertAlliesWhen(BiPredicate predicate) { + this.alertAlliesPredicate = predicate; + + return this; + } + + /** + * Set the predicate to determine whether a given entity should be alerted to the target as an ally of the brain + * owner.
    + * Overriding replaces the default predicate, so be sure to include any portions of the default predicate in your + * own if applicable + * + * @param predicate The predicate + * @return this + */ + public TargetOrRetaliate isAllyIf(BiPredicate predicate) { + this.allyPredicate = predicate; + + return this; + } + + @Override + protected List, MemoryStatus>> getMemoryRequirements() { + return MEMORY_REQUIREMENTS; + } + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, E owner) { + Brain brain = owner.getBrain(); + this.toTarget = BrainUtils.getMemory(brain, this.priorityTargetMemory); + + if (this.toTarget == null) { + this.toTarget = BrainUtils.getMemory(brain, MemoryModuleType.HURT_BY_ENTITY); + + if (this.toTarget == null) { + NearestVisibleLivingEntities nearbyEntities = BrainUtils.getMemory( + brain, + MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES + ); + + if (nearbyEntities != null) + this.toTarget = nearbyEntities.findClosest(this.canAttackPredicate).orElse(null); + + if (this.alertAlliesPredicate.test(owner, this.toTarget)) + alertAllies(level, owner); + + if (this.toTarget == null) + return false; + } + } + + if (this.alertAlliesPredicate.test(owner, this.toTarget)) + alertAllies(level, owner); + + return this.canAttackPredicate.test(this.toTarget); + } + + @Override + protected void start(E entity) { + BrainUtils.setTargetOfEntity(entity, this.toTarget); + BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); + + this.toTarget = null; + } + + protected void alertAllies(ServerLevel level, E owner) { + double followRange = owner.getAttributeValue(Attributes.FOLLOW_RANGE); + + for ( + LivingEntity ally : EntityRetrievalUtil.getEntities( + level, + owner.getBoundingBox().inflate(followRange, 10, followRange), + entity -> entity != owner && entity instanceof LivingEntity livingEntity && this.allyPredicate.test( + owner, + livingEntity + ) + ) + ) { + BrainUtils.setTargetOfEntity(ally, this.toTarget); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/ExtendedNavigator.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/ExtendedNavigator.java index fe5b48f79..637ccc170 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/ExtendedNavigator.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/ExtendedNavigator.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.navigation; @@ -24,9 +23,11 @@ /** * Extracted interface to act as a helper utility for cleaner navigator implementations *

    - * This expands on Vanilla's navigator functionality, fixing some issues, optimising it, and splitting it out to be properly extensible + * This expands on Vanilla's navigator functionality, fixing some issues, optimising it, and splitting it out to be + * properly extensible */ public interface ExtendedNavigator { + /** * Minimum threshold representing a rounding error for the purposes of bounds collision */ @@ -63,7 +64,8 @@ default boolean canPathInto(PathType pathType) { } /** - * Determine whether the entity should be considered close enough to the next node to be counted as having reached it + * Determine whether the entity should be considered close enough to the next node to be counted as having reached + * it * * @param distance The distance threshold which counts as 'close enough' to the next node * @return Whether the entity is within reach of the next node in the path @@ -75,12 +77,13 @@ default boolean isCloseToNextNode(float distance) { final Vec3 nextNodePos = getEntityPosAtNode(path.getNextNodeIndex()); return Math.abs(mob.getX() - nextNodePos.x) < distance && - Math.abs(mob.getZ() - nextNodePos.z) < distance && - Math.abs(mob.getY() - nextNodePos.y) < 1; + Math.abs(mob.getZ() - nextNodePos.z) < distance && + Math.abs(mob.getY() - nextNodePos.y) < 1; } /** - * @return Whether the path the mob is following is about to cause a change in elevation (either up or down), accounting for potentially skippable nodes based on the entity's stride size + * @return Whether the path the mob is following is about to cause a change in elevation (either up or down), + * accounting for potentially skippable nodes based on the entity's stride size */ default boolean isAboutToTraverseVertically() { final Mob mob = getMob(); @@ -98,13 +101,15 @@ default boolean isAboutToTraverseVertically() { } /** - * Wrap a Path instance in a new instance, patching out the {@link Path#getEntityPosAtNode(Entity, int)} implementation for smoother pathing + * Wrap a Path instance in a new instance, patching out the {@link Path#getEntityPosAtNode(Entity, int)} + * implementation for smoother pathing * * @return A new Path instance, or null if the input Path was null */ @Nullable default Path patchPath(@Nullable Path path) { return path == null ? null : new Path(path.nodes, path.getTarget(), path.canReach()) { + @Override public Vec3 getEntityPosAtNode(Entity entity, int nodeIndex) { return ExtendedNavigator.this.getEntityPosAtNode(nodeIndex); @@ -113,25 +118,39 @@ public Vec3 getEntityPosAtNode(Entity entity, int nodeIndex) { } /** - * Create a PathFinder instance patching out the {@link Path#getEntityPosAtNode(Entity, int)} implementation for smoother pathing + * Create a PathFinder instance patching out the {@link Path#getEntityPosAtNode(Entity, int)} implementation for + * smoother pathing */ default PathFinder createSmoothPathFinder(NodeEvaluator nodeEvaluator, int maxVisitedNodes) { return new PathFinder(nodeEvaluator, maxVisitedNodes) { + @Nullable @Override - public Path findPath(PathNavigationRegion navigationRegion, Mob mob, Set targetPositions, float maxRange, int accuracy, float searchDepthMultiplier) { - return patchPath(super.findPath(navigationRegion, mob, targetPositions, maxRange, accuracy, searchDepthMultiplier)); + public Path findPath( + PathNavigationRegion navigationRegion, + Mob mob, + Set targetPositions, + float maxRange, + int accuracy, + float searchDepthMultiplier + ) { + return patchPath( + super.findPath(navigationRegion, mob, targetPositions, maxRange, accuracy, searchDepthMultiplier) + ); } }; } /** - * Attempt to skip to the target node, bypassing the intermediate notes depending on bounds collision for the intervening distance + * Attempt to skip to the target node, bypassing the intermediate notes depending on bounds collision for the + * intervening distance *

    - * Typically, the target node should already have been checked for proximal relevance, as otherwise this could cause node skips to act strangely + * Typically, the target node should already have been checked for proximal relevance, as otherwise this could cause + * node skips to act strangely * * @param targetNode The target node index to shortcut to - * @param safeSurfacePos The baseline position of where the mob should traverse to (usually the nearest ground pos or surface of the fluid it's submerged in) + * @param safeSurfacePos The baseline position of where the mob should traverse to (usually the nearest ground pos + * or surface of the fluid it's submerged in) * @return Whether the shortcut was successful or not */ default boolean attemptShortcut(int targetNode, Vec3 safeSurfacePos) { @@ -171,10 +190,12 @@ default Vec3 getEntityPosAtNode(int nodeIndex) { } /** - * Recursively sweep the edges of a given area, identifying collisions for colliding faces of a pseudo-bounds determined by ray-casts - * projected from the bounds leading edge, then cross-checking interceptions for the relevant face. + * Recursively sweep the edges of a given area, identifying collisions for colliding faces of a pseudo-bounds + * determined by ray-casts projected from the bounds leading edge, then cross-checking interceptions for the + * relevant face. *

      - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Extensible {@link #prefersShallowSwimming()} implementation for ease-of-use
    • + *
    • Patched {@link Path} implementation to use proper rounding
    • + *
    • Extensible {@link #prefersShallowSwimming()} implementation for ease-of-use
    • *
    *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based walking entity + * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based + * walking entity */ public class SmoothAmphibiousPathNavigation extends AmphibiousPathNavigation implements ExtendedNavigator { + public SmoothAmphibiousPathNavigation(Mob mob, Level level) { super(mob, level); } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothFlyingPathNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothFlyingPathNavigation.java index 4b8f5a817..b0f51773f 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothFlyingPathNavigation.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothFlyingPathNavigation.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.navigation; @@ -17,12 +16,14 @@ /** * Extension of the vanilla {@link FlyingPathNavigation} with some tweaks for smoother pathfinding: *

      - *
    • Patched {@link Path} implementation to use proper rounding
    • + *
    • Patched {@link Path} implementation to use proper rounding
    • *
    *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based walking entity + * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based + * walking entity */ public class SmoothFlyingPathNavigation extends FlyingPathNavigation implements ExtendedNavigator { + public SmoothFlyingPathNavigation(Mob mob, Level level) { super(mob, level); } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothGroundNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothGroundNavigation.java index 7ed2f8325..f414c2b0f 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothGroundNavigation.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothGroundNavigation.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.navigation; @@ -20,17 +19,20 @@ /** * Extension of the vanilla {@link GroundPathNavigation} with some tweaks for smoother pathfinding: *

      - *
    • Smoothed unit rounding to better accommodate edge-cases
    • - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Skip to vertical traversal first before continuing path nodes if appropriate
    • - *
    • Accessible {@link GroundPathNavigation#getSurfaceY()} override for extensibility
    • + *
    • Smoothed unit rounding to better accommodate edge-cases
    • + *
    • Patched {@link Path} implementation to use proper rounding
    • + *
    • Skip to vertical traversal first before continuing path nodes if appropriate
    • + *
    • Accessible {@link GroundPathNavigation#getSurfaceY()} override for extensibility
    • *
    *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based walking entity + * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based + * walking entity + * * @see ExtendedNavigator#canPathOnto * @see ExtendedNavigator#canPathInto */ public class SmoothGroundNavigation extends GroundPathNavigation implements ExtendedNavigator { + public SmoothGroundNavigation(Mob mob, Level level) { super(mob, level); } @@ -61,10 +63,16 @@ protected PathFinder createPathFinder(int maxVisitedNodes) { protected void followThePath() { final Vec3 safeSurfacePos = getTempMobPos(); final int shortcutNode = getClosestVerticalTraversal(Mth.floor(safeSurfacePos.y)); - this.maxDistanceToWaypoint = this.mob.getBbWidth() > 0.75f ? this.mob.getBbWidth() / 2f : 0.75f - this.mob.getBbWidth() / 2f; + this.maxDistanceToWaypoint = this.mob.getBbWidth() > 0.75f + ? this.mob.getBbWidth() / 2f + : 0.75f - this.mob.getBbWidth() / 2f; if (!attemptShortcut(shortcutNode, safeSurfacePos)) { - if (isCloseToNextNode(0.5f) || isAboutToTraverseVertically() && isCloseToNextNode(getMaxDistanceToWaypoint())) + if ( + isCloseToNextNode(0.5f) || isAboutToTraverseVertically() && isCloseToNextNode( + getMaxDistanceToWaypoint() + ) + ) this.path.advance(); } @@ -86,10 +94,11 @@ public int getSurfaceY() { /** * Find the nearest node in the path that accounts for a vertical traversal (either up or down) *

    - * This can then be used to test if a collision-free traversal can be made, skipping the intermediate nodes as appropriate - * - * @param safeSurfaceHeight The baseline floored y-pos of where the mob should traverse to (usually the nearest ground pos or surface of the fluid it's submerged in) + * This can then be used to test if a collision-free traversal can be made, skipping the intermediate nodes as + * appropriate * + * @param safeSurfaceHeight The baseline floored y-pos of where the mob should traverse to (usually the nearest + * ground pos or surface of the fluid it's submerged in) * @return The node index for the nearest node representing a vertical traversal */ protected int getClosestVerticalTraversal(int safeSurfaceHeight) { diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWallClimberNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWallClimberNavigation.java index 9b9ee4a92..cf1cfe5be 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWallClimberNavigation.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWallClimberNavigation.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.navigation; @@ -19,13 +18,15 @@ /** * Extension of the vanilla {@link WallClimberNavigation} with some tweaks for smoother pathfinding: *

      - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Accessible {@link GroundPathNavigation#getSurfaceY()} override for extensibility
    • + *
    • Patched {@link Path} implementation to use proper rounding
    • + *
    • Accessible {@link GroundPathNavigation#getSurfaceY()} override for extensibility
    • *
    *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based walking entity + * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based + * walking entity */ public class SmoothWallClimberNavigation extends WallClimberNavigation implements ExtendedNavigator { + public SmoothWallClimberNavigation(Mob mob, Level level) { super(mob, level); } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWaterBoundPathNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWaterBoundPathNavigation.java index 457b0f4cc..188984954 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWaterBoundPathNavigation.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWaterBoundPathNavigation.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.navigation; @@ -18,14 +17,16 @@ /** * Extension of the vanilla {@link WaterBoundPathNavigation} navigator with some tweaks for smoother pathfinding: *

      - *
    • Smoothed unit rounding to better accommodate edge-cases
    • - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Extensible {@link #canBreach()} implementation for ease-of-use
    • + *
    • Smoothed unit rounding to better accommodate edge-cases
    • + *
    • Patched {@link Path} implementation to use proper rounding
    • + *
    • Extensible {@link #canBreach()} implementation for ease-of-use
    • *
    *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a water-based swimming entity + * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a water-based + * swimming entity */ public class SmoothWaterBoundPathNavigation extends WaterBoundPathNavigation implements ExtendedNavigator { + public SmoothWaterBoundPathNavigation(Mob mob, Level level) { super(mob, level); } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/schedule/SmartBrainSchedule.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/schedule/SmartBrainSchedule.java index fe88cfa59..95fa9dd0e 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/schedule/SmartBrainSchedule.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/schedule/SmartBrainSchedule.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.schedule; @@ -13,7 +12,6 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.schedule.Activity; import net.minecraft.world.entity.schedule.Schedule; -import mod.azure.azurelib.sblforked.api.SmartBrainOwner; import org.jetbrains.annotations.Nullable; import java.util.Arrays; @@ -21,177 +19,193 @@ import java.util.function.ToIntBiFunction; import java.util.function.ToIntFunction; +import mod.azure.azurelib.sblforked.api.SmartBrainOwner; + /** * SBL-implementation of the vanilla {@link net.minecraft.world.entity.schedule.Schedule Schedule}.
    - * It extends the vanilla {@link Schedule} purely for compatibility reasons, but does not utilise any of its functionality.
    + * It extends the vanilla {@link Schedule} purely for compatibility reasons, but does not utilise any of its + * functionality.
    *
    - * This segment of the Brain system is used to timeline activities, allowing you to run activity groups and tasks on a tick-based schedule.
    + * This segment of the Brain system is used to timeline activities, allowing you to run activity groups and tasks on a + * tick-based schedule.
    *
    - * Activities scheduled using this system will override the activity priorities from {@link SmartBrainOwner#getActivityPriorities()} at tick time + * Activities scheduled using this system will override the activity priorities from + * {@link SmartBrainOwner#getActivityPriorities()} at tick time */ public class SmartBrainSchedule extends Schedule { - private final Type type; - private final Int2ObjectArrayMap timeline = new Int2ObjectArrayMap<>(0); - private final ListMultimap> callbacks = MultimapBuilder.hashKeys(0).arrayListValues().build(); - - private boolean sortedTimeline = true; - - public SmartBrainSchedule() { - this(Type.DAYTIME); - } - - public SmartBrainSchedule(Type type) { - this.type = type; - } - - /** - * Set the active {@link Activity} for the brain at the given tick/time - * @param tick The tick/time to activate the activity - * @param activity The activity to set as active at the given time - * @return this - */ - public SmartBrainSchedule activityAt(int tick, Activity activity) { - this.timeline.put(tick, activity); - - this.sortedTimeline = false; - - return this; - } - - /** - * Add a callback to run at the given tick - * @param tick The tick/time to run the callback at - * @param callback The callback to run at the given time - * @return this - */ - public SmartBrainSchedule doAt(int tick, Consumer callback) { - this.callbacks.put(tick, callback); - - return this; - } - - /** - * Adds a dynamically-scheduled task for a given tick-time in the future - * @param brainOwner The owner of the brain - * @param delay The delay time (in ticks) before the task should be called - * @param task The task to run after the given delay - */ - public void scheduleTask(LivingEntity brainOwner, int delay, Consumer task) { - this.callbacks.put(this.type.resolveDelay(brainOwner, delay), entity -> task.accept(brainOwner)); - } - - /** - * Remove all entries from the schedule, clearing it out - */ - public void clearSchedule() { - this.callbacks.clear(); - this.timeline.clear(); - } - - /** - * Tick the schedule and return the activity to switch the entity to, if applicable - * @param brainOwner The owner of the brain that contains this schedule - * @return The activity to set as active based on the current tick, or null if none to set - */ - @Nullable - public Activity tick(LivingEntity brainOwner) { - int tick = this.type.resolve(brainOwner); - - if (!this.callbacks.isEmpty()) { - this.callbacks.get(tick).forEach(consumer -> consumer.accept(brainOwner)); - - if (this.type == Type.AGE) - this.callbacks.removeAll(tick); - } - - if (!this.timeline.isEmpty()) { - if (!this.sortedTimeline) - sortTimeline(); - - int index = -1; - Activity activity = null; - - for (Int2ObjectMap.Entry entry : this.timeline.int2ObjectEntrySet()) { - index++; - - if (entry.getIntKey() >= tick) { - if (entry.getIntKey() == tick) - activity = entry.getValue(); - - break; - } - - activity = entry.getValue(); - } - - if (this.type == Type.AGE && index + 1 >= this.timeline.size()) - this.timeline.clear(); - - return activity; - } - - return null; - } - - private void sortTimeline() { - Int2ObjectArrayMap copy = new Int2ObjectArrayMap<>(this.timeline); - int[] keys = copy.keySet().toArray(new int[0]); - - Arrays.sort(keys); - this.timeline.clear(); - - for (int key : keys) { - this.timeline.put(key, copy.get(key)); - } - - this.sortedTimeline = true; - } - - @Override - public final Activity getActivityAt(int tick) { - if (this.type == Type.AGE) - return Activity.IDLE; - - Activity activity = Activity.IDLE; - - for (Int2ObjectMap.Entry entry : this.timeline.int2ObjectEntrySet()) { - if (entry.getIntKey() >= tick) - return activity; - - activity = entry.getValue(); - } - - return activity; - } - - /** - * The type of scheduling this scheduler is using (I.E. how it determines the input tick) - */ - public enum Type { - /** - * Time of day (0-24000 ticks) - */ - DAYTIME(e -> (int)(e.level().getDayTime() % 24000L), (e, t) -> (int)((e.level().getDayTime() + t) % 24000L)), - /** - * Age of the brain owner (0+).
    - * This makes the schedule a 'run-once' per entity - */ - AGE(e -> e.tickCount, (e, t) -> e.tickCount + t); - - final ToIntFunction tickResolver; - final ToIntBiFunction delayResolver; - - Type(ToIntFunction tickResolver, ToIntBiFunction delayResolver) { - this.tickResolver = tickResolver; - this.delayResolver = delayResolver; - } - - public int resolve(LivingEntity entity) { - return this.tickResolver.applyAsInt(entity); - } - - public int resolveDelay(LivingEntity entity, int delay) { - return this.delayResolver.applyAsInt(entity, delay); - } - } + + private final Type type; + + private final Int2ObjectArrayMap timeline = new Int2ObjectArrayMap<>(0); + + private final ListMultimap> callbacks = MultimapBuilder.hashKeys(0) + .arrayListValues() + .build(); + + private boolean sortedTimeline = true; + + public SmartBrainSchedule() { + this(Type.DAYTIME); + } + + public SmartBrainSchedule(Type type) { + this.type = type; + } + + /** + * Set the active {@link Activity} for the brain at the given tick/time + * + * @param tick The tick/time to activate the activity + * @param activity The activity to set as active at the given time + * @return this + */ + public SmartBrainSchedule activityAt(int tick, Activity activity) { + this.timeline.put(tick, activity); + + this.sortedTimeline = false; + + return this; + } + + /** + * Add a callback to run at the given tick + * + * @param tick The tick/time to run the callback at + * @param callback The callback to run at the given time + * @return this + */ + public SmartBrainSchedule doAt(int tick, Consumer callback) { + this.callbacks.put(tick, callback); + + return this; + } + + /** + * Adds a dynamically-scheduled task for a given tick-time in the future + * + * @param brainOwner The owner of the brain + * @param delay The delay time (in ticks) before the task should be called + * @param task The task to run after the given delay + */ + public void scheduleTask(LivingEntity brainOwner, int delay, Consumer task) { + this.callbacks.put(this.type.resolveDelay(brainOwner, delay), entity -> task.accept(brainOwner)); + } + + /** + * Remove all entries from the schedule, clearing it out + */ + public void clearSchedule() { + this.callbacks.clear(); + this.timeline.clear(); + } + + /** + * Tick the schedule and return the activity to switch the entity to, if applicable + * + * @param brainOwner The owner of the brain that contains this schedule + * @return The activity to set as active based on the current tick, or null if none to set + */ + @Nullable + public Activity tick(LivingEntity brainOwner) { + int tick = this.type.resolve(brainOwner); + + if (!this.callbacks.isEmpty()) { + this.callbacks.get(tick).forEach(consumer -> consumer.accept(brainOwner)); + + if (this.type == Type.AGE) + this.callbacks.removeAll(tick); + } + + if (!this.timeline.isEmpty()) { + if (!this.sortedTimeline) + sortTimeline(); + + int index = -1; + Activity activity = null; + + for (Int2ObjectMap.Entry entry : this.timeline.int2ObjectEntrySet()) { + index++; + + if (entry.getIntKey() >= tick) { + if (entry.getIntKey() == tick) + activity = entry.getValue(); + + break; + } + + activity = entry.getValue(); + } + + if (this.type == Type.AGE && index + 1 >= this.timeline.size()) + this.timeline.clear(); + + return activity; + } + + return null; + } + + private void sortTimeline() { + Int2ObjectArrayMap copy = new Int2ObjectArrayMap<>(this.timeline); + int[] keys = copy.keySet().toArray(new int[0]); + + Arrays.sort(keys); + this.timeline.clear(); + + for (int key : keys) { + this.timeline.put(key, copy.get(key)); + } + + this.sortedTimeline = true; + } + + @Override + public final Activity getActivityAt(int tick) { + if (this.type == Type.AGE) + return Activity.IDLE; + + Activity activity = Activity.IDLE; + + for (Int2ObjectMap.Entry entry : this.timeline.int2ObjectEntrySet()) { + if (entry.getIntKey() >= tick) + return activity; + + activity = entry.getValue(); + } + + return activity; + } + + /** + * The type of scheduling this scheduler is using (I.E. how it determines the input tick) + */ + public enum Type { + + /** + * Time of day (0-24000 ticks) + */ + DAYTIME(e -> (int) (e.level().getDayTime() % 24000L), (e, t) -> (int) ((e.level().getDayTime() + t) % 24000L)), + /** + * Age of the brain owner (0+).
    + * This makes the schedule a 'run-once' per entity + */ + AGE(e -> e.tickCount, (e, t) -> e.tickCount + t); + + final ToIntFunction tickResolver; + + final ToIntBiFunction delayResolver; + + Type(ToIntFunction tickResolver, ToIntBiFunction delayResolver) { + this.tickResolver = tickResolver; + this.delayResolver = delayResolver; + } + + public int resolve(LivingEntity entity) { + return this.tickResolver.applyAsInt(entity); + } + + public int resolveDelay(LivingEntity entity, int delay) { + return this.delayResolver.applyAsInt(entity, delay); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/EntityFilteringSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/EntityFilteringSensor.java index 128fab038..8f9c4e714 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/EntityFilteringSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/EntityFilteringSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor; @@ -10,56 +9,65 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** - * An abstract class that is used to pick out certain entities from the existing {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory.
    + * An abstract class that is used to pick out certain entities from the existing + * {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory.
    * This requires that another sensor has pre-filled that memory. + * * @see net.minecraft.world.entity.ai.sensing.NearestVisibleLivingEntitySensor * @param

    The target entity * @param The entity */ public abstract class EntityFilteringSensor extends PredicateSensor { - /** - * Which memory the sensor should set if an entity meets the given criteria. - * - * @return The memory type to use - */ - protected abstract MemoryModuleType

    getMemory(); - @Override - protected abstract BiPredicate predicate(); + /** + * Which memory the sensor should set if an entity meets the given criteria. + * + * @return The memory type to use + */ + protected abstract MemoryModuleType

    getMemory(); + + @Override + protected abstract BiPredicate predicate(); - @Override - public List> memoriesUsed() { - return List.of(getMemory()); - } + @Override + public List> memoriesUsed() { + return List.of(getMemory()); + } - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.setMemory(entity, getMemory(), testForEntity(entity)); - } + @Override + protected void doTick(ServerLevel level, E entity) { + BrainUtils.setMemory(entity, getMemory(), testForEntity(entity)); + } - protected P testForEntity(E entity) { - NearestVisibleLivingEntities matcher = BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); + protected P testForEntity(E entity) { + NearestVisibleLivingEntities matcher = BrainUtils.getMemory( + entity, + MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES + ); - if (matcher == null) - return null; + if (matcher == null) + return null; - return findMatches(entity, matcher); - } + return findMatches(entity, matcher); + } - /** - * Find and return matches based on the provided list of entities.
    - * The returned value is saved as the memory for this sensor. - * @param entity The entity - * @param matcher The nearby entities list retrieved from the {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory - * @return The match(es) to save in memory - */ - @Nullable - protected abstract P findMatches(E entity, NearestVisibleLivingEntities matcher); + /** + * Find and return matches based on the provided list of entities.
    + * The returned value is saved as the memory for this sensor. + * + * @param entity The entity + * @param matcher The nearby entities list retrieved from the + * {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory + * @return The match(es) to save in memory + */ + @Nullable + protected abstract P findMatches(E entity, NearestVisibleLivingEntities matcher); } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/ExtendedSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/ExtendedSensor.java index 915ce3fae..b231ae8d5 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/ExtendedSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/ExtendedSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor; @@ -19,83 +18,90 @@ import java.util.function.Function; /** - * An extension of the base Sensor. This adds some minor additional functionality and swaps the memory to a list for easier usage and faster iteration.
    + * An extension of the base Sensor. This adds some minor additional functionality and swaps the memory to a list for + * easier usage and faster iteration.
    * All custom sensor implementations should use this superclass. * * @param The entity */ public abstract class ExtendedSensor extends Sensor { - protected Function scanRate = entity -> 20; - protected Consumer scanCallback = entity -> {}; - protected long nextTickTime = 0; - - public ExtendedSensor() { - super(); - } - - /** - * Set the scan rate provider for this sensor.
    - * The provider will be sampled every time the sensor does a scan. - * - * @param function The function to provide the tick rate - * @return this - */ - public ExtendedSensor setScanRate(Function function) { - this.scanRate = function; - - return this; - } - - /** - * Set a callback function for when the sensor completes a scan. - */ - public ExtendedSensor afterScanning(Consumer callback) { - this.scanCallback = callback; - - return this; - } - - @Override - public final void tick(ServerLevel level, E entity) { - if (nextTickTime < level.getGameTime()) { - nextTickTime = level.getGameTime() + scanRate.apply(entity); - - doTick(level, entity); - this.scanCallback.accept(entity); - } - } - - /** - * Handle the Sensor's actual function here. Be wary of performance implications of computation-heavy checks here. - * - * @param level The level the entity is in - * @param entity The owner of the brain - */ - @Override - protected void doTick(ServerLevel level, E entity) {} - - /** - * The list of memory types this sensor saves to. This should contain any memory the sensor sets a value for in the brain
    - * Bonus points if it's a statically-initialised list. - * - * @return The list of memory types saves by this sensor - */ - public abstract List> memoriesUsed(); - - /** - * The {@link SensorType} of the sensor, used for reverse lookups. - * @return The sensor type - */ - public abstract SensorType> type(); - - /** - * Vanilla's implementation of the required memory collection. Functionally replaced by {@link ExtendedSensor#memoriesUsed()}.
    - * Left in place for compatibility reasons. - * - * @return A set view of the list returned by {@code memoriesUsed()} - */ - @Override - public final Set> requires() { - return new ObjectOpenHashSet<>(memoriesUsed()); - } + + protected Function scanRate = entity -> 20; + + protected Consumer scanCallback = entity -> {}; + + protected long nextTickTime = 0; + + public ExtendedSensor() { + super(); + } + + /** + * Set the scan rate provider for this sensor.
    + * The provider will be sampled every time the sensor does a scan. + * + * @param function The function to provide the tick rate + * @return this + */ + public ExtendedSensor setScanRate(Function function) { + this.scanRate = function; + + return this; + } + + /** + * Set a callback function for when the sensor completes a scan. + */ + public ExtendedSensor afterScanning(Consumer callback) { + this.scanCallback = callback; + + return this; + } + + @Override + public final void tick(ServerLevel level, E entity) { + if (nextTickTime < level.getGameTime()) { + nextTickTime = level.getGameTime() + scanRate.apply(entity); + + doTick(level, entity); + this.scanCallback.accept(entity); + } + } + + /** + * Handle the Sensor's actual function here. Be wary of performance implications of computation-heavy checks here. + * + * @param level The level the entity is in + * @param entity The owner of the brain + */ + @Override + protected void doTick(ServerLevel level, E entity) {} + + /** + * The list of memory types this sensor saves to. This should contain any memory the sensor sets a value for in the + * brain
    + * Bonus points if it's a statically-initialised list. + * + * @return The list of memory types saves by this sensor + */ + public abstract List> memoriesUsed(); + + /** + * The {@link SensorType} of the sensor, used for reverse lookups. + * + * @return The sensor type + */ + public abstract SensorType> type(); + + /** + * Vanilla's implementation of the required memory collection. Functionally replaced by + * {@link ExtendedSensor#memoriesUsed()}.
    + * Left in place for compatibility reasons. + * + * @return A set view of the list returned by {@code memoriesUsed()} + */ + @Override + public final Set> requires() { + return new ObjectOpenHashSet<>(memoriesUsed()); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/PredicateSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/PredicateSensor.java index 887183400..8d7b92140 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/PredicateSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/PredicateSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor; @@ -11,41 +10,42 @@ import java.util.function.BiPredicate; /** - * An abstract sensor class used for sensors that utilise some form of predication in their function. - * This allows for instance-based SmartBrainLib of the predicate and the sensor. + * An abstract sensor class used for sensors that utilise some form of predication in their function. This allows for + * instance-based SmartBrainLib of the predicate and the sensor. * * @param

    The predicate, used for whatever the sensor might need * @param The entity */ public abstract class PredicateSensor extends ExtendedSensor { - private BiPredicate predicate; - - public PredicateSensor() { - this((obj, entity) -> true); - } - - public PredicateSensor(BiPredicate predicate) { - this.predicate = predicate; - } - - /** - * Set the predicate for the sensor. The subclass of this class determines its usage. - * - * @param predicate The predicate - * @return this - */ - public PredicateSensor setPredicate(BiPredicate predicate) { - this.predicate = predicate; - - return this; - } - - /** - * Retrieve the predicate this sensor is using. - * - * @return The predicate - */ - protected BiPredicate predicate() { - return this.predicate; - } + + private BiPredicate predicate; + + public PredicateSensor() { + this((obj, entity) -> true); + } + + public PredicateSensor(BiPredicate predicate) { + this.predicate = predicate; + } + + /** + * Set the predicate for the sensor. The subclass of this class determines its usage. + * + * @param predicate The predicate + * @return this + */ + public PredicateSensor setPredicate(BiPredicate predicate) { + this.predicate = predicate; + + return this; + } + + /** + * Retrieve the predicate this sensor is using. + * + * @return The predicate + */ + protected BiPredicate predicate() { + return this.predicate; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/GenericAttackTargetSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/GenericAttackTargetSensor.java index 1e2200075..7082c97b5 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/GenericAttackTargetSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/GenericAttackTargetSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.custom; @@ -10,40 +9,44 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; import org.jetbrains.annotations.Nullable; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; +import mod.azure.azurelib.sblforked.registry.SBLSensors; + /** * Sets the {@link MemoryModuleType#NEAREST_ATTACKABLE} memory based on visible nearby entities.
    * Defaults: *

      - *
    • Only targets that {@link net.minecraft.world.entity.ai.sensing.Sensor#isEntityAttackable(LivingEntity, LivingEntity)} passes.
    • + *
    • Only targets that + * {@link net.minecraft.world.entity.ai.sensing.Sensor#isEntityAttackable(LivingEntity, LivingEntity)} passes.
    • *
    + * * @param */ public class GenericAttackTargetSensor extends EntityFilteringSensor { - @Override - protected MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_ATTACKABLE; - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> isEntityAttackable(entity, target); - } - - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } - - @Override - public SensorType> type() { - return SBLSensors.GENERIC_ATTACK_TARGET.get(); - } + + @Override + protected MemoryModuleType getMemory() { + return MemoryModuleType.NEAREST_ATTACKABLE; + } + + @Override + protected BiPredicate predicate() { + return (target, entity) -> isEntityAttackable(entity, target); + } + + @Nullable + @Override + protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { + return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); + } + + @Override + public SensorType> type() { + return SBLSensors.GENERIC_ATTACK_TARGET.get(); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/IncomingProjectilesSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/IncomingProjectilesSensor.java index 0bcc8ec64..70805fcaf 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/IncomingProjectilesSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/IncomingProjectilesSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.custom; @@ -12,6 +11,10 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.sensing.SensorType; import net.minecraft.world.entity.projectile.Projectile; + +import java.util.Comparator; +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; @@ -19,52 +22,57 @@ import mod.azure.azurelib.sblforked.util.BrainUtils; import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; -import java.util.Comparator; -import java.util.List; - /** - * Custom sensor that detects incoming projectiles. - * Defaults: + * Custom sensor that detects incoming projectiles. Defaults: *
      - *
    • 3-tick scan rate
    • - *
    • Only projectiles that are still in flight
    • - *
    • Only projectiles that will hit the entity before the next scan
    • + *
    • 3-tick scan rate
    • + *
    • Only projectiles that are still in flight
    • + *
    • Only projectiles that will hit the entity before the next scan
    • *
    + * * @param */ public class IncomingProjectilesSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(SBLMemoryTypes.INCOMING_PROJECTILES.get()); - public IncomingProjectilesSensor() { - setScanRate(entity -> 3); - setPredicate((projectile, entity) -> { - if (projectile.onGround() || projectile.horizontalCollision || projectile.verticalCollision) - return false; + private static final List> MEMORIES = ObjectArrayList.of( + SBLMemoryTypes.INCOMING_PROJECTILES.get() + ); + + public IncomingProjectilesSensor() { + setScanRate(entity -> 3); + setPredicate((projectile, entity) -> { + if (projectile.onGround() || projectile.horizontalCollision || projectile.verticalCollision) + return false; - return entity.getBoundingBox().clip(projectile.position(), projectile.position().add(projectile.getDeltaMovement().multiply(3, 3, 3))).isPresent(); - }); - } + return entity.getBoundingBox() + .clip(projectile.position(), projectile.position().add(projectile.getDeltaMovement().multiply(3, 3, 3))) + .isPresent(); + }); + } - @Override - public List> memoriesUsed() { - return MEMORIES; - } + @Override + public List> memoriesUsed() { + return MEMORIES; + } - @Override - public SensorType> type() { - return SBLSensors.INCOMING_PROJECTILES.get(); - } + @Override + public SensorType> type() { + return SBLSensors.INCOMING_PROJECTILES.get(); + } - @Override - protected void doTick(ServerLevel level, E entity) { - List projectiles = EntityRetrievalUtil.getEntities(level, entity.getBoundingBox().inflate(7), target -> target instanceof Projectile projectile && predicate().test(projectile, entity)); + @Override + protected void doTick(ServerLevel level, E entity) { + List projectiles = EntityRetrievalUtil.getEntities( + level, + entity.getBoundingBox().inflate(7), + target -> target instanceof Projectile projectile && predicate().test(projectile, entity) + ); - if (!projectiles.isEmpty()) { - projectiles.sort(Comparator.comparingDouble(entity::distanceToSqr)); - BrainUtils.setMemory(entity, SBLMemoryTypes.INCOMING_PROJECTILES.get(), projectiles); - } - else { - BrainUtils.clearMemory(entity, SBLMemoryTypes.INCOMING_PROJECTILES.get()); - } - } + if (!projectiles.isEmpty()) { + projectiles.sort(Comparator.comparingDouble(entity::distanceToSqr)); + BrainUtils.setMemory(entity, SBLMemoryTypes.INCOMING_PROJECTILES.get(), projectiles); + } else { + BrainUtils.clearMemory(entity, SBLMemoryTypes.INCOMING_PROJECTILES.get()); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyBlocksSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyBlocksSensor.java index 685fcdebc..f0fb96400 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyBlocksSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyBlocksSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.custom; @@ -14,6 +13,9 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.sensing.SensorType; import net.minecraft.world.level.block.state.BlockState; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; import mod.azure.azurelib.sblforked.object.SquareRadius; @@ -21,72 +23,78 @@ import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; -import java.util.List; - /** - * Sensor for identifying and memorising nearby blocks using the {@link SBLMemoryTypes#NEARBY_BLOCKS} memory module.
    + * Sensor for identifying and memorising nearby blocks using the {@link SBLMemoryTypes#NEARBY_BLOCKS} memory module. + *
    * Defaults: *
      - *
    • 1-block radius
    • - *
    • Ignores air blocks
    • + *
    • 1-block radius
    • + *
    • Ignores air blocks
    • *
    */ public class NearbyBlocksSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(SBLMemoryTypes.NEARBY_BLOCKS.get()); - - protected SquareRadius radius = new SquareRadius(1, 1); - - public NearbyBlocksSensor() { - setPredicate((state, entity) -> !state.isAir()); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_BLOCKS.get(); - } - - /** - * Set the radius for the sensor to scan - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyBlocksSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan. - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyBlocksSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - protected void doTick(ServerLevel level, E entity) { - List> blocks = new ObjectArrayList<>(); - - for (BlockPos pos : BlockPos.betweenClosed(entity.blockPosition().subtract(this.radius.toVec3i()), entity.blockPosition().offset(this.radius.toVec3i()))) { - BlockState state = level.getBlockState(pos); - - if (this.predicate().test(state, entity)) - blocks.add(Pair.of(pos.immutable(), state)); - } - - if (blocks.isEmpty()) { - BrainUtils.clearMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get()); - } - else { - BrainUtils.setMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get(), blocks); - } - } -} \ No newline at end of file + + private static final List> MEMORIES = ObjectArrayList.of(SBLMemoryTypes.NEARBY_BLOCKS.get()); + + protected SquareRadius radius = new SquareRadius(1, 1); + + public NearbyBlocksSensor() { + setPredicate((state, entity) -> !state.isAir()); + } + + @Override + public List> memoriesUsed() { + return MEMORIES; + } + + @Override + public SensorType> type() { + return SBLSensors.NEARBY_BLOCKS.get(); + } + + /** + * Set the radius for the sensor to scan + * + * @param radius The coordinate radius, in blocks + * @return this + */ + public NearbyBlocksSensor setRadius(double radius) { + return setRadius(radius, radius); + } + + /** + * Set the radius for the sensor to scan. + * + * @param xz The X/Z coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks + * @return this + */ + public NearbyBlocksSensor setRadius(double xz, double y) { + this.radius = new SquareRadius(xz, y); + + return this; + } + + @Override + protected void doTick(ServerLevel level, E entity) { + List> blocks = new ObjectArrayList<>(); + + for ( + BlockPos pos : BlockPos.betweenClosed( + entity.blockPosition().subtract(this.radius.toVec3i()), + entity.blockPosition().offset(this.radius.toVec3i()) + ) + ) { + BlockState state = level.getBlockState(pos); + + if (this.predicate().test(state, entity)) + blocks.add(Pair.of(pos.immutable(), state)); + } + + if (blocks.isEmpty()) { + BrainUtils.clearMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get()); + } else { + BrainUtils.setMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get(), blocks); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyItemsSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyItemsSensor.java index 971954f96..30ff6198f 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyItemsSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyItemsSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.custom; @@ -14,6 +13,9 @@ import net.minecraft.world.entity.ai.sensing.SensorType; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; import mod.azure.azurelib.sblforked.object.SquareRadius; @@ -22,66 +24,70 @@ import mod.azure.azurelib.sblforked.util.BrainUtils; import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; -import java.util.List; - /** * A sensor that looks for nearby {@link ItemEntity items} in the surrounding area.
    * Defaults: *
      *
    • 32x16x32 radius
    • *
    • Only items that return true for {@link Mob#wantsToPickUp(ItemStack)}
    • - *
    • Only items that return true for - * {@link net.minecraft.world.entity.LivingEntity#hasLineOfSight(Entity)}
    • + *
    • Only items that return true for {@link net.minecraft.world.entity.LivingEntity#hasLineOfSight(Entity)}
    • *
    * * @param The entity */ public class NearbyItemsSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(SBLMemoryTypes.NEARBY_ITEMS.get()); - - protected SquareRadius radius = new SquareRadius(32, 16); - public NearbyItemsSensor() { - super((item, entity) -> entity.wantsToPickUp(item.getItem()) && entity.hasLineOfSight(item)); - } + private static final List> MEMORIES = ObjectArrayList.of(SBLMemoryTypes.NEARBY_ITEMS.get()); - /** - * Set the radius for the item sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyItemsSensor setRadius(double radius) { - return setRadius(radius, radius); - } + protected SquareRadius radius = new SquareRadius(32, 16); - /** - * Set the radius for the item sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyItemsSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); + public NearbyItemsSensor() { + super((item, entity) -> entity.wantsToPickUp(item.getItem()) && entity.hasLineOfSight(item)); + } - return this; - } + /** + * Set the radius for the item sensor to scan. + * + * @param radius The coordinate radius, in blocks + * @return this + */ + public NearbyItemsSensor setRadius(double radius) { + return setRadius(radius, radius); + } - @Override - public List> memoriesUsed() { - return MEMORIES; - } + /** + * Set the radius for the item sensor to scan. + * + * @param xz The X/Z coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks + * @return this + */ + public NearbyItemsSensor setRadius(double xz, double y) { + this.radius = new SquareRadius(xz, y); - @Override - public SensorType> type() { - return SBLSensors.NEARBY_ITEMS.get(); - } + return this; + } - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.setMemory(entity, SBLMemoryTypes.NEARBY_ITEMS.get(), EntityRetrievalUtil.getEntities(level, this.radius.inflateAABB(entity.getBoundingBox()), obj -> obj instanceof ItemEntity item && predicate().test(item, entity))); - } -} + @Override + public List> memoriesUsed() { + return MEMORIES; + } + @Override + public SensorType> type() { + return SBLSensors.NEARBY_ITEMS.get(); + } + @Override + protected void doTick(ServerLevel level, E entity) { + BrainUtils.setMemory( + entity, + SBLMemoryTypes.NEARBY_ITEMS.get(), + EntityRetrievalUtil.getEntities( + level, + this.radius.inflateAABB(entity.getBoundingBox()), + obj -> obj instanceof ItemEntity item && predicate().test(item, entity) + ) + ); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/UnreachableTargetSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/UnreachableTargetSensor.java index 6398a3d40..b7bcd64af 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/UnreachableTargetSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/UnreachableTargetSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.custom; @@ -12,75 +11,82 @@ import net.minecraft.world.entity.ai.Brain; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.sensing.SensorType; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; -import java.util.List; - /** - * A sensor to attempt to track whether the entity's target is currently obstructed either by blocks or a wall/tower of blocks.
    - * This is differentiated from {@link MemoryModuleType#CANT_REACH_WALK_TARGET_SINCE} in that it only stores state if the entity is actively blocked, and not just completing a previous path that may have been blocked.
    + * A sensor to attempt to track whether the entity's target is currently obstructed either by blocks or a wall/tower of + * blocks.
    + * This is differentiated from {@link MemoryModuleType#CANT_REACH_WALK_TARGET_SINCE} in that it only stores state if the + * entity is actively blocked, and not just completing a previous path that may have been blocked.
    * The contract of the memory (when this sensor is used) is as follows:
    *
      - *
    • If not present: entity is not blocked
    • - *
    • If false: entity is blocked at a similar or lower y-coordinate (wall-blocked)
    • - *
    • If true: entity is blocked at a higher y-coordinate (target has towered up, or is on cliff)
    • + *
    • If not present: entity is not blocked
    • + *
    • If false: entity is blocked at a similar or lower y-coordinate (wall-blocked)
    • + *
    • If true: entity is blocked at a higher y-coordinate (target has towered up, or is on cliff)
    • *
    + * * @param The entity */ public class UnreachableTargetSensor extends ExtendedSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.ATTACK_TARGET, SBLMemoryTypes.TARGET_UNREACHABLE.get()); - protected long lastUnpathableTime = 0; + private static final List> MEMORIES = ObjectArrayList.of( + MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, + MemoryModuleType.ATTACK_TARGET, + SBLMemoryTypes.TARGET_UNREACHABLE.get() + ); + + protected long lastUnpathableTime = 0; - @Override - public List> memoriesUsed() { - return MEMORIES; - } + @Override + public List> memoriesUsed() { + return MEMORIES; + } - @Override - public SensorType> type() { - return SBLSensors.UNREACHABLE_TARGET.get(); - } + @Override + public SensorType> type() { + return SBLSensors.UNREACHABLE_TARGET.get(); + } - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - LivingEntity target = BrainUtils.getTargetOfEntity(entity); + @Override + protected void doTick(ServerLevel level, E entity) { + Brain brain = entity.getBrain(); + LivingEntity target = BrainUtils.getTargetOfEntity(entity); - if (target == null) { - resetState(brain); + if (target == null) { + resetState(brain); - return; - } + return; + } - Long unpathableTime = BrainUtils.getMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); + Long unpathableTime = BrainUtils.getMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - if (unpathableTime == null) { - resetState(brain); + if (unpathableTime == null) { + resetState(brain); - return; - } + return; + } - if (this.lastUnpathableTime == 0) { - this.lastUnpathableTime = unpathableTime; - } - else if (this.lastUnpathableTime == unpathableTime) { - BrainUtils.clearMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get()); - } - else if (this.lastUnpathableTime < unpathableTime) { - this.lastUnpathableTime = unpathableTime; + if (this.lastUnpathableTime == 0) { + this.lastUnpathableTime = unpathableTime; + } else if (this.lastUnpathableTime == unpathableTime) { + BrainUtils.clearMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get()); + } else if (this.lastUnpathableTime < unpathableTime) { + this.lastUnpathableTime = unpathableTime; - BrainUtils.setMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get(), target.getY() > entity.getEyeY()); - } - } + BrainUtils.setMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get(), target.getY() > entity.getEyeY()); + } + } - private void resetState(Brain brain) { - if (this.lastUnpathableTime > 0) - BrainUtils.clearMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get()); + private void resetState(Brain brain) { + if (this.lastUnpathableTime > 0) + BrainUtils.clearMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get()); - this.lastUnpathableTime = 0; - } + this.lastUnpathableTime = 0; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/AxolotlSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/AxolotlSpecificSensor.java index 266ee4665..c774ee19e 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/AxolotlSpecificSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/AxolotlSpecificSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -12,58 +11,64 @@ import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; import net.minecraft.world.entity.ai.sensing.Sensor; import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; +import mod.azure.azurelib.sblforked.registry.SBLSensors; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** - * A replication of vanilla's - * {@link net.minecraft.world.entity.ai.sensing.AxolotlAttackablesSensor}. Not - * really useful, but included for completeness' sake and legibility.
    + * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.AxolotlAttackablesSensor}. Not really useful, + * but included for completeness' sake and legibility.
    * Handles the Axolotl's hostility and targets - * + * * @param The entity */ public class AxolotlSpecificSensor extends EntityFilteringSensor { - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_ATTACKABLE; - } - @Override - public List> memoriesUsed() { - return List.of(getMemory(), MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); - } + @Override + public MemoryModuleType getMemory() { + return MemoryModuleType.NEAREST_ATTACKABLE; + } + + @Override + public List> memoriesUsed() { + return List.of(getMemory(), MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); + } - @Override - public SensorType> type() { - return SBLSensors.AXOLOTL_SPECIFIC.get(); - } + @Override + public SensorType> type() { + return SBLSensors.AXOLOTL_SPECIFIC.get(); + } - @Override - protected BiPredicate predicate() { - return (target, entity) -> { - if (target.distanceToSqr(entity) > 64) - return false; + @Override + protected BiPredicate predicate() { + return (target, entity) -> { + if (target.distanceToSqr(entity) > 64) + return false; - if (!target.isInWaterOrBubble()) - return false; + if (!target.isInWaterOrBubble()) + return false; - if (!target.getType().is(EntityTypeTags.AXOLOTL_ALWAYS_HOSTILES) && (BrainUtils.hasMemory(target, MemoryModuleType.HAS_HUNTING_COOLDOWN) || !target.getType().is(EntityTypeTags.AXOLOTL_HUNT_TARGETS))) - return false; + if ( + !target.getType().is(EntityTypeTags.AXOLOTL_ALWAYS_HOSTILES) && (BrainUtils.hasMemory( + target, + MemoryModuleType.HAS_HUNTING_COOLDOWN + ) || !target.getType().is(EntityTypeTags.AXOLOTL_HUNT_TARGETS)) + ) + return false; - return Sensor.isEntityAttackable(entity, target); - }; - } + return Sensor.isEntityAttackable(entity, target); + }; + } - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } + @Nullable + @Override + protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { + return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/FrogSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/FrogSpecificSensor.java index 24572c28f..b5f453e78 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/FrogSpecificSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/FrogSpecificSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -12,59 +11,60 @@ import net.minecraft.world.entity.ai.sensing.Sensor; import net.minecraft.world.entity.ai.sensing.SensorType; import net.minecraft.world.entity.animal.frog.Frog; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.UUID; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; +import mod.azure.azurelib.sblforked.registry.SBLSensors; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** - * A replication of vanilla's - * {@link net.minecraft.world.entity.ai.sensing.FrogAttackablesSensor}. Not - * really useful, but included for completeness' sake and legibility.
    + * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.FrogAttackablesSensor}. Not really useful, + * but included for completeness' sake and legibility.
    * Handles the Frog's tongue target. - * + * * @param The entity */ public class FrogSpecificSensor extends EntityFilteringSensor { - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_ATTACKABLE; - } - @Override - public SensorType> type() { - return SBLSensors.FROG_SPECIFIC.get(); - } + @Override + public MemoryModuleType getMemory() { + return MemoryModuleType.NEAREST_ATTACKABLE; + } + + @Override + public SensorType> type() { + return SBLSensors.FROG_SPECIFIC.get(); + } - @Override - protected BiPredicate predicate() { - return (target, entity) -> { - if (BrainUtils.hasMemory(entity, MemoryModuleType.HAS_HUNTING_COOLDOWN)) - return false; + @Override + protected BiPredicate predicate() { + return (target, entity) -> { + if (BrainUtils.hasMemory(entity, MemoryModuleType.HAS_HUNTING_COOLDOWN)) + return false; - if (!Sensor.isEntityAttackable(entity, target)) - return false; + if (!Sensor.isEntityAttackable(entity, target)) + return false; - if (!Frog.canEat(target)) - return false; + if (!Frog.canEat(target)) + return false; - if (!target.closerThan(entity, 10)) - return false; + if (!target.closerThan(entity, 10)) + return false; - List unreachableTargets = BrainUtils.getMemory(entity, MemoryModuleType.UNREACHABLE_TONGUE_TARGETS); + List unreachableTargets = BrainUtils.getMemory(entity, MemoryModuleType.UNREACHABLE_TONGUE_TARGETS); - return unreachableTargets == null || !unreachableTargets.contains(target.getUUID()); - }; - } + return unreachableTargets == null || !unreachableTargets.contains(target.getUUID()); + }; + } - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } + @Nullable + @Override + protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { + return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HoglinSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HoglinSpecificSensor.java index e554e49cf..81639f3b9 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HoglinSpecificSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HoglinSpecificSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -16,62 +15,74 @@ import net.minecraft.world.entity.ai.sensing.SensorType; import net.minecraft.world.entity.monster.hoglin.Hoglin; import net.minecraft.world.entity.monster.piglin.Piglin; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; -import java.util.List; - /** - * A replication of vanilla's - * {@link net.minecraft.world.entity.ai.sensing.HoglinSpecificSensor}. Not - * really useful, but included for completeness' sake and legibility.
    + * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.HoglinSpecificSensor}. Not really useful, but + * included for completeness' sake and legibility.
    * Handles most of Hoglin's memories at once - * + * * @param The entity */ public class HoglinSpecificSensor extends ExtendedSensor { - private static final List> MEMORIES = ObjectArrayList.of( - MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, - MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, - MemoryModuleType.NEAREST_REPELLENT); - @Override - public List> memoriesUsed() { - return MEMORIES; - } + private static final List> MEMORIES = ObjectArrayList.of( + MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, + MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, + MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, + MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, + MemoryModuleType.NEAREST_REPELLENT + ); + + @Override + public List> memoriesUsed() { + return MEMORIES; + } - @Override - public SensorType> type() { - return SBLSensors.HOGLIN_SPECIFIC.get(); - } + @Override + public SensorType> type() { + return SBLSensors.HOGLIN_SPECIFIC.get(); + } - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); + @Override + protected void doTick(ServerLevel level, E entity) { + Brain brain = entity.getBrain(); - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, entities -> { - int piglinCount = 0; - Piglin nearestPiglin = null; - List hoglins = new ObjectArrayList<>(); + BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, entities -> { + int piglinCount = 0; + Piglin nearestPiglin = null; + List hoglins = new ObjectArrayList<>(); - for (LivingEntity target : entities.findAll(mob -> !mob.isBaby())) { - if (target instanceof Piglin piglin) { - piglinCount++; + for (LivingEntity target : entities.findAll(mob -> !mob.isBaby())) { + if (target instanceof Piglin piglin) { + piglinCount++; - if (nearestPiglin == null) - nearestPiglin = piglin; - } - else if (target instanceof Hoglin hoglin) { - hoglins.add(hoglin); - } - } + if (nearestPiglin == null) + nearestPiglin = piglin; + } else if (target instanceof Hoglin hoglin) { + hoglins.add(hoglin); + } + } - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, nearestPiglin); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, hoglins); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, piglinCount); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, hoglins.size()); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_REPELLENT, BlockPos.findClosestMatch(entity.blockPosition(), 8, 4, pos -> level.getBlockState(pos).is(BlockTags.HOGLIN_REPELLENTS)).orElse(null)); - }); - } + BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, nearestPiglin); + BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, hoglins); + BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, piglinCount); + BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, hoglins.size()); + BrainUtils.setMemory( + brain, + MemoryModuleType.NEAREST_REPELLENT, + BlockPos.findClosestMatch( + entity.blockPosition(), + 8, + 4, + pos -> level.getBlockState(pos).is(BlockTags.HOGLIN_REPELLENTS) + ).orElse(null) + ); + }); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HurtBySensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HurtBySensor.java index 4a6d8e0a1..efeb9b1c3 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HurtBySensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HurtBySensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -14,55 +13,61 @@ import net.minecraft.world.entity.ai.Brain; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.sensing.SensorType; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; -import java.util.List; - /** * A sensor that sets the memory state for the last damage source and attacker. * * @param The entity */ public class HurtBySensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.HURT_BY, MemoryModuleType.HURT_BY_ENTITY); - public HurtBySensor() { - super((damageSource, entity) -> true); - } + private static final List> MEMORIES = ObjectArrayList.of( + MemoryModuleType.HURT_BY, + MemoryModuleType.HURT_BY_ENTITY + ); + + public HurtBySensor() { + super((damageSource, entity) -> true); + } - @Override - public List> memoriesUsed() { - return MEMORIES; - } + @Override + public List> memoriesUsed() { + return MEMORIES; + } - @Override - public SensorType> type() { - return SBLSensors.HURT_BY.get(); - } + @Override + public SensorType> type() { + return SBLSensors.HURT_BY.get(); + } - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - DamageSource damageSource = entity.getLastDamageSource(); + @Override + protected void doTick(ServerLevel level, E entity) { + Brain brain = entity.getBrain(); + DamageSource damageSource = entity.getLastDamageSource(); - if (damageSource == null) { - BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY); - BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY_ENTITY); - } - else if (predicate().test(damageSource, entity)) { - BrainUtils.setMemory(brain, MemoryModuleType.HURT_BY, damageSource); + if (damageSource == null) { + BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY); + BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY_ENTITY); + } else if (predicate().test(damageSource, entity)) { + BrainUtils.setMemory(brain, MemoryModuleType.HURT_BY, damageSource); - if (damageSource.getEntity()instanceof LivingEntity attacker && attacker.isAlive() && attacker.level() == entity.level()) - BrainUtils.setMemory(brain, MemoryModuleType.HURT_BY_ENTITY, attacker); - } - else { - BrainUtils.withMemory(brain, MemoryModuleType.HURT_BY_ENTITY, attacker -> { - if (!attacker.isAlive() || attacker.level() != entity.level()) - BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY_ENTITY); - }); - } - } + if ( + damageSource.getEntity() instanceof LivingEntity attacker && attacker.isAlive() && attacker + .level() == entity.level() + ) + BrainUtils.setMemory(brain, MemoryModuleType.HURT_BY_ENTITY, attacker); + } else { + BrainUtils.withMemory(brain, MemoryModuleType.HURT_BY_ENTITY, attacker -> { + if (!attacker.isAlive() || attacker.level() != entity.level()) + BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY_ENTITY); + }); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/InWaterSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/InWaterSensor.java index 6960b2444..00f29ab24 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/InWaterSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/InWaterSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -12,47 +11,47 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.sensing.SensorType; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; -import java.util.List; - /** - * A sensor that sets or clears the {@link MemoryModuleType#IS_IN_WATER} memory - * depending on certain criteria.
    + * A sensor that sets or clears the {@link MemoryModuleType#IS_IN_WATER} memory depending on certain criteria.
    * Defaults: *
      *
    • {@link LivingEntity#isInWater()}
    • *
    - * + * * @param The entity */ public class InWaterSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.IS_IN_WATER); - - public InWaterSensor() { - super((entity2, entity) -> entity.isInWater()); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.IN_WATER.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - if (predicate().test(entity, entity)) { - BrainUtils.setMemory(entity, MemoryModuleType.IS_IN_WATER, Unit.INSTANCE); - } - else { - BrainUtils.clearMemory(entity, MemoryModuleType.IS_IN_WATER); - } - } + + private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.IS_IN_WATER); + + public InWaterSensor() { + super((entity2, entity) -> entity.isInWater()); + } + + @Override + public List> memoriesUsed() { + return MEMORIES; + } + + @Override + public SensorType> type() { + return SBLSensors.IN_WATER.get(); + } + + @Override + protected void doTick(ServerLevel level, E entity) { + if (predicate().test(entity, entity)) { + BrainUtils.setMemory(entity, MemoryModuleType.IS_IN_WATER, Unit.INSTANCE); + } else { + BrainUtils.clearMemory(entity, MemoryModuleType.IS_IN_WATER); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/ItemTemptingSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/ItemTemptingSensor.java index bc43fb7cc..bece8b489 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/ItemTemptingSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/ItemTemptingSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -14,6 +13,11 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; + +import java.util.Comparator; +import java.util.List; +import java.util.function.BiPredicate; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; import mod.azure.azurelib.sblforked.object.SquareRadius; @@ -21,112 +25,117 @@ import mod.azure.azurelib.sblforked.util.BrainUtils; import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; -import java.util.Comparator; -import java.util.List; -import java.util.function.BiPredicate; - /** - * Find the nearest player that is holding out a tempting item for the entity. - * Defaults: + * Find the nearest player that is holding out a tempting item for the entity. Defaults: *
      *
    • 10x10x10 Radius
    • *
    • No spectators
    • *
    - * + * * @see net.minecraft.world.entity.ai.sensing.TemptingSensor * @param The entity */ public class ItemTemptingSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.TEMPTING_PLAYER); - - protected BiPredicate temptPredicate = (entity, stack) -> false; - protected SquareRadius radius = new SquareRadius(10, 10); - - public ItemTemptingSensor() { - setPredicate((target, entity) -> { - if (target.isSpectator() || !target.isAlive()) - return false; - - return this.temptPredicate.test(entity, target.getMainHandItem()) || this.temptPredicate.test(entity, target.getOffhandItem()); - }); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.ITEM_TEMPTING.get(); - } - - /** - * Set the items to temptable items for the entity. - * - * @param temptingItems An ingredient representing the temptations for the - * entity - * @deprecated Use {@link ItemTemptingSensor#temptedWith} - * @return this - */ - @Deprecated(forRemoval = true) - public ItemTemptingSensor setTemptingItems(Ingredient temptingItems) { - return temptedWith((entity, stack) -> temptingItems.test(stack)); - } - - /** - * Set the items to temptable items for the entity. - * - * @param predicate An ingredient representing the temptations for the - * entity - * @return this - */ - public ItemTemptingSensor temptedWith(final BiPredicate predicate) { - this.temptPredicate = predicate; - - return this; - } - - /** - * Set the radius for the player sensor to scan - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public ItemTemptingSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the player sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public ItemTemptingSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Player player; - final List nearbyPlayers = BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_PLAYERS); - - if (nearbyPlayers != null) { - player = nearbyPlayers.stream().filter(pl -> predicate().test(pl, entity)).min(Comparator.comparing(pl -> pl.distanceToSqr(entity))).orElse(null); - } - else { - player = EntityRetrievalUtil.getNearestPlayer(entity, this.radius.xzRadius(), this.radius.yRadius(), this.radius.xzRadius(), target -> predicate().test(target, entity)); - } - - if (player == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.TEMPTING_PLAYER); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.TEMPTING_PLAYER, player); - } - } + + private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.TEMPTING_PLAYER); + + protected BiPredicate temptPredicate = (entity, stack) -> false; + + protected SquareRadius radius = new SquareRadius(10, 10); + + public ItemTemptingSensor() { + setPredicate((target, entity) -> { + if (target.isSpectator() || !target.isAlive()) + return false; + + return this.temptPredicate.test(entity, target.getMainHandItem()) || this.temptPredicate.test( + entity, + target.getOffhandItem() + ); + }); + } + + @Override + public List> memoriesUsed() { + return MEMORIES; + } + + @Override + public SensorType> type() { + return SBLSensors.ITEM_TEMPTING.get(); + } + + /** + * Set the items to temptable items for the entity. + * + * @param temptingItems An ingredient representing the temptations for the entity + * @deprecated Use {@link ItemTemptingSensor#temptedWith} + * @return this + */ + @Deprecated(forRemoval = true) + public ItemTemptingSensor setTemptingItems(Ingredient temptingItems) { + return temptedWith((entity, stack) -> temptingItems.test(stack)); + } + + /** + * Set the items to temptable items for the entity. + * + * @param predicate An ingredient representing the temptations for the entity + * @return this + */ + public ItemTemptingSensor temptedWith(final BiPredicate predicate) { + this.temptPredicate = predicate; + + return this; + } + + /** + * Set the radius for the player sensor to scan + * + * @param radius The coordinate radius, in blocks + * @return this + */ + public ItemTemptingSensor setRadius(double radius) { + return setRadius(radius, radius); + } + + /** + * Set the radius for the player sensor to scan. + * + * @param xz The X/Z coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks + * @return this + */ + public ItemTemptingSensor setRadius(double xz, double y) { + this.radius = new SquareRadius(xz, y); + + return this; + } + + @Override + protected void doTick(ServerLevel level, E entity) { + Player player; + final List nearbyPlayers = BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_PLAYERS); + + if (nearbyPlayers != null) { + player = nearbyPlayers.stream() + .filter(pl -> predicate().test(pl, entity)) + .min(Comparator.comparing(pl -> pl.distanceToSqr(entity))) + .orElse(null); + } else { + player = EntityRetrievalUtil.getNearestPlayer( + entity, + this.radius.xzRadius(), + this.radius.yRadius(), + this.radius.xzRadius(), + target -> predicate().test(target, entity) + ); + } + + if (player == null) { + BrainUtils.clearMemory(entity, MemoryModuleType.TEMPTING_PLAYER); + } else { + BrainUtils.setMemory(entity, MemoryModuleType.TEMPTING_PLAYER, player); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyAdultSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyAdultSensor.java index 0e89466a6..44b41040b 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyAdultSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyAdultSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -11,40 +10,41 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; import org.jetbrains.annotations.Nullable; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; +import mod.azure.azurelib.sblforked.registry.SBLSensors; + /** - * A sensor that sets the {@link MemoryModuleType#NEAREST_VISIBLE_ADULT} memory - * by checking the existing visible entities for nearby adults of the same - * entity type.
    - * + * A sensor that sets the {@link MemoryModuleType#NEAREST_VISIBLE_ADULT} memory by checking the existing visible + * entities for nearby adults of the same entity type.
    + * * @see net.minecraft.world.entity.ai.sensing.AdultSensor * @param The entity */ public class NearbyAdultSensor extends EntityFilteringSensor { - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_VISIBLE_ADULT; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_ADULT.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> target.getType() == entity.getType() && !target.isBaby(); - } - - @Nullable - @Override - protected AgeableMob findMatches(E entity, NearestVisibleLivingEntities matcher) { - return (AgeableMob) matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } + + @Override + public MemoryModuleType getMemory() { + return MemoryModuleType.NEAREST_VISIBLE_ADULT; + } + + @Override + public SensorType> type() { + return SBLSensors.NEARBY_ADULT.get(); + } + + @Override + protected BiPredicate predicate() { + return (target, entity) -> target.getType() == entity.getType() && !target.isBaby(); + } + + @Nullable + @Override + protected AgeableMob findMatches(E entity, NearestVisibleLivingEntities matcher) { + return (AgeableMob) matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyBabySensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyBabySensor.java index 4bff95125..4c2debe9d 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyBabySensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyBabySensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -11,41 +10,42 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; +import mod.azure.azurelib.sblforked.registry.SBLSensors; + /** - * A sensor that sets the {@link MemoryModuleType#VISIBLE_VILLAGER_BABIES} - * memory by checking the existing visible entities for nearby babies of the - * same entity type.
    - * + * A sensor that sets the {@link MemoryModuleType#VISIBLE_VILLAGER_BABIES} memory by checking the existing visible + * entities for nearby babies of the same entity type.
    + * * @see net.minecraft.world.entity.ai.sensing.VillagerBabiesSensor * @param The entity */ public class NearbyBabySensor extends EntityFilteringSensor, E> { - @Override - public MemoryModuleType> getMemory() { - return MemoryModuleType.VISIBLE_VILLAGER_BABIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_BABY.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> target.getType() == entity.getType() && target.isBaby(); - } - - @Nullable - @Override - protected List findMatches(E entity, NearestVisibleLivingEntities matcher) { - return ImmutableList.copyOf(matcher.findAll(target -> predicate().test(target, entity))); - } + + @Override + public MemoryModuleType> getMemory() { + return MemoryModuleType.VISIBLE_VILLAGER_BABIES; + } + + @Override + public SensorType> type() { + return SBLSensors.NEARBY_BABY.get(); + } + + @Override + protected BiPredicate predicate() { + return (target, entity) -> target.getType() == entity.getType() && target.isBaby(); + } + + @Nullable + @Override + protected List findMatches(E entity, NearestVisibleLivingEntities matcher) { + return ImmutableList.copyOf(matcher.findAll(target -> predicate().test(target, entity))); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyGolemSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyGolemSensor.java index bb908d297..9e8d6f887 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyGolemSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyGolemSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -12,72 +11,80 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.sensing.SensorType; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; -import java.util.List; - /** - * A sensor that sets the {@link MemoryModuleType#GOLEM_DETECTED_RECENTLY} - * memory by checking if any of the detected nearby entities are - * {@link net.minecraft.world.entity.animal.IronGolem Iron Golems}.
    + * A sensor that sets the {@link MemoryModuleType#GOLEM_DETECTED_RECENTLY} memory by checking if any of the detected + * nearby entities are {@link net.minecraft.world.entity.animal.IronGolem Iron Golems}.
    * Defaults: *
      *
    • 200-tick scan rate
    • *
    • Only detects vanilla Iron Golems
    • *
    • Remembers the nearby golem for 600 ticks
    • *
    - * + * * @see net.minecraft.world.entity.ai.sensing.GolemSensor * @param The entity */ public class NearbyGolemSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.GOLEM_DETECTED_RECENTLY); - private int timeToRemember = 600; + private static final List> MEMORIES = ObjectArrayList.of( + MemoryModuleType.GOLEM_DETECTED_RECENTLY + ); + + private int timeToRemember = 600; - public NearbyGolemSensor() { - setScanRate(entity -> 200); - setPredicate((target, entity) -> target.getType() == EntityType.IRON_GOLEM && target.isAlive()); - } + public NearbyGolemSensor() { + setScanRate(entity -> 200); + setPredicate((target, entity) -> target.getType() == EntityType.IRON_GOLEM && target.isAlive()); + } - /** - * Set the amount of ticks the entity should remember that the golem is there. - * - * @param ticks The number of ticks to remember for - * @return this - */ - public NearbyGolemSensor setMemoryTime(int ticks) { - this.timeToRemember = ticks; + /** + * Set the amount of ticks the entity should remember that the golem is there. + * + * @param ticks The number of ticks to remember for + * @return this + */ + public NearbyGolemSensor setMemoryTime(int ticks) { + this.timeToRemember = ticks; - return this; - } + return this; + } - @Override - public List> memoriesUsed() { - return MEMORIES; - } + @Override + public List> memoriesUsed() { + return MEMORIES; + } - @Override - public SensorType> type() { - return SBLSensors.NEARBY_GOLEM.get(); - } + @Override + public SensorType> type() { + return SBLSensors.NEARBY_GOLEM.get(); + } - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.withMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entityList -> { - if (entityList.isEmpty()) - return; + @Override + protected void doTick(ServerLevel level, E entity) { + BrainUtils.withMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entityList -> { + if (entityList.isEmpty()) + return; - for (LivingEntity target : entityList) { - if (predicate().test(target, entity)) { - BrainUtils.setForgettableMemory(entity, MemoryModuleType.GOLEM_DETECTED_RECENTLY, true, this.timeToRemember); + for (LivingEntity target : entityList) { + if (predicate().test(target, entity)) { + BrainUtils.setForgettableMemory( + entity, + MemoryModuleType.GOLEM_DETECTED_RECENTLY, + true, + this.timeToRemember + ); - return; - } - } - }); - } + return; + } + } + }); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyHostileSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyHostileSensor.java index efbd5b5b4..e2d916e16 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyHostileSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyHostileSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -13,92 +12,93 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.function.BiPredicate; +import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; +import mod.azure.azurelib.sblforked.registry.SBLSensors; + /** - * A sensor that sets the {@link MemoryModuleType#NEAREST_HOSTILE} memory by - * checking the existing visible entities for nearby hostiles.
    - * By default, this is used for villager hostile detection, but it can be - * configured at instantiation for any types. - * + * A sensor that sets the {@link MemoryModuleType#NEAREST_HOSTILE} memory by checking the existing visible entities for + * nearby hostiles.
    + * By default, this is used for villager hostile detection, but it can be configured at instantiation for any types. + * * @see net.minecraft.world.entity.ai.sensing.VillagerHostilesSensor * @param The entity */ public class NearbyHostileSensor extends EntityFilteringSensor { - private final Map, Float> hostileDistanceMap = new Object2FloatOpenHashMap<>(11); - - public NearbyHostileSensor() { - setHostiles( - Pair.of(EntityType.DROWNED, 8f), - Pair.of(EntityType.HUSK, 8f), - Pair.of(EntityType.VEX, 8f), - Pair.of(EntityType.ZOMBIE, 8f), - Pair.of(EntityType.ZOMBIE_VILLAGER, 8f), - Pair.of(EntityType.VINDICATOR, 10f), - Pair.of(EntityType.ZOGLIN, 10f), - Pair.of(EntityType.EVOKER, 12f), - Pair.of(EntityType.ILLUSIONER, 12f), - Pair.of(EntityType.RAVAGER, 12f), - Pair.of(EntityType.PILLAGER, 15f)); - } - - /** - * Clear the hostile types map, and add all of the given entries. - * - * @param entries The collection of entity types and distances to set the - * hostile types map to - * @return this - */ - public NearbyHostileSensor setHostiles(Pair, Float>... entries) { - this.hostileDistanceMap.clear(); - - for (Pair, Float> entry : entries) { - this.hostileDistanceMap.put(entry.getFirst(), entry.getSecond()); - } - - return this; - } - - /** - * Add an entity type to the hostile types map. - * - * @param entry The entity type and distance to which it should be considered. - * @return this - */ - public NearbyHostileSensor addHostile(Pair, Float> entry) { - this.hostileDistanceMap.put(entry.getFirst(), entry.getSecond()); - - return this; - } - - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_HOSTILE; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_HOSTILE.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> { - Float distance = this.hostileDistanceMap.get(target.getType()); - - return distance != null && target.distanceToSqr(entity) <= distance * distance; - }; - } - - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } + + private final Map, Float> hostileDistanceMap = new Object2FloatOpenHashMap<>(11); + + public NearbyHostileSensor() { + setHostiles( + Pair.of(EntityType.DROWNED, 8f), + Pair.of(EntityType.HUSK, 8f), + Pair.of(EntityType.VEX, 8f), + Pair.of(EntityType.ZOMBIE, 8f), + Pair.of(EntityType.ZOMBIE_VILLAGER, 8f), + Pair.of(EntityType.VINDICATOR, 10f), + Pair.of(EntityType.ZOGLIN, 10f), + Pair.of(EntityType.EVOKER, 12f), + Pair.of(EntityType.ILLUSIONER, 12f), + Pair.of(EntityType.RAVAGER, 12f), + Pair.of(EntityType.PILLAGER, 15f) + ); + } + + /** + * Clear the hostile types map, and add all of the given entries. + * + * @param entries The collection of entity types and distances to set the hostile types map to + * @return this + */ + public NearbyHostileSensor setHostiles(Pair, Float>... entries) { + this.hostileDistanceMap.clear(); + + for (Pair, Float> entry : entries) { + this.hostileDistanceMap.put(entry.getFirst(), entry.getSecond()); + } + + return this; + } + + /** + * Add an entity type to the hostile types map. + * + * @param entry The entity type and distance to which it should be considered. + * @return this + */ + public NearbyHostileSensor addHostile(Pair, Float> entry) { + this.hostileDistanceMap.put(entry.getFirst(), entry.getSecond()); + + return this; + } + + @Override + public MemoryModuleType getMemory() { + return MemoryModuleType.NEAREST_HOSTILE; + } + + @Override + public SensorType> type() { + return SBLSensors.NEARBY_HOSTILE.get(); + } + + @Override + protected BiPredicate predicate() { + return (target, entity) -> { + Float distance = this.hostileDistanceMap.get(target.getType()); + + return distance != null && target.distanceToSqr(entity) <= distance * distance; + }; + } + + @Nullable + @Override + protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { + return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyLivingEntitySensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyLivingEntitySensor.java index 8d50fae93..43a59ea64 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyLivingEntitySensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyLivingEntitySensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -12,6 +11,11 @@ import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.sensing.SensorType; +import org.jetbrains.annotations.Nullable; + +import java.util.Comparator; +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; import mod.azure.azurelib.sblforked.object.FixedNearestVisibleLivingEntities; @@ -19,82 +23,87 @@ import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; -import org.jetbrains.annotations.Nullable; - -import java.util.Comparator; -import java.util.List; /** - * A sensor that looks for nearby living entities in the surrounding area, - * sorted by proximity to the brain owner.
    + * A sensor that looks for nearby living entities in the surrounding area, sorted by proximity to the brain owner.
    * Defaults: *
      - *
    • Radius is equivalent to the entity's - * {@link Attributes#FOLLOW_RANGE} - * attribute
    • + *
    • Radius is equivalent to the entity's {@link Attributes#FOLLOW_RANGE} attribute
    • *
    • Only alive entities
    • *
    - * + * * @param The entity */ public class NearbyLivingEntitySensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); - - @Nullable - protected SquareRadius radius = null; - - public NearbyLivingEntitySensor() { - super((target, entity) -> target != entity && target.isAlive()); - } - - /** - * Set the radius for the sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyLivingEntitySensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyLivingEntitySensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_LIVING_ENTITY.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - SquareRadius radius = this.radius; - - if (radius == null) { - double dist = entity.getAttributeValue(Attributes.FOLLOW_RANGE); - - radius = new SquareRadius(dist, dist); - } - - List entities = EntityRetrievalUtil.getEntities(level, entity.getBoundingBox().inflate(radius.xzRadius(), radius.yRadius(), radius.xzRadius()), obj -> obj instanceof LivingEntity livingEntity && predicate().test(livingEntity, entity)); - - entities.sort(Comparator.comparingDouble(entity::distanceToSqr)); - - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities); - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, new FixedNearestVisibleLivingEntities(entity, entities)); - } + + private static final List> MEMORIES = ObjectArrayList.of( + MemoryModuleType.NEAREST_LIVING_ENTITIES, + MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES + ); + + @Nullable + protected SquareRadius radius = null; + + public NearbyLivingEntitySensor() { + super((target, entity) -> target != entity && target.isAlive()); + } + + /** + * Set the radius for the sensor to scan. + * + * @param radius The coordinate radius, in blocks + * @return this + */ + public NearbyLivingEntitySensor setRadius(double radius) { + return setRadius(radius, radius); + } + + /** + * Set the radius for the sensor to scan. + * + * @param xz The X/Z coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks + * @return this + */ + public NearbyLivingEntitySensor setRadius(double xz, double y) { + this.radius = new SquareRadius(xz, y); + + return this; + } + + @Override + public List> memoriesUsed() { + return MEMORIES; + } + + @Override + public SensorType> type() { + return SBLSensors.NEARBY_LIVING_ENTITY.get(); + } + + @Override + protected void doTick(ServerLevel level, E entity) { + SquareRadius radius = this.radius; + + if (radius == null) { + double dist = entity.getAttributeValue(Attributes.FOLLOW_RANGE); + + radius = new SquareRadius(dist, dist); + } + + List entities = EntityRetrievalUtil.getEntities( + level, + entity.getBoundingBox().inflate(radius.xzRadius(), radius.yRadius(), radius.xzRadius()), + obj -> obj instanceof LivingEntity livingEntity && predicate().test(livingEntity, entity) + ); + + entities.sort(Comparator.comparingDouble(entity::distanceToSqr)); + + BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities); + BrainUtils.setMemory( + entity, + MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, + new FixedNearestVisibleLivingEntities(entity, entities) + ); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyPlayersSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyPlayersSensor.java index 3d09cdbb2..c70fbfb52 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyPlayersSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyPlayersSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -13,97 +12,112 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.sensing.SensorType; import net.minecraft.world.entity.player.Player; +import org.jetbrains.annotations.Nullable; + +import java.util.Comparator; +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; import mod.azure.azurelib.sblforked.object.SquareRadius; import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; -import org.jetbrains.annotations.Nullable; - -import java.util.Comparator; -import java.util.List; /** - * A sensor that looks for nearby players in the surrounding area, sorted by - * proximity to the brain owner.
    + * A sensor that looks for nearby players in the surrounding area, sorted by proximity to the brain owner.
    * Defaults: *
      - *
    • Radius is equivalent to the entity's - * {@link Attributes#FOLLOW_RANGE} - * attribute
    • + *
    • Radius is equivalent to the entity's {@link Attributes#FOLLOW_RANGE} attribute
    • *
    • No spectators
    • *
    - * + * * @param The entity */ public class NearbyPlayersSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_PLAYERS, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER); - - @Nullable - protected SquareRadius radius = null; - - public NearbyPlayersSensor() { - super((player, entity) -> !player.isSpectator()); - } - - /** - * Set the radius for the sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyPlayersSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyPlayersSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_PLAYERS.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - SquareRadius radius = this.radius; - - if (radius == null) { - double dist = entity.getAttributeValue(Attributes.FOLLOW_RANGE); - - radius = new SquareRadius(dist, dist); - } - - List players = EntityRetrievalUtil.getPlayers(level, radius.inflateAABB(entity.getBoundingBox()), player -> predicate().test(player, entity)); - - players.sort(Comparator.comparingDouble(entity::distanceToSqr)); - - List targetablePlayers = new ObjectArrayList<>(players); - - targetablePlayers.removeIf(pl -> !isEntityTargetable(entity, pl)); - - List attackablePlayers = new ObjectArrayList<>(targetablePlayers); - - attackablePlayers.removeIf(pl -> !isEntityAttackable(entity, pl)); - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_PLAYERS, players); - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_VISIBLE_PLAYER, targetablePlayers.isEmpty() ? null : targetablePlayers.get(0)); - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, attackablePlayers.isEmpty() ? null : attackablePlayers.get(0)); - } + private static final List> MEMORIES = ObjectArrayList.of( + MemoryModuleType.NEAREST_PLAYERS, + MemoryModuleType.NEAREST_VISIBLE_PLAYER, + MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER + ); + + @Nullable + protected SquareRadius radius = null; + + public NearbyPlayersSensor() { + super((player, entity) -> !player.isSpectator()); + } + + /** + * Set the radius for the sensor to scan. + * + * @param radius The coordinate radius, in blocks + * @return this + */ + public NearbyPlayersSensor setRadius(double radius) { + return setRadius(radius, radius); + } + + /** + * Set the radius for the sensor to scan. + * + * @param xz The X/Z coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks + * @return this + */ + public NearbyPlayersSensor setRadius(double xz, double y) { + this.radius = new SquareRadius(xz, y); + + return this; + } + + @Override + public List> memoriesUsed() { + return MEMORIES; + } + + @Override + public SensorType> type() { + return SBLSensors.NEARBY_PLAYERS.get(); + } + + @Override + protected void doTick(ServerLevel level, E entity) { + SquareRadius radius = this.radius; + + if (radius == null) { + double dist = entity.getAttributeValue(Attributes.FOLLOW_RANGE); + + radius = new SquareRadius(dist, dist); + } + + List players = EntityRetrievalUtil.getPlayers( + level, + radius.inflateAABB(entity.getBoundingBox()), + player -> predicate().test(player, entity) + ); + + players.sort(Comparator.comparingDouble(entity::distanceToSqr)); + + List targetablePlayers = new ObjectArrayList<>(players); + + targetablePlayers.removeIf(pl -> !isEntityTargetable(entity, pl)); + + List attackablePlayers = new ObjectArrayList<>(targetablePlayers); + + attackablePlayers.removeIf(pl -> !isEntityAttackable(entity, pl)); + + BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_PLAYERS, players); + BrainUtils.setMemory( + entity, + MemoryModuleType.NEAREST_VISIBLE_PLAYER, + targetablePlayers.isEmpty() ? null : targetablePlayers.get(0) + ); + BrainUtils.setMemory( + entity, + MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, + attackablePlayers.isEmpty() ? null : attackablePlayers.get(0) + ); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestHomeSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestHomeSensor.java index 7bd595a53..75ce366f8 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestHomeSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestHomeSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -20,90 +19,98 @@ import net.minecraft.world.entity.ai.village.poi.PoiType; import net.minecraft.world.entity.ai.village.poi.PoiTypes; import net.minecraft.world.level.pathfinder.Path; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; import java.util.List; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; +import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; +import mod.azure.azurelib.sblforked.registry.SBLSensors; +import mod.azure.azurelib.sblforked.util.BrainUtils; + /** - * A sensor that looks for the nearest home point of interest in the surrounding - * area.
    + * A sensor that looks for the nearest home point of interest in the surrounding area.
    * Defaults: *
      *
    • 48 block radius
    • *
    • Only runs if the owner of the brain is a baby
    • *
    - * + * * @param The entity */ public class NearestHomeSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_BED); - - protected int radius = 48; - - private final Object2LongOpenHashMap homesMap = new Object2LongOpenHashMap<>(5); - private int tries = 0; - - public NearestHomeSensor() { - super((brainOwner, entity) -> brainOwner.isBaby()); - } - - /** - * Set the radius for the item sensor to scan - * - * @param radius The radius - * @return this - */ - public NearestHomeSensor setRadius(int radius) { - this.radius = radius; - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEAREST_HOME.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - if (!predicate().test(entity, entity)) - return; - - this.tries = 0; - long nodeExpiryTime = level.getGameTime() + level.getRandom().nextInt(20); - PoiManager poiManager = level.getPoiManager(); - Predicate predicate = pos -> { - if (this.homesMap.containsKey(pos)) - return false; - - if (++this.tries >= 5) - return false; - - this.homesMap.put(pos, nodeExpiryTime + 40); - - return true; - }; - Set, BlockPos>> poiLocations = poiManager.findAllWithType(poiType -> poiType.is(PoiTypes.HOME), predicate, entity.blockPosition(), this.radius, PoiManager.Occupancy.ANY).collect(Collectors.toSet()); - Path pathToHome = AcquirePoi.findPathToPois(entity, poiLocations); - - if (pathToHome != null && pathToHome.canReach()) { - BlockPos targetPos = pathToHome.getTarget(); - - poiManager.getType(targetPos).ifPresent(poiType -> BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_BED, targetPos)); - } - else if (this.tries < 5) { - this.homesMap.object2LongEntrySet().removeIf(pos -> pos.getLongValue() < nodeExpiryTime); - } - } + + private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_BED); + + protected int radius = 48; + + private final Object2LongOpenHashMap homesMap = new Object2LongOpenHashMap<>(5); + + private int tries = 0; + + public NearestHomeSensor() { + super((brainOwner, entity) -> brainOwner.isBaby()); + } + + /** + * Set the radius for the item sensor to scan + * + * @param radius The radius + * @return this + */ + public NearestHomeSensor setRadius(int radius) { + this.radius = radius; + + return this; + } + + @Override + public List> memoriesUsed() { + return MEMORIES; + } + + @Override + public SensorType> type() { + return SBLSensors.NEAREST_HOME.get(); + } + + @Override + protected void doTick(ServerLevel level, E entity) { + if (!predicate().test(entity, entity)) + return; + + this.tries = 0; + long nodeExpiryTime = level.getGameTime() + level.getRandom().nextInt(20); + PoiManager poiManager = level.getPoiManager(); + Predicate predicate = pos -> { + if (this.homesMap.containsKey(pos)) + return false; + + if (++this.tries >= 5) + return false; + + this.homesMap.put(pos, nodeExpiryTime + 40); + + return true; + }; + Set, BlockPos>> poiLocations = poiManager.findAllWithType( + poiType -> poiType.is(PoiTypes.HOME), + predicate, + entity.blockPosition(), + this.radius, + PoiManager.Occupancy.ANY + ).collect(Collectors.toSet()); + Path pathToHome = AcquirePoi.findPathToPois(entity, poiLocations); + + if (pathToHome != null && pathToHome.canReach()) { + BlockPos targetPos = pathToHome.getTarget(); + + poiManager.getType(targetPos) + .ifPresent(poiType -> BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_BED, targetPos)); + } else if (this.tries < 5) { + this.homesMap.object2LongEntrySet().removeIf(pos -> pos.getLongValue() < nodeExpiryTime); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestItemSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestItemSensor.java index ed1e232c8..899fdb1e2 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestItemSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestItemSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -14,6 +13,9 @@ import net.minecraft.world.entity.ai.sensing.SensorType; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; import mod.azure.azurelib.sblforked.object.SquareRadius; @@ -21,64 +23,73 @@ import mod.azure.azurelib.sblforked.util.BrainUtils; import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; -import java.util.List; - /** * A sensor that looks for the nearest item entity in the surrounding area.
    * Defaults: *
      *
    • 32x16x32 radius
    • *
    • Only items that return true for {@link Mob#wantsToPickUp(ItemStack)}
    • - *
    • Only items that return true for - * {@link net.minecraft.world.entity.LivingEntity#hasLineOfSight(Entity)}
    • + *
    • Only items that return true for {@link net.minecraft.world.entity.LivingEntity#hasLineOfSight(Entity)}
    • *
    - * + * * @param The entity */ public class NearestItemSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM); - protected SquareRadius radius = new SquareRadius(32, 16); + private static final List> MEMORIES = ObjectArrayList.of( + MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM + ); + + protected SquareRadius radius = new SquareRadius(32, 16); - public NearestItemSensor() { - super((item, entity) -> entity.wantsToPickUp(item.getItem()) && entity.hasLineOfSight(item)); - } + public NearestItemSensor() { + super((item, entity) -> entity.wantsToPickUp(item.getItem()) && entity.hasLineOfSight(item)); + } - /** - * Set the radius for the item sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearestItemSensor setRadius(double radius) { - return setRadius(radius, radius); - } + /** + * Set the radius for the item sensor to scan. + * + * @param radius The coordinate radius, in blocks + * @return this + */ + public NearestItemSensor setRadius(double radius) { + return setRadius(radius, radius); + } - /** - * Set the radius for the item sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearestItemSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); + /** + * Set the radius for the item sensor to scan. + * + * @param xz The X/Z coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks + * @return this + */ + public NearestItemSensor setRadius(double xz, double y) { + this.radius = new SquareRadius(xz, y); - return this; - } + return this; + } - @Override - public List> memoriesUsed() { - return MEMORIES; - } + @Override + public List> memoriesUsed() { + return MEMORIES; + } - @Override - public SensorType> type() { - return SBLSensors.NEAREST_ITEM.get(); - } + @Override + public SensorType> type() { + return SBLSensors.NEAREST_ITEM.get(); + } - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, EntityRetrievalUtil.getNearestEntity(level, this.radius.inflateAABB(entity.getBoundingBox()), entity.position(), obj -> obj instanceof ItemEntity item && predicate().test(item, entity))); - } + @Override + protected void doTick(ServerLevel level, E entity) { + BrainUtils.setMemory( + entity, + MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, + EntityRetrievalUtil.getNearestEntity( + level, + this.radius.inflateAABB(entity.getBoundingBox()), + entity.position(), + obj -> obj instanceof ItemEntity item && predicate().test(item, entity) + ) + ); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinBruteSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinBruteSpecificSensor.java index 90acabd85..2881b4552 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinBruteSpecificSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinBruteSpecificSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -17,46 +16,55 @@ import net.minecraft.world.entity.monster.WitherSkeleton; import net.minecraft.world.entity.monster.piglin.AbstractPiglin; import net.minecraft.world.entity.monster.piglin.Piglin; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; -import java.util.List; - /** - * A replication of vanilla's - * {@link net.minecraft.world.entity.ai.sensing.PiglinBruteSpecificSensor}. Not - * really useful, but included for completeness' sake and legibility.
    - * Keeps track of nearby {@link Piglin piglins} and - * {@link MemoryModuleType#NEAREST_VISIBLE_NEMESIS nemesis} - * + * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.PiglinBruteSpecificSensor}. Not really + * useful, but included for completeness' sake and legibility.
    + * Keeps track of nearby {@link Piglin piglins} and {@link MemoryModuleType#NEAREST_VISIBLE_NEMESIS nemesis} + * * @param The entity */ public class PiglinBruteSpecificSensor extends ExtendedSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEARBY_ADULT_PIGLINS); - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.PIGLIN_BRUTE_SPECIFIC.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - List nearbyPiglins = new ObjectArrayList<>(); - - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, entities -> BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_NEMESIS, (Mob)entities.findClosest(target -> target instanceof WitherSkeleton || target instanceof WitherBoss).orElse(null))); - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { - for (LivingEntity target : entities) { - if (target instanceof AbstractPiglin piglin && piglin.isAdult()) - nearbyPiglins.add(piglin); - } - }); - BrainUtils.setMemory(brain, MemoryModuleType.NEARBY_ADULT_PIGLINS, nearbyPiglins); - } + + private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEARBY_ADULT_PIGLINS); + + @Override + public List> memoriesUsed() { + return MEMORIES; + } + + @Override + public SensorType> type() { + return SBLSensors.PIGLIN_BRUTE_SPECIFIC.get(); + } + + @Override + protected void doTick(ServerLevel level, E entity) { + Brain brain = entity.getBrain(); + List nearbyPiglins = new ObjectArrayList<>(); + + BrainUtils.withMemory( + brain, + MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, + entities -> BrainUtils.setMemory( + brain, + MemoryModuleType.NEAREST_VISIBLE_NEMESIS, + (Mob) entities.findClosest(target -> target instanceof WitherSkeleton || target instanceof WitherBoss) + .orElse(null) + ) + ); + BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { + for (LivingEntity target : entities) { + if (target instanceof AbstractPiglin piglin && piglin.isAdult()) + nearbyPiglins.add(piglin); + } + }); + BrainUtils.setMemory(brain, MemoryModuleType.NEARBY_ADULT_PIGLINS, nearbyPiglins); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinSpecificSensor.java index 12f96a3c6..cde09fd1c 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinSpecificSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinSpecificSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -26,107 +25,131 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.CampfireBlock; import net.minecraft.world.level.block.state.BlockState; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; -import java.util.List; - /** - * A replication of vanilla's - * {@link net.minecraft.world.entity.ai.sensing.PiglinSpecificSensor}. Not - * really useful, but included for completeness' sake and legibility.
    + * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.PiglinSpecificSensor}. Not really useful, but + * included for completeness' sake and legibility.
    * Handles most of Piglin's memories at once. - * + * * @param The entity */ public class PiglinSpecificSensor extends ExtendedSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_VISIBLE_NEMESIS, MemoryModuleType.NEAREST_VISIBLE_HUNTABLE_HOGLIN, MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD, MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, MemoryModuleType.NEAREST_REPELLENT, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEARBY_ADULT_PIGLINS); - @Override - public List> memoriesUsed() { - return MEMORIES; - } + private static final List> MEMORIES = ObjectArrayList.of( + MemoryModuleType.NEAREST_VISIBLE_NEMESIS, + MemoryModuleType.NEAREST_VISIBLE_HUNTABLE_HOGLIN, + MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, + MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, + MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD, + MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM, + MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, + MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, + MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, + MemoryModuleType.NEAREST_REPELLENT, + MemoryModuleType.NEAREST_LIVING_ENTITIES, + MemoryModuleType.NEARBY_ADULT_PIGLINS + ); + + @Override + public List> memoriesUsed() { + return MEMORIES; + } - @Override - public SensorType> type() { - return SBLSensors.PIGLIN_SPECIFIC.get(); - } + @Override + public SensorType> type() { + return SBLSensors.PIGLIN_SPECIFIC.get(); + } - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - List adultPiglins = new ObjectArrayList<>(); + @Override + protected void doTick(ServerLevel level, E entity) { + Brain brain = entity.getBrain(); + List adultPiglins = new ObjectArrayList<>(); - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, entities -> { - Mob nemesis = null; - Hoglin nearestHuntableHoglin = null; - Hoglin nearestBabyHoglin = null; - LivingEntity nearestZombified = null; - Player nearestPlayerWithoutGold = null; - Player nearestPlayerWithWantedItem = null; - List visibleAdultPiglins = new ObjectArrayList<>(); - int adultHoglinCount = 0; + BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, entities -> { + Mob nemesis = null; + Hoglin nearestHuntableHoglin = null; + Hoglin nearestBabyHoglin = null; + LivingEntity nearestZombified = null; + Player nearestPlayerWithoutGold = null; + Player nearestPlayerWithWantedItem = null; + List visibleAdultPiglins = new ObjectArrayList<>(); + int adultHoglinCount = 0; - for (LivingEntity target : entities.findAll(obj -> true)) { - if (target instanceof Hoglin hoglin) { - if (hoglin.isBaby() && nearestBabyHoglin == null) { - nearestBabyHoglin = hoglin; - } - else if (hoglin.isAdult()) { - adultHoglinCount++; + for (LivingEntity target : entities.findAll(obj -> true)) { + if (target instanceof Hoglin hoglin) { + if (hoglin.isBaby() && nearestBabyHoglin == null) { + nearestBabyHoglin = hoglin; + } else if (hoglin.isAdult()) { + adultHoglinCount++; - if (nearestHuntableHoglin == null && hoglin.canBeHunted()) - nearestHuntableHoglin = hoglin; - } - } - else if (target instanceof PiglinBrute brute) { - visibleAdultPiglins.add(brute); - } - else if (target instanceof Piglin piglin) { - if (piglin.isAdult()) - visibleAdultPiglins.add(piglin); - } - else if (target instanceof Player player) { - if (nearestPlayerWithoutGold == null && !PiglinAi.isWearingGold(player) && entity.canAttack(player)) - nearestPlayerWithoutGold = player; + if (nearestHuntableHoglin == null && hoglin.canBeHunted()) + nearestHuntableHoglin = hoglin; + } + } else if (target instanceof PiglinBrute brute) { + visibleAdultPiglins.add(brute); + } else if (target instanceof Piglin piglin) { + if (piglin.isAdult()) + visibleAdultPiglins.add(piglin); + } else if (target instanceof Player player) { + if (nearestPlayerWithoutGold == null && !PiglinAi.isWearingGold(player) && entity.canAttack(player)) + nearestPlayerWithoutGold = player; - if (nearestPlayerWithWantedItem == null && !player.isSpectator() && PiglinAi.isPlayerHoldingLovedItem(player)) - nearestPlayerWithWantedItem = player; - } - else if (nemesis != null || !(target instanceof WitherSkeleton) && !(target instanceof WitherBoss)) { - if (nearestZombified == null && PiglinAi.isZombified(target.getType())) - nearestZombified = target; - } - else { - nemesis = (Mob) target; - } - } + if ( + nearestPlayerWithWantedItem == null && !player.isSpectator() && PiglinAi + .isPlayerHoldingLovedItem(player) + ) + nearestPlayerWithWantedItem = player; + } else if (nemesis != null || !(target instanceof WitherSkeleton) && !(target instanceof WitherBoss)) { + if (nearestZombified == null && PiglinAi.isZombified(target.getType())) + nearestZombified = target; + } else { + nemesis = (Mob) target; + } + } - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_NEMESIS, nemesis); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_HUNTABLE_HOGLIN, nearestHuntableHoglin); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, nearestBabyHoglin); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, nearestZombified); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD, nearestPlayerWithoutGold); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM, nearestPlayerWithWantedItem); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, visibleAdultPiglins); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, visibleAdultPiglins.size()); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, adultHoglinCount); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_REPELLENT, - BlockPos.findClosestMatch(entity.blockPosition(), 8, 4, pos -> { - BlockState state = level.getBlockState(pos); - boolean isRepellent = state.is(BlockTags.PIGLIN_REPELLENTS); + BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_NEMESIS, nemesis); + BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_HUNTABLE_HOGLIN, nearestHuntableHoglin); + BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, nearestBabyHoglin); + BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, nearestZombified); + BrainUtils.setMemory( + brain, + MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD, + nearestPlayerWithoutGold + ); + BrainUtils.setMemory( + brain, + MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM, + nearestPlayerWithWantedItem + ); + BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, visibleAdultPiglins); + BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, visibleAdultPiglins.size()); + BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, adultHoglinCount); + BrainUtils.setMemory( + brain, + MemoryModuleType.NEAREST_REPELLENT, + BlockPos.findClosestMatch(entity.blockPosition(), 8, 4, pos -> { + BlockState state = level.getBlockState(pos); + boolean isRepellent = state.is(BlockTags.PIGLIN_REPELLENTS); - return isRepellent && state.is(Blocks.SOUL_CAMPFIRE) ? CampfireBlock.isLitCampfire(state) : isRepellent; - }).orElse(null)); - }); + return isRepellent && state.is(Blocks.SOUL_CAMPFIRE) + ? CampfireBlock.isLitCampfire(state) + : isRepellent; + }).orElse(null) + ); + }); - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { - for (LivingEntity target : entities) { - if (target instanceof AbstractPiglin piglin && piglin.isAdult()) - adultPiglins.add(piglin); - } - }); - BrainUtils.setMemory(brain, MemoryModuleType.NEARBY_ADULT_PIGLINS, adultPiglins); - } + BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { + for (LivingEntity target : entities) { + if (target instanceof AbstractPiglin piglin && piglin.isAdult()) + adultPiglins.add(piglin); + } + }); + BrainUtils.setMemory(brain, MemoryModuleType.NEARBY_ADULT_PIGLINS, adultPiglins); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/SecondaryPoiSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/SecondaryPoiSensor.java index 9e4281282..f0d341f24 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/SecondaryPoiSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/SecondaryPoiSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -17,87 +16,96 @@ import net.minecraft.world.entity.npc.Villager; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.object.SquareRadius; import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; -import java.util.List; - /** - * A sensor that looks for a nearby - * {@link net.minecraft.world.entity.ai.village.poi.PoiTypes POI} block that - * matches a villager's secondary profession.
    + * A sensor that looks for a nearby {@link net.minecraft.world.entity.ai.village.poi.PoiTypes POI} block that matches a + * villager's secondary profession.
    * Defaults: *
      *
    • 40-tick scan rate
    • *
    • 8x4x8 radius
    • *
    - * + * * @param The entity */ public class SecondaryPoiSensor extends ExtendedSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.SECONDARY_JOB_SITE); - - protected SquareRadius radius = new SquareRadius(8, 4); - - public SecondaryPoiSensor() { - setScanRate(entity -> 40); - } - - /** - * Set the radius for the sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public SecondaryPoiSensor setRadius(int radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SecondaryPoiSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.SECONDARY_POI.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - ResourceKey dimension = level.dimension(); - BlockPos pos = entity.blockPosition(); - ImmutableSet testPoiBlocks = entity.getVillagerData().getProfession().secondaryPoi(); - List poiPositions = new ObjectArrayList<>(); - - if (testPoiBlocks.isEmpty()) - return; - - for (BlockPos testPos : BlockPos.betweenClosed(pos.getX() - (int) this.radius.xzRadius() / 2, pos.getY() - (int) this.radius.yRadius() / 2, pos.getZ() - (int) this.radius.xzRadius() / 2, pos.getX() + (int) this.radius.xzRadius() / 2, pos.getY() + (int) this.radius.yRadius() / 2, pos.getZ() + (int) this.radius.xzRadius() / 2)) { - if (testPoiBlocks.contains(level.getBlockState(testPos).getBlock())) - poiPositions.add(GlobalPos.of(dimension, testPos.immutable())); - } - - if (poiPositions.isEmpty()) { - BrainUtils.clearMemory(entity, MemoryModuleType.SECONDARY_JOB_SITE); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.SECONDARY_JOB_SITE, poiPositions); - } - } + + private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.SECONDARY_JOB_SITE); + + protected SquareRadius radius = new SquareRadius(8, 4); + + public SecondaryPoiSensor() { + setScanRate(entity -> 40); + } + + /** + * Set the radius for the sensor to scan. + * + * @param radius The coordinate radius, in blocks + * @return this + */ + public SecondaryPoiSensor setRadius(int radius) { + return setRadius(radius, radius); + } + + /** + * Set the radius for the sensor to scan + * + * @param xz The X/Z coordinate radius, in blocks + * @param y The Y coordinate radius, in blocks + * @return this + */ + public SecondaryPoiSensor setRadius(double xz, double y) { + this.radius = new SquareRadius(xz, y); + + return this; + } + + @Override + public List> memoriesUsed() { + return MEMORIES; + } + + @Override + public SensorType> type() { + return SBLSensors.SECONDARY_POI.get(); + } + + @Override + protected void doTick(ServerLevel level, E entity) { + ResourceKey dimension = level.dimension(); + BlockPos pos = entity.blockPosition(); + ImmutableSet testPoiBlocks = entity.getVillagerData().getProfession().secondaryPoi(); + List poiPositions = new ObjectArrayList<>(); + + if (testPoiBlocks.isEmpty()) + return; + + for ( + BlockPos testPos : BlockPos.betweenClosed( + pos.getX() - (int) this.radius.xzRadius() / 2, + pos.getY() - (int) this.radius.yRadius() / 2, + pos.getZ() - (int) this.radius.xzRadius() / 2, + pos.getX() + (int) this.radius.xzRadius() / 2, + pos.getY() + (int) this.radius.yRadius() / 2, + pos.getZ() + (int) this.radius.xzRadius() / 2 + ) + ) { + if (testPoiBlocks.contains(level.getBlockState(testPos).getBlock())) + poiPositions.add(GlobalPos.of(dimension, testPos.immutable())); + } + + if (poiPositions.isEmpty()) { + BrainUtils.clearMemory(entity, MemoryModuleType.SECONDARY_JOB_SITE); + } else { + BrainUtils.setMemory(entity, MemoryModuleType.SECONDARY_JOB_SITE, poiPositions); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/WardenSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/WardenSpecificSensor.java index 91f1f4eec..f796b4863 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/WardenSpecificSensor.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/WardenSpecificSensor.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; @@ -13,59 +12,61 @@ import net.minecraft.world.entity.ai.sensing.SensorType; import net.minecraft.world.entity.monster.warden.Warden; import net.minecraft.world.entity.player.Player; + +import java.util.List; + import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.registry.SBLSensors; import mod.azure.azurelib.sblforked.util.BrainUtils; -import java.util.List; - /** - * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.WardenEntitySensor}. Not really useful, but included for completeness' sake and legibility.
    + * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.WardenEntitySensor}. Not really useful, but + * included for completeness' sake and legibility.
    * Handle's the Warden's nearest attackable target, prioritising players. + * * @param The entity */ public class WardenSpecificSensor extends NearbyLivingEntitySensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_ATTACKABLE); - public WardenSpecificSensor() { - setRadius(24); - setPredicate((target, entity) -> entity.canTargetEntity(target)); - } + private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_ATTACKABLE); + + public WardenSpecificSensor() { + setRadius(24); + setPredicate((target, entity) -> entity.canTargetEntity(target)); + } - @Override - public List> memoriesUsed() { - return MEMORIES; - } + @Override + public List> memoriesUsed() { + return MEMORIES; + } - @Override - public SensorType> type() { - return SBLSensors.WARDEN_SPECIFIC.get(); - } + @Override + public SensorType> type() { + return SBLSensors.WARDEN_SPECIFIC.get(); + } - @Override - protected void doTick(ServerLevel level, E entity) { - super.doTick(level, entity); + @Override + protected void doTick(ServerLevel level, E entity) { + super.doTick(level, entity); - BrainUtils.withMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { - LivingEntity fallbackTarget = null; + BrainUtils.withMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { + LivingEntity fallbackTarget = null; - for (LivingEntity target : entities) { - if (target instanceof Player) { - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE, target); + for (LivingEntity target : entities) { + if (target instanceof Player) { + BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE, target); - return; - } - else if (fallbackTarget == null) { - fallbackTarget = target; - } - } + return; + } else if (fallbackTarget == null) { + fallbackTarget = target; + } + } - if (fallbackTarget != null) { - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE, fallbackTarget); - } - else { - BrainUtils.clearMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE); - } - }); - } + if (fallbackTarget != null) { + BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE, fallbackTarget); + } else { + BrainUtils.clearMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE); + } + }); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourConsumer.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourConsumer.java index 81d4c2468..493906f5a 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourConsumer.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourConsumer.java @@ -1,28 +1,30 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.object; import net.minecraft.world.entity.ai.behavior.BehaviorControl; import net.minecraft.world.entity.schedule.Activity; -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; + /** * Functional consumer for brain activity related functions */ @FunctionalInterface public interface BrainBehaviourConsumer { - /** - * Accepts the given behaviour and the information related to it - * @param priority The priority the behaviour is nested under - * @param activity The activity category the behaviour is under - * @param behaviour The behaviour - * @param parent The {@link net.minecraft.world.entity.ai.behavior.GateBehavior GateBehaviour} or {@link GroupBehaviour GroupBehaviour} - * the behaviour is a child of, if applicable - */ - void consume(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parent); + + /** + * Accepts the given behaviour and the information related to it + * + * @param priority The priority the behaviour is nested under + * @param activity The activity category the behaviour is under + * @param behaviour The behaviour + * @param parent The {@link net.minecraft.world.entity.ai.behavior.GateBehavior GateBehaviour} or + * {@link GroupBehaviour GroupBehaviour} the behaviour is a child of, if applicable + */ + void consume(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parent); } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourPredicate.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourPredicate.java index c6201d8d1..8ff5d784c 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourPredicate.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourPredicate.java @@ -1,28 +1,35 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.object; import net.minecraft.world.entity.ai.behavior.BehaviorControl; import net.minecraft.world.entity.schedule.Activity; -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; + /** * Functional interface to handle passing multiple arguments back for behaviour-predication handling */ @FunctionalInterface public interface BrainBehaviourPredicate { - /** - * Tests whether the given behaviour is relevant to the predicate. - * @param priority The priority the behaviour is nested under - * @param activity The activity category the behaviour is under - * @param behaviour The behaviour to check - * @param parentBehaviour The {@link net.minecraft.world.entity.ai.behavior.GateBehavior GateBehaviour} or {@link GroupBehaviour GroupBehaviour} - * the behaviour is a child of, if applicable - */ - boolean isBehaviour(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parentBehaviour); + + /** + * Tests whether the given behaviour is relevant to the predicate. + * + * @param priority The priority the behaviour is nested under + * @param activity The activity category the behaviour is under + * @param behaviour The behaviour to check + * @param parentBehaviour The {@link net.minecraft.world.entity.ai.behavior.GateBehavior GateBehaviour} or + * {@link GroupBehaviour GroupBehaviour} the behaviour is a child of, if applicable + */ + boolean isBehaviour( + int priority, + Activity activity, + BehaviorControl behaviour, + @Nullable BehaviorControl parentBehaviour + ); } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/ExtendedTargetingConditions.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/ExtendedTargetingConditions.java index f9c0da313..2d9dd70ac 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/ExtendedTargetingConditions.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/object/ExtendedTargetingConditions.java @@ -1,28 +1,34 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.object; import net.minecraft.world.Difficulty; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.attributes.Attributes; -import mod.azure.azurelib.sblforked.util.SensoryUtils; import org.jetbrains.annotations.Nullable; import java.util.function.BiPredicate; import java.util.function.Function; +import mod.azure.azurelib.sblforked.util.SensoryUtils; + /** - * Replacement for Vanilla's {@link net.minecraft.world.entity.ai.targeting.TargetingConditions} due to its somewhat limited implementation + * Replacement for Vanilla's {@link net.minecraft.world.entity.ai.targeting.TargetingConditions} due to its somewhat + * limited implementation */ public class ExtendedTargetingConditions { + protected BiPredicate customFilter = null; + protected Function rangeRetriever = null; + protected boolean isAttacking = true; + protected boolean checkLineOfSight = true; + protected boolean ignoresInvisibility = false; public static ExtendedTargetingConditions forLookTarget() { @@ -58,7 +64,8 @@ public ExtendedTargetingConditions withRange(double range) { } /** - * Filter out any targeting that occurs for entities larger than the distance provided by this function from the entity + * Filter out any targeting that occurs for entities larger than the distance provided by this function from the + * entity */ public ExtendedTargetingConditions withRange(Function function) { this.rangeRetriever = function; @@ -67,15 +74,24 @@ public ExtendedTargetingConditions withRange(Function func } /** - * Filter out any targeting that occurs for entities outside of the entity's {@link Attributes#FOLLOW_RANGE} attribute + * Filter out any targeting that occurs for entities outside of the entity's {@link Attributes#FOLLOW_RANGE} + * attribute */ public ExtendedTargetingConditions withFollowRange() { - return withRange(entity -> entity.getAttribute(Attributes.FOLLOW_RANGE) != null ? entity.getAttributeValue(Attributes.FOLLOW_RANGE) : 16d); + return withRange( + entity -> entity.getAttribute(Attributes.FOLLOW_RANGE) != null + ? entity.getAttributeValue(Attributes.FOLLOW_RANGE) + : 16d + ); } /** - * Additionally filter out any specific cases that may apply. This check is applied before any other conditions are checked - *

    Note that the targeting entity may be null, for generic checks

    + * Additionally filter out any specific cases that may apply. This check is applied before any other + * conditions are checked + *

    + * Note that the targeting entity may be null, for generic checks + *

    + * * @return true if the entity should be allowed to target the target, or false if not */ public ExtendedTargetingConditions onlyTargeting(BiPredicate<@Nullable LivingEntity, LivingEntity> predicate) { @@ -85,7 +101,8 @@ public ExtendedTargetingConditions onlyTargeting(BiPredicate<@Nullable LivingEnt } /** - * Skip the line of sight checks in the predicate. This can be useful for entities that track with other senses, or for other special-case situations + * Skip the line of sight checks in the predicate. This can be useful for entities that track with other senses, or + * for other special-case situations */ public ExtendedTargetingConditions ignoreLineOfSight() { this.checkLineOfSight = false; @@ -94,7 +111,8 @@ public ExtendedTargetingConditions ignoreLineOfSight() { } /** - * Skip the invisibility check for targeting. This is often used where the entity is already being targeted/tracked, and we're just checking for attackability. + * Skip the invisibility check for targeting. This is often used where the entity is already being targeted/tracked, + * and we're just checking for attackability. */ public ExtendedTargetingConditions skipInvisibilityCheck() { this.ignoresInvisibility = true; @@ -110,15 +128,22 @@ public boolean test(@Nullable LivingEntity entity, LivingEntity target) { return false; if (entity == null) - return !this.isAttacking || (target.canBeSeenAsEnemy() && target.level().getDifficulty() != Difficulty.PEACEFUL); + return !this.isAttacking || (target.canBeSeenAsEnemy() && target.level() + .getDifficulty() != Difficulty.PEACEFUL); - if (this.isAttacking && (!entity.canAttack(target) || !entity.canAttackType(target.getType()) || entity.isAlliedTo(target))) + if ( + this.isAttacking && (!entity.canAttack(target) || !entity.canAttackType(target.getType()) || entity + .isAlliedTo(target)) + ) return false; double range = this.rangeRetriever.apply(entity); if (range > 0) { - double sightRange = Math.max(range * (this.ignoresInvisibility ? 1 : target.getVisibilityPercent(entity)), 2); + double sightRange = Math.max( + range * (this.ignoresInvisibility ? 1 : target.getVisibilityPercent(entity)), + 2 + ); if (entity.distanceToSqr(target) > sightRange * sightRange) return false; diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/FixedNearestVisibleLivingEntities.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/FixedNearestVisibleLivingEntities.java index 2894024ba..be1d28b9b 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/FixedNearestVisibleLivingEntities.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/object/FixedNearestVisibleLivingEntities.java @@ -1,23 +1,25 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.object; import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import mod.azure.azurelib.sblforked.util.SensoryUtils; import java.util.List; import java.util.function.Predicate; +import mod.azure.azurelib.sblforked.util.SensoryUtils; + /** - * Wrapper for {@link NearestVisibleLivingEntities} that supports follow range for entities rather than a hardcoded 16-block limit + * Wrapper for {@link NearestVisibleLivingEntities} that supports follow range for entities rather than a hardcoded + * 16-block limit */ public class FixedNearestVisibleLivingEntities extends NearestVisibleLivingEntities { + private FixedNearestVisibleLivingEntities() { super(); } @@ -27,11 +29,15 @@ public FixedNearestVisibleLivingEntities(LivingEntity entity, List this.nearbyEntities = entities; this.lineOfSightTest = new Predicate<>() { + final Object2BooleanOpenHashMap cache = new Object2BooleanOpenHashMap<>(entities.size()); @Override public boolean test(LivingEntity target) { - return this.cache.computeIfAbsent(target, (Predicate)target1 -> SensoryUtils.isEntityTargetable(entity, target1)); + return this.cache.computeIfAbsent( + target, + (Predicate) target1 -> SensoryUtils.isEntityTargetable(entity, target1) + ); } }; } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/FreePositionTracker.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/FreePositionTracker.java index 5758c675d..53af3ddc0 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/FreePositionTracker.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/object/FreePositionTracker.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.object; @@ -12,24 +11,25 @@ import net.minecraft.world.phys.Vec3; public class FreePositionTracker implements PositionTracker { - private final Vec3 pos; - public FreePositionTracker(Vec3 pos) { - this.pos = pos; - } + private final Vec3 pos; - @Override - public Vec3 currentPosition() { - return pos; - } + public FreePositionTracker(Vec3 pos) { + this.pos = pos; + } - @Override - public BlockPos currentBlockPosition() { - return BlockPos.containing(pos); - } + @Override + public Vec3 currentPosition() { + return pos; + } - @Override - public boolean isVisibleBy(LivingEntity entity) { - return true; - } + @Override + public BlockPos currentBlockPosition() { + return BlockPos.containing(pos); + } + + @Override + public boolean isVisibleBy(LivingEntity entity) { + return true; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/SBLShufflingList.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/SBLShufflingList.java index 81b3aff73..c7a4a4808 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/SBLShufflingList.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/object/SBLShufflingList.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.object; @@ -20,100 +19,106 @@ import java.util.stream.Stream; public class SBLShufflingList implements Iterable { - private final List> entries; - private final RandomSource random = RandomSource.createNewThreadLocalInstance(); - - public SBLShufflingList() { - this.entries = new ObjectArrayList<>(); - } - - public SBLShufflingList(int size) { - this.entries = new ObjectArrayList<>(size); - } - - public SBLShufflingList(Pair... entries) { - this.entries = new ObjectArrayList<>(entries.length); - - for (Pair entry : entries) { - this.entries.add(new WeightedEntry<>(entry.getFirst(), entry.getSecond())); - } - } - - public SBLShufflingList shuffle() { - this.entries.forEach(entry -> entry.setShuffledWeight(this.random.nextFloat())); - this.entries.sort(Comparator.comparingDouble(WeightedEntry::getShuffledWeight)); - - return this; - } - - public boolean add(T entry, int weight) { - return this.entries.add(new WeightedEntry<>(entry, weight)); - } - - @Nullable - public T get(int index) { - return this.entries.get(index).get(); - } - - @NotNull - @Override - public Iterator iterator() { - return new ObjectIterators.AbstractIndexBasedIterator<>(0, 0) { - @Override - protected T get(int location) { - return SBLShufflingList.this.entries.get(location).get(); - } - - @Override - protected void remove(int location) { - SBLShufflingList.this.entries.remove(location); - } - - @Override - protected int getMaxPos() { - return SBLShufflingList.this.entries.size(); - } - }; - } - - @Override - public void forEach(Consumer action) { - this.entries.forEach(entry -> action.accept(entry.get())); - } - - public Stream stream() { - return this.entries.stream().map(WeightedEntry::get); - } - - public static class WeightedEntry { - private final T object; - private final int weight; - private double shuffledWeight; - - WeightedEntry(T object, int weight) { - this.object = object; - this.weight = weight; - } - - double getShuffledWeight() { - return this.shuffledWeight; - } - - T get() { - return this.object; - } - - int getWeight() { - return this.weight; - } - - void setShuffledWeight(float mod) { - this.shuffledWeight = -Math.pow(mod, 1f / this.weight); - } - - @Override - public String toString() { - return this.object + ":" + this.weight; - } - } + + private final List> entries; + + private final RandomSource random = RandomSource.createNewThreadLocalInstance(); + + public SBLShufflingList() { + this.entries = new ObjectArrayList<>(); + } + + public SBLShufflingList(int size) { + this.entries = new ObjectArrayList<>(size); + } + + public SBLShufflingList(Pair... entries) { + this.entries = new ObjectArrayList<>(entries.length); + + for (Pair entry : entries) { + this.entries.add(new WeightedEntry<>(entry.getFirst(), entry.getSecond())); + } + } + + public SBLShufflingList shuffle() { + this.entries.forEach(entry -> entry.setShuffledWeight(this.random.nextFloat())); + this.entries.sort(Comparator.comparingDouble(WeightedEntry::getShuffledWeight)); + + return this; + } + + public boolean add(T entry, int weight) { + return this.entries.add(new WeightedEntry<>(entry, weight)); + } + + @Nullable + public T get(int index) { + return this.entries.get(index).get(); + } + + @NotNull + @Override + public Iterator iterator() { + return new ObjectIterators.AbstractIndexBasedIterator<>(0, 0) { + + @Override + protected T get(int location) { + return SBLShufflingList.this.entries.get(location).get(); + } + + @Override + protected void remove(int location) { + SBLShufflingList.this.entries.remove(location); + } + + @Override + protected int getMaxPos() { + return SBLShufflingList.this.entries.size(); + } + }; + } + + @Override + public void forEach(Consumer action) { + this.entries.forEach(entry -> action.accept(entry.get())); + } + + public Stream stream() { + return this.entries.stream().map(WeightedEntry::get); + } + + public static class WeightedEntry { + + private final T object; + + private final int weight; + + private double shuffledWeight; + + WeightedEntry(T object, int weight) { + this.object = object; + this.weight = weight; + } + + double getShuffledWeight() { + return this.shuffledWeight; + } + + T get() { + return this.object; + } + + int getWeight() { + return this.weight; + } + + void setShuffledWeight(float mod) { + this.shuffledWeight = -Math.pow(mod, 1f / this.weight); + } + + @Override + public String toString() { + return this.object + ":" + this.weight; + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/SquareRadius.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/SquareRadius.java index 5d4775df5..0767b701b 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/SquareRadius.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/object/SquareRadius.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.object; @@ -14,23 +13,28 @@ /** * Helper class to store radius values without needlessly using 3 values.
    * Also comes with some handy helper methods. + * * @param xzRadius The lateral radius value (X/Z direction) - * @param yRadius The vertical radius value (Y direction) + * @param yRadius The vertical radius value (Y direction) */ -public record SquareRadius(double xzRadius, double yRadius) { - public Vec3i toVec3i() { - return new Vec3i((int)this.xzRadius, (int)this.yRadius, (int)this.xzRadius); - } +public record SquareRadius( + double xzRadius, + double yRadius +) { - public BlockPos toBlockPos() { - return BlockPos.containing(this.xzRadius, this.yRadius, this.xzRadius); - } + public Vec3i toVec3i() { + return new Vec3i((int) this.xzRadius, (int) this.yRadius, (int) this.xzRadius); + } - public Vec3 toVec3() { - return new Vec3(this.xzRadius, this.yRadius, this.xzRadius); - } + public BlockPos toBlockPos() { + return BlockPos.containing(this.xzRadius, this.yRadius, this.xzRadius); + } - public AABB inflateAABB(AABB bounds) { - return bounds.inflate(this.xzRadius, this.yRadius, this.xzRadius); - } -} \ No newline at end of file + public Vec3 toVec3() { + return new Vec3(this.xzRadius, this.yRadius, this.xzRadius); + } + + public AABB inflateAABB(AABB bounds) { + return bounds.inflate(this.xzRadius, this.yRadius, this.xzRadius); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/TriPredicate.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/TriPredicate.java index f68b3964d..1bd8753b3 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/TriPredicate.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/object/TriPredicate.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.object; @@ -13,21 +12,22 @@ */ @FunctionalInterface public interface TriPredicate { - boolean test(A a, B b, C c); - default TriPredicate and(TriPredicate other) { - Objects.requireNonNull(other); + boolean test(A a, B b, C c); - return (A a, B b, C c) -> test(a, b, c) && other.test(a, b, c); - } + default TriPredicate and(TriPredicate other) { + Objects.requireNonNull(other); - default TriPredicate negate() { - return (A a, B b, C c) -> !test(a, b, c); - } + return (A a, B b, C c) -> test(a, b, c) && other.test(a, b, c); + } - default TriPredicate or(TriPredicate other) { - Objects.requireNonNull(other); + default TriPredicate negate() { + return (A a, B b, C c) -> !test(a, b, c); + } - return (A a, B b, C c) -> test(a, b, c) || other.test(a, b, c); - } -} \ No newline at end of file + default TriPredicate or(TriPredicate other) { + Objects.requireNonNull(other); + + return (A a, B b, C c) -> test(a, b, c) || other.test(a, b, c); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLMemoryTypes.java b/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLMemoryTypes.java index 646486a59..df5d1b2d1 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLMemoryTypes.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLMemoryTypes.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.registry; @@ -13,29 +12,41 @@ import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.level.block.state.BlockState; -import mod.azure.azurelib.sblforked.SBLConstants; import java.util.List; import java.util.Optional; import java.util.function.Supplier; +import mod.azure.azurelib.sblforked.SBLConstants; + /** * Registry class for custom {@link MemoryModuleType Memory Types} */ public final class SBLMemoryTypes { - public static void init() {} - public static final Supplier>> INCOMING_PROJECTILES = register("incoming_projectiles"); - public static final Supplier> TARGET_UNREACHABLE = register("target_unreachable"); - public static final Supplier> SPECIAL_ATTACK_COOLDOWN = register("special_attack_cooldown"); - public static final Supplier>>> NEARBY_BLOCKS = register("nearby_blocks"); - public static final Supplier>> NEARBY_ITEMS = register("nearby_items"); + public static void init() {} + + public static final Supplier>> INCOMING_PROJECTILES = register( + "incoming_projectiles" + ); + + public static final Supplier> TARGET_UNREACHABLE = register("target_unreachable"); + + public static final Supplier> SPECIAL_ATTACK_COOLDOWN = register( + "special_attack_cooldown" + ); + + public static final Supplier>>> NEARBY_BLOCKS = register( + "nearby_blocks" + ); + + public static final Supplier>> NEARBY_ITEMS = register("nearby_items"); - private static Supplier> register(String id) { - return register(id, Optional.empty()); - } + private static Supplier> register(String id) { + return register(id, Optional.empty()); + } - private static Supplier> register(String id, Optional> codec) { - return SBLConstants.SBL_LOADER.registerMemoryType(id, codec); - } + private static Supplier> register(String id, Optional> codec) { + return SBLConstants.SBL_LOADER.registerMemoryType(id, codec); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLSensors.java b/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLSensors.java index 25540bae6..afb456fb6 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLSensors.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLSensors.java @@ -1,55 +1,139 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.registry; import net.minecraft.world.entity.ai.sensing.SensorType; + +import java.util.function.Supplier; + import mod.azure.azurelib.sblforked.SBLConstants; import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; import mod.azure.azurelib.sblforked.api.core.sensor.custom.*; import mod.azure.azurelib.sblforked.api.core.sensor.vanilla.*; -import java.util.function.Supplier; - /** * Registry class for {@link ExtendedSensor} implementations */ public final class SBLSensors { - public static void init() {} - - // Vanilla sensors - public static final Supplier>> NEAREST_ITEM = register("nearest_item", NearestItemSensor::new); - public static final Supplier>> NEARBY_LIVING_ENTITY = register("nearby_living_entity", NearbyLivingEntitySensor::new); - public static final Supplier>> NEARBY_PLAYERS = register("nearby_players", NearbyPlayersSensor::new); - public static final Supplier>> NEAREST_HOME = register("nearest_home", NearestHomeSensor::new); - public static final Supplier>> HURT_BY = register("hurt_by", HurtBySensor::new); - public static final Supplier>> NEARBY_HOSTILE = register("nearby_hostile", NearbyHostileSensor::new); - public static final Supplier>> NEARBY_BABY = register("nearby_baby", NearbyBabySensor::new); - public static final Supplier>> SECONDARY_POI = register("secondary_poi", SecondaryPoiSensor::new); - public static final Supplier>> NEARBY_GOLEM = register("nearby_golem", NearbyGolemSensor::new); - public static final Supplier>> NEARBY_ADULT = register("nearby_adult", NearbyAdultSensor::new); - public static final Supplier>> ITEM_TEMPTING = register("item_tempting", ItemTemptingSensor::new); - public static final Supplier>> IN_WATER = register("in_water", InWaterSensor::new); - - // Entity Specific - public static final Supplier>> FROG_SPECIFIC = register("frog_specific", FrogSpecificSensor::new); - public static final Supplier>> AXOLOTL_SPECIFIC = register("axolotl_specific", AxolotlSpecificSensor::new); - public static final Supplier>> PIGLIN_SPECIFIC = register("piglin_specific", PiglinSpecificSensor::new); - public static final Supplier>> PIGLIN_BRUTE_SPECIFIC = register("piglin_brute_specific", PiglinBruteSpecificSensor::new); - public static final Supplier>> HOGLIN_SPECIFIC = register("hoglin_specific", HoglinSpecificSensor::new); - public static final Supplier>> WARDEN_SPECIFIC = register("warden_specific", WardenSpecificSensor::new); - - // Custom - public static final Supplier>> INCOMING_PROJECTILES = register("incoming_projectiles", IncomingProjectilesSensor::new); - public static final Supplier>> GENERIC_ATTACK_TARGET = register("generic_attack_target", GenericAttackTargetSensor::new); - public static final Supplier>> UNREACHABLE_TARGET = register("unreachable_target", UnreachableTargetSensor::new); - public static final Supplier>> NEARBY_BLOCKS = register("nearby_blocks", NearbyBlocksSensor::new); - public static final Supplier>> NEARBY_ITEMS = register("nearby_items", NearbyItemsSensor::new); - - private static > Supplier> register(String id, Supplier sensor) { - return SBLConstants.SBL_LOADER.registerSensorType(id, sensor); - } + + public static void init() {} + + // Vanilla sensors + public static final Supplier>> NEAREST_ITEM = register( + "nearest_item", + NearestItemSensor::new + ); + + public static final Supplier>> NEARBY_LIVING_ENTITY = register( + "nearby_living_entity", + NearbyLivingEntitySensor::new + ); + + public static final Supplier>> NEARBY_PLAYERS = register( + "nearby_players", + NearbyPlayersSensor::new + ); + + public static final Supplier>> NEAREST_HOME = register( + "nearest_home", + NearestHomeSensor::new + ); + + public static final Supplier>> HURT_BY = register("hurt_by", HurtBySensor::new); + + public static final Supplier>> NEARBY_HOSTILE = register( + "nearby_hostile", + NearbyHostileSensor::new + ); + + public static final Supplier>> NEARBY_BABY = register( + "nearby_baby", + NearbyBabySensor::new + ); + + public static final Supplier>> SECONDARY_POI = register( + "secondary_poi", + SecondaryPoiSensor::new + ); + + public static final Supplier>> NEARBY_GOLEM = register( + "nearby_golem", + NearbyGolemSensor::new + ); + + public static final Supplier>> NEARBY_ADULT = register( + "nearby_adult", + NearbyAdultSensor::new + ); + + public static final Supplier>> ITEM_TEMPTING = register( + "item_tempting", + ItemTemptingSensor::new + ); + + public static final Supplier>> IN_WATER = register("in_water", InWaterSensor::new); + + // Entity Specific + public static final Supplier>> FROG_SPECIFIC = register( + "frog_specific", + FrogSpecificSensor::new + ); + + public static final Supplier>> AXOLOTL_SPECIFIC = register( + "axolotl_specific", + AxolotlSpecificSensor::new + ); + + public static final Supplier>> PIGLIN_SPECIFIC = register( + "piglin_specific", + PiglinSpecificSensor::new + ); + + public static final Supplier>> PIGLIN_BRUTE_SPECIFIC = register( + "piglin_brute_specific", + PiglinBruteSpecificSensor::new + ); + + public static final Supplier>> HOGLIN_SPECIFIC = register( + "hoglin_specific", + HoglinSpecificSensor::new + ); + + public static final Supplier>> WARDEN_SPECIFIC = register( + "warden_specific", + WardenSpecificSensor::new + ); + + // Custom + public static final Supplier>> INCOMING_PROJECTILES = register( + "incoming_projectiles", + IncomingProjectilesSensor::new + ); + + public static final Supplier>> GENERIC_ATTACK_TARGET = register( + "generic_attack_target", + GenericAttackTargetSensor::new + ); + + public static final Supplier>> UNREACHABLE_TARGET = register( + "unreachable_target", + UnreachableTargetSensor::new + ); + + public static final Supplier>> NEARBY_BLOCKS = register( + "nearby_blocks", + NearbyBlocksSensor::new + ); + + public static final Supplier>> NEARBY_ITEMS = register( + "nearby_items", + NearbyItemsSensor::new + ); + + private static > Supplier> register(String id, Supplier sensor) { + return SBLConstants.SBL_LOADER.registerSensorType(id, sensor); + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/BrainUtils.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/BrainUtils.java index 268ab1ed9..7037b3276 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/BrainUtils.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/util/BrainUtils.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.util; @@ -24,6 +23,13 @@ import net.minecraft.world.entity.schedule.Activity; import net.minecraft.world.entity.schedule.Schedule; import net.minecraft.world.entity.schedule.Timeline; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Stream; + import mod.azure.azurelib.sblforked.api.core.BrainActivityGroup; import mod.azure.azurelib.sblforked.api.core.SmartBrain; import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; @@ -32,527 +38,613 @@ import mod.azure.azurelib.sblforked.object.BrainBehaviourConsumer; import mod.azure.azurelib.sblforked.object.BrainBehaviourPredicate; import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.stream.Stream; /** * Utility class for various brain functions. Try to utilise this where possible to ensure consistency and safety. */ public final class BrainUtils { - /** - * Get a memory value from an entity, with a fallback value if no memory is present - * - * @param entity The entity - * @param memory Memory type to get the value for - * @param fallback Fallback value if no memory value is present - * @return The stored memory, or fallback value if no memory was stored - * @param The type of object the memory uses - */ - public static T memoryOrDefault(LivingEntity entity, MemoryModuleType memory, Supplier fallback) { - return memoryOrDefault(entity.getBrain(), memory, fallback); - } - - /** - * Get a memory value from a brain, with a fallback value if no memory is present - * - * @param brain The brain - * @param memory Memory type to get the value for - * @param fallback Fallback value if no memory value is present - * @return The stored memory, or fallback value if no memory was stored - * @param The type of object the memory uses - */ - public static T memoryOrDefault(Brain brain, MemoryModuleType memory, Supplier fallback) { - return brain.getMemory(memory).orElseGet(fallback); - } - - /** - * Get a memory value from an entity, or null if no memory is present - * - * @param entity The entity - * @param memory Memory type to get the value for - * @return The stored memory, or null if no memory was stored - * @param The type of object the memory uses - */ - @Nullable - public static T getMemory(LivingEntity entity, MemoryModuleType memory) { - return getMemory(entity.getBrain(), memory); - } - - /** - * Get a memory value from a brain, or null if no memory is present - * - * @param brain The brain - * @param memory Memory type to get the value for - * @return The stored memory, or null if no memory was stored - * @param The type of object the memory uses - */ - @Nullable - public static T getMemory(Brain brain, MemoryModuleType memory) { - return memoryOrDefault(brain, memory, () -> null); - } - - /** - * Perform an operation on a given memory value, if present. If no memory value set, operation is not run - * - * @param entity The entity - * @param memory Memory type to get the value for - * @param consumer The operation to run if the memory is present - * @param The type of object the memory uses - */ - public static void withMemory(LivingEntity entity, MemoryModuleType memory, Consumer consumer) { - withMemory(entity.getBrain(), memory, consumer); - } - - /** - * Perform an operation on a given memory value, if present. If no memory value set, operation is not run - * - * @param brain The brain - * @param memory Memory type to get the value for - * @param consumer The operation to run if the memory is present - * @param The type of object the memory uses - */ - public static void withMemory(Brain brain, MemoryModuleType memory, Consumer consumer) { - brain.getMemory(memory).ifPresent(consumer); - } - - /** - * Check whether an entity has a memory value set. - * - * @param entity The entity - * @param memory Memory type to get the value for - * @return True if the memory value is present, or false if the memory value is absent or unregistered - */ - public static boolean hasMemory(LivingEntity entity, MemoryModuleType memory) { - return hasMemory(entity.getBrain(), memory); - } - /** - * Check whether a brain has a memory value set. - * - * @param brain The brain - * @param memory Memory type to get the value for - * @return True if the memory value is present, or false if the memory value is absent or unregistered - */ - public static boolean hasMemory(Brain brain, MemoryModuleType memory) { - return brain.hasMemoryValue(memory); - } - - /** - * Gets the ticks remaining until a memory expires. - * @param entity The entity - * @param memory Memory type to get the expiry time for - * @return The ticks until the memory expires, or 0 if the memory doesn't exist or doesn't expire - */ - public static long getTimeUntilMemoryExpires(LivingEntity entity, MemoryModuleType memory) { - return getTimeUntilMemoryExpires(entity.getBrain(), memory); - } - - /** - * Gets the ticks remaining until a memory expires. - * @param brain The brain - * @param memory Memory type to get the expiry time for - * @return The ticks until the memory expires, or 0 if the memory doesn't exist or doesn't expire - */ - public static long getTimeUntilMemoryExpires(Brain brain, MemoryModuleType memory) { - return brain.getTimeUntilExpiry(memory); - } - - /** - * Set an entity's memory value for the given memory type.
    - * Use {@link BrainUtils#clearMemory(LivingEntity, MemoryModuleType)} if intending to set a memory to nothing. - * - * @param entity The entity - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param The type of object the memory uses - */ - public static void setMemory(LivingEntity entity, MemoryModuleType memoryType, T memory) { - setMemory(entity.getBrain(), memoryType, memory); - } - - /** - * Set a brain's memory value for the given memory type.
    - * Use {@link BrainUtils#clearMemory(Brain, MemoryModuleType)} if intending to set a memory to nothing. - * - * @param brain The brain - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param The type of object the memory uses - */ - public static void setMemory(Brain brain, MemoryModuleType memoryType, T memory) { - brain.setMemory(memoryType, memory); - } - - /** - * Set a brain's memory value for the given memory type, with the memory expiring after a certain time.
    - * Use {@link BrainUtils#clearMemory(LivingEntity, MemoryModuleType)} if intending to set a memory to nothing. - * @param entity The entity - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param expirationTicks How many ticks until the memory expires - * @param The type of object the memory uses - */ - public static void setForgettableMemory(LivingEntity entity, MemoryModuleType memoryType, T memory, int expirationTicks) { - setForgettableMemory(entity.getBrain(), memoryType, memory, expirationTicks); - } - - /** - * Set an entity's memory value for the given memory type, with the memory expiring after a certain time.
    - * Use {@link BrainUtils#clearMemory(Brain, MemoryModuleType)} if intending to set a memory to nothing. - * @param brain The brain - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param expirationTicks How many ticks until the memory expires - * @param The type of object the memory uses - */ - public static void setForgettableMemory(Brain brain, MemoryModuleType memoryType, T memory, int expirationTicks) { - brain.setMemoryWithExpiry(memoryType, memory, expirationTicks); - } - - /** - * Wipe an entity's memory value for the given memory type. This safely unsets a memory, returning it to empty. - * - * @param entity The entity - * @param memory Memory type to erase the value for - */ - public static void clearMemory(LivingEntity entity, MemoryModuleType memory) { - clearMemory(entity.getBrain(), memory); - } - - /** - * Wipe a brain's memory value for the given memory type. This safely unsets a memory, returning it to empty. - * - * @param brain The brain - * @param memory Memory type to erase the value for - */ - public static void clearMemory(Brain brain, MemoryModuleType memory) { - brain.eraseMemory(memory); - } - - /** - * Wipe multiple memories for a given entity. This safely unsets each memory, returning them to empty. - * - * @param entity The entity - * @param memories The list of memory types to erase the values for - */ - public static void clearMemories(LivingEntity entity, MemoryModuleType... memories) { - clearMemories(entity.getBrain(), memories); - } - - /** - * Wipe multiple memories for a given brain. This safely unsets each memory, returning them to empty. - * - * @param brain The brain - * @param memories The list of memory types to erase the values for - */ - public static void clearMemories(Brain brain, MemoryModuleType... memories) { - for (MemoryModuleType memory : memories) { - brain.eraseMemory(memory); - } - } - - /** - * Gets the current attack target of an entity, if present. - * - * @param entity The entity - * @return The current attack target of the entity, or null if none present - */ - @Nullable - public static LivingEntity getTargetOfEntity(LivingEntity entity) { - return getTargetOfEntity(entity, null); - } - - /** - * Gets the current attack target of an entity, if present, or an optional fallback entity if none present - * - * @param entity The entity - * @param fallback Optional fallback entity to return if no attack target is set. - * @return The current attack target of the entity, the fallback entity if provided, or null otherwise - */ - @Nullable - public static LivingEntity getTargetOfEntity(LivingEntity entity, @Nullable LivingEntity fallback) { - return memoryOrDefault(entity.getBrain(), MemoryModuleType.ATTACK_TARGET, () -> fallback); - } - - /** - * Gets the last entity to attack the given entity, if present.
    - * Requires that the entity uses the {@link MemoryModuleType#HURT_BY_ENTITY} memory type, and a sensor that sets it - * - * @param entity The entity - * @return The last entity to attack the given entity, or null if none present - */ - @Nullable - public static LivingEntity getLastAttacker(LivingEntity entity) { - return memoryOrDefault(entity, MemoryModuleType.HURT_BY_ENTITY, () -> null); - } - - /** - * Sets the attack target of the given entity, and safely sets the non-brain attack target for compatibility purposes.
    - * Provided target can be null to effectively remove an entity's attack target. - * - * @param entity The entity - * @param target The entity to target - */ - public static void setTargetOfEntity(LivingEntity entity, @Nullable LivingEntity target) { - if (entity instanceof Mob mob) - mob.setTarget(target); - - if (target == null) { - clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } - else { - setMemory(entity, MemoryModuleType.ATTACK_TARGET, target); - } - } - - /** - * Replacement of {@link net.minecraft.world.entity.ai.behavior.BehaviorUtils#canSee}, falling back to a raytrace check in the event the target entity isn't in the {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory - * @param entity The entity to check the brain of - * @param target The target entity - * @return Whether the target entity is known to be visible or not - */ - public static boolean canSee(LivingEntity entity, LivingEntity target) { - Brain brain = entity.getBrain(); - - if (BehaviorUtils.entityIsVisible(brain, target)) - return true; - - return entity.hasLineOfSight(target); - } - - /** - * Sets a {@link SBLMemoryTypes#SPECIAL_ATTACK_COOLDOWN} value for a certain length of time.
    - * This can then be checked via {@link BrainUtils#isOnSpecialCooldown(LivingEntity)} as needed. - * @param entity The entity to check the brain of - * @param ticks The length of time (in ticks) the cooldown should apply for - */ - public static void setSpecialCooldown(LivingEntity entity, int ticks) { - setForgettableMemory(entity, SBLMemoryTypes.SPECIAL_ATTACK_COOLDOWN.get(), true, ticks); - } - - /** - * Checks whether the entity has had a {@link SBLMemoryTypes#SPECIAL_ATTACK_COOLDOWN} set, and it hasn't expired.
    - * This can be used for cross-behaviour cooldowns and interactions - * @param entity The entity to check the brain of - * @return Whether the entity has a cooldown currently active - */ - public static boolean isOnSpecialCooldown(LivingEntity entity) { - return hasMemory(entity, SBLMemoryTypes.SPECIAL_ATTACK_COOLDOWN.get()); - } - - /** - * Returns a stream of all {@link BehaviorControl Behaviours} registered to this brain - */ - public static Stream> getAllBehaviours(Brain brain) { - if (brain instanceof SmartBrain smartBrain) - return smartBrain.getBehaviours(); - - return brain.availableBehaviorsByPriority.values().stream() - .map(Map::values) - .flatMap(set -> set.stream().map(value -> value.stream().toList()).flatMap(List::stream)); - } - - /** - * Loops over all {@link BehaviorControl Behaviours} registered to this brain, calling the consumer for each - * @param brain The brain to scrape the behaviours of - * @param consumer The consumer called for each - */ - public static void forEachBehaviour(Brain brain, BrainBehaviourConsumer consumer) { - if (brain instanceof SmartBrain smartBrain) { - smartBrain.forEachBehaviour(consumer); - - return; - } - - Set>>>> behaviours = (Set)brain.availableBehaviorsByPriority.entrySet(); - - for (Map.Entry>>> priorityEntry : behaviours) { - Integer priority = priorityEntry.getKey(); - - for (Map.Entry>> activityEntry : priorityEntry.getValue().entrySet()) { - Activity activity = activityEntry.getKey(); - - for (BehaviorControl behaviour : activityEntry.getValue()) { - consumeBehaviour(priority, activity, behaviour, null, consumer); - } - } - } - } - - private static void consumeBehaviour(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parentBehaviour, BrainBehaviourConsumer consumer) { - consumer.consume(priority, activity, behaviour, parentBehaviour); - - if (behaviour instanceof GateBehavior groupBehaviour) { - groupBehaviour.behaviors.stream().forEach(childBehaviour -> consumeBehaviour(priority, activity, (BehaviorControl)childBehaviour, groupBehaviour, consumer)); - } - else if (behaviour instanceof GroupBehaviour groupBehaviour) { - groupBehaviour.getBehaviours().forEachRemaining(childBehaviour -> consumeBehaviour(priority, activity, (BehaviorControl)childBehaviour, groupBehaviour, consumer)); - } - } - - /** - * Removes any behaviours matching the given predicate from the provided brain.
    - * Removed behaviours are stopped prior to removal - * @param entity The owner of the brain - * @param predicate The predicate checked for each - */ - public static void removeBehaviour(E entity, BrainBehaviourPredicate predicate) { - if (entity.getBrain() instanceof SmartBrain smartBrain) { - smartBrain.removeBehaviour(entity, predicate); - - return; - } - - Set>>>> behaviours = (Set)entity.getBrain().availableBehaviorsByPriority.entrySet(); - - for (Map.Entry>>> priorityEntry : behaviours) { - Integer priority = priorityEntry.getKey(); - - for (Map.Entry>> activityEntry : priorityEntry.getValue().entrySet()) { - Activity activity = activityEntry.getKey(); - - for (Iterator> iterator = activityEntry.getValue().iterator(); iterator.hasNext();) { - BehaviorControl behaviour = iterator.next(); - - checkBehaviour(priority, activity, behaviour, null, predicate, () -> { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.doStop((ServerLevel)entity.level(), entity, entity.level().getGameTime()); - - iterator.remove(); - }); - } - } - } - } - - private static void checkBehaviour(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parentBehaviour, BrainBehaviourPredicate predicate, Runnable callback) { - if (predicate.isBehaviour(priority, activity, behaviour, parentBehaviour)) { - callback.run(); - } - else if (behaviour instanceof GateBehavior groupBehaviour) { - for (Iterator> childBehaviourIterator = groupBehaviour.behaviors.iterator(); childBehaviourIterator.hasNext();) { - checkBehaviour(priority, activity, childBehaviourIterator.next(), groupBehaviour, predicate, childBehaviourIterator::remove); - } - - if (!groupBehaviour.behaviors.iterator().hasNext()) - callback.run(); - } - else if (behaviour instanceof GroupBehaviour groupBehaviour) { - for (Iterator> childBehaviourIterator = groupBehaviour.getBehaviours(); childBehaviourIterator.hasNext();) { - checkBehaviour(priority, activity, childBehaviourIterator.next(), groupBehaviour, predicate, childBehaviourIterator::remove); - } - - if (!groupBehaviour.getBehaviours().hasNext()) - callback.run(); - } - } - - /** - * Safely a new {@link BehaviorControl Behaviour} to the given {@link Brain} - * @param brain The brain to add the behaviour to - * @param priority The priority index the behaviour belongs to (lower runs earlier) - * @param activity The activity category the behaviour belongs to - * @param behaviourControl The behaviour to add - */ - public static void addBehaviour(Brain brain, int priority, Activity activity, BehaviorControl behaviourControl) { - if (brain instanceof SmartBrain smartBrain) { - smartBrain.addBehaviour(priority, activity, behaviourControl); - - return; - } - - brain.availableBehaviorsByPriority.computeIfAbsent(priority, priority2 -> Maps.newHashMap()).computeIfAbsent(activity, activity2 -> Sets.newLinkedHashSet()).add(behaviourControl); - - if (behaviourControl instanceof Behavior behavior) { - for (MemoryModuleType memoryType : behavior.entryCondition.keySet()) { - brain.memories.putIfAbsent(memoryType, Optional.empty()); - } - } - } - - /** - * Adds a full {@link BrainActivityGroup} to the brain, inclusive of activities and conditions - */ - public static void addActivity(Brain brain, BrainActivityGroup behaviourGroup) { - if (brain instanceof SmartBrain smartBrain) { - smartBrain.addActivity(behaviourGroup); - - return; - } - - brain.addActivityAndRemoveMemoriesWhenStopped(behaviourGroup.getActivity(), (ImmutableList)behaviourGroup.pairBehaviourPriorities(), behaviourGroup.getActivityStartMemoryConditions(), behaviourGroup.getWipedMemoriesOnFinish()); - } - - /** - * Adds a sensor to the given brain, additionally allowing for custom instantiation.
    - * Automatically adds detected memories to the brain, but because of the nature of the vanilla brain system, - * you may need to {@link BrainUtils#addMemories add additional memories manually} if Mojang didn't set something up properly - */ - public static > void addSensor(Brain brain, SensorType sensorType, S sensor) { - if (brain instanceof SmartBrain smartBrain) { - if (!(sensor instanceof ExtendedSensor extendedSensor)) - throw new IllegalArgumentException("Attempted to provide sensor to SmartBrain, only ExtendedSensor subclasses acceptable. Sensor: " + sensor.getClass()); - - smartBrain.addSensor(extendedSensor); - - return; - } - - brain.sensors.put((SensorType)sensorType, (Sensor)sensor); - addMemories(brain, sensor.requires().toArray(new MemoryModuleType[0])); - } - - /** - * Adds the given {@link MemoryModuleType} to the provided brain.
    - * Generally only required if modifying vanilla brains and additional memories are needed. - */ - public static void addMemories(Brain brain, MemoryModuleType... memories) { - if (brain instanceof SmartBrain smartBrain) { - for (MemoryModuleType memoryType : memories) { - smartBrain.getMemory(memoryType); - } - - return; - } - - for (MemoryModuleType memoryType : memories) { - brain.memories.computeIfAbsent(memoryType, key -> Optional.empty()).map(ExpirableValue::getValue); - } - } - - /** - * Adds the given scheduled activity transition to the provided brain's {@link net.minecraft.world.entity.schedule.Schedule schedule}, creating a new schedule if required. - * @param brain The brain the schedule belongs to - * @param activity The activity to transition to - * @param tickTime The tick-time the activity transition should happen - * @param tickType The type of tick tracking the schedule should use, if a new schedule has to be created. - */ - public static void addScheduledActivityTransition(Brain brain, Activity activity, int tickTime, SmartBrainSchedule.Type tickType) { - if (brain instanceof SmartBrain smartBrain) { - SmartBrainSchedule schedule; - - if ((schedule = smartBrain.getSchedule()) == null) - smartBrain.setSchedule((schedule = new SmartBrainSchedule(tickType))); - - schedule.activityAt(tickTime, activity); - } - else { - Schedule schedule; - - if ((schedule = brain.getSchedule()) == Schedule.EMPTY) - brain.setSchedule(new Schedule()); - - Timeline timeline = schedule.timelines.computeIfAbsent(activity, key -> new Timeline()); - - timeline.addKeyframe(tickTime, 1); - - for (Map.Entry entry : schedule.timelines.entrySet()) { - if (entry.getKey() != activity) - entry.getValue().addKeyframe(tickTime, 0); - } - } - } + + /** + * Get a memory value from an entity, with a fallback value if no memory is present + * + * @param entity The entity + * @param memory Memory type to get the value for + * @param fallback Fallback value if no memory value is present + * @return The stored memory, or fallback value if no memory was stored + * @param The type of object the memory uses + */ + public static T memoryOrDefault(LivingEntity entity, MemoryModuleType memory, Supplier fallback) { + return memoryOrDefault(entity.getBrain(), memory, fallback); + } + + /** + * Get a memory value from a brain, with a fallback value if no memory is present + * + * @param brain The brain + * @param memory Memory type to get the value for + * @param fallback Fallback value if no memory value is present + * @return The stored memory, or fallback value if no memory was stored + * @param The type of object the memory uses + */ + public static T memoryOrDefault(Brain brain, MemoryModuleType memory, Supplier fallback) { + return brain.getMemory(memory).orElseGet(fallback); + } + + /** + * Get a memory value from an entity, or null if no memory is present + * + * @param entity The entity + * @param memory Memory type to get the value for + * @return The stored memory, or null if no memory was stored + * @param The type of object the memory uses + */ + @Nullable + public static T getMemory(LivingEntity entity, MemoryModuleType memory) { + return getMemory(entity.getBrain(), memory); + } + + /** + * Get a memory value from a brain, or null if no memory is present + * + * @param brain The brain + * @param memory Memory type to get the value for + * @return The stored memory, or null if no memory was stored + * @param The type of object the memory uses + */ + @Nullable + public static T getMemory(Brain brain, MemoryModuleType memory) { + return memoryOrDefault(brain, memory, () -> null); + } + + /** + * Perform an operation on a given memory value, if present. If no memory value set, operation is not run + * + * @param entity The entity + * @param memory Memory type to get the value for + * @param consumer The operation to run if the memory is present + * @param The type of object the memory uses + */ + public static void withMemory(LivingEntity entity, MemoryModuleType memory, Consumer consumer) { + withMemory(entity.getBrain(), memory, consumer); + } + + /** + * Perform an operation on a given memory value, if present. If no memory value set, operation is not run + * + * @param brain The brain + * @param memory Memory type to get the value for + * @param consumer The operation to run if the memory is present + * @param The type of object the memory uses + */ + public static void withMemory(Brain brain, MemoryModuleType memory, Consumer consumer) { + brain.getMemory(memory).ifPresent(consumer); + } + + /** + * Check whether an entity has a memory value set. + * + * @param entity The entity + * @param memory Memory type to get the value for + * @return True if the memory value is present, or false if the memory value is absent or unregistered + */ + public static boolean hasMemory(LivingEntity entity, MemoryModuleType memory) { + return hasMemory(entity.getBrain(), memory); + } + + /** + * Check whether a brain has a memory value set. + * + * @param brain The brain + * @param memory Memory type to get the value for + * @return True if the memory value is present, or false if the memory value is absent or unregistered + */ + public static boolean hasMemory(Brain brain, MemoryModuleType memory) { + return brain.hasMemoryValue(memory); + } + + /** + * Gets the ticks remaining until a memory expires. + * + * @param entity The entity + * @param memory Memory type to get the expiry time for + * @return The ticks until the memory expires, or 0 if the memory doesn't exist or doesn't expire + */ + public static long getTimeUntilMemoryExpires(LivingEntity entity, MemoryModuleType memory) { + return getTimeUntilMemoryExpires(entity.getBrain(), memory); + } + + /** + * Gets the ticks remaining until a memory expires. + * + * @param brain The brain + * @param memory Memory type to get the expiry time for + * @return The ticks until the memory expires, or 0 if the memory doesn't exist or doesn't expire + */ + public static long getTimeUntilMemoryExpires(Brain brain, MemoryModuleType memory) { + return brain.getTimeUntilExpiry(memory); + } + + /** + * Set an entity's memory value for the given memory type.
    + * Use {@link BrainUtils#clearMemory(LivingEntity, MemoryModuleType)} if intending to set a memory to nothing. + * + * @param entity The entity + * @param memoryType Memory type to set the value for + * @param memory The memory value to set + * @param The type of object the memory uses + */ + public static void setMemory(LivingEntity entity, MemoryModuleType memoryType, T memory) { + setMemory(entity.getBrain(), memoryType, memory); + } + + /** + * Set a brain's memory value for the given memory type.
    + * Use {@link BrainUtils#clearMemory(Brain, MemoryModuleType)} if intending to set a memory to nothing. + * + * @param brain The brain + * @param memoryType Memory type to set the value for + * @param memory The memory value to set + * @param The type of object the memory uses + */ + public static void setMemory(Brain brain, MemoryModuleType memoryType, T memory) { + brain.setMemory(memoryType, memory); + } + + /** + * Set a brain's memory value for the given memory type, with the memory expiring after a certain time.
    + * Use {@link BrainUtils#clearMemory(LivingEntity, MemoryModuleType)} if intending to set a memory to nothing. + * + * @param entity The entity + * @param memoryType Memory type to set the value for + * @param memory The memory value to set + * @param expirationTicks How many ticks until the memory expires + * @param The type of object the memory uses + */ + public static void setForgettableMemory( + LivingEntity entity, + MemoryModuleType memoryType, + T memory, + int expirationTicks + ) { + setForgettableMemory(entity.getBrain(), memoryType, memory, expirationTicks); + } + + /** + * Set an entity's memory value for the given memory type, with the memory expiring after a certain time.
    + * Use {@link BrainUtils#clearMemory(Brain, MemoryModuleType)} if intending to set a memory to nothing. + * + * @param brain The brain + * @param memoryType Memory type to set the value for + * @param memory The memory value to set + * @param expirationTicks How many ticks until the memory expires + * @param The type of object the memory uses + */ + public static void setForgettableMemory( + Brain brain, + MemoryModuleType memoryType, + T memory, + int expirationTicks + ) { + brain.setMemoryWithExpiry(memoryType, memory, expirationTicks); + } + + /** + * Wipe an entity's memory value for the given memory type. This safely unsets a memory, returning it to empty. + * + * @param entity The entity + * @param memory Memory type to erase the value for + */ + public static void clearMemory(LivingEntity entity, MemoryModuleType memory) { + clearMemory(entity.getBrain(), memory); + } + + /** + * Wipe a brain's memory value for the given memory type. This safely unsets a memory, returning it to empty. + * + * @param brain The brain + * @param memory Memory type to erase the value for + */ + public static void clearMemory(Brain brain, MemoryModuleType memory) { + brain.eraseMemory(memory); + } + + /** + * Wipe multiple memories for a given entity. This safely unsets each memory, returning them to empty. + * + * @param entity The entity + * @param memories The list of memory types to erase the values for + */ + public static void clearMemories(LivingEntity entity, MemoryModuleType... memories) { + clearMemories(entity.getBrain(), memories); + } + + /** + * Wipe multiple memories for a given brain. This safely unsets each memory, returning them to empty. + * + * @param brain The brain + * @param memories The list of memory types to erase the values for + */ + public static void clearMemories(Brain brain, MemoryModuleType... memories) { + for (MemoryModuleType memory : memories) { + brain.eraseMemory(memory); + } + } + + /** + * Gets the current attack target of an entity, if present. + * + * @param entity The entity + * @return The current attack target of the entity, or null if none present + */ + @Nullable + public static LivingEntity getTargetOfEntity(LivingEntity entity) { + return getTargetOfEntity(entity, null); + } + + /** + * Gets the current attack target of an entity, if present, or an optional fallback entity if none present + * + * @param entity The entity + * @param fallback Optional fallback entity to return if no attack target is set. + * @return The current attack target of the entity, the fallback entity if provided, or null otherwise + */ + @Nullable + public static LivingEntity getTargetOfEntity(LivingEntity entity, @Nullable LivingEntity fallback) { + return memoryOrDefault(entity.getBrain(), MemoryModuleType.ATTACK_TARGET, () -> fallback); + } + + /** + * Gets the last entity to attack the given entity, if present.
    + * Requires that the entity uses the {@link MemoryModuleType#HURT_BY_ENTITY} memory type, and a sensor that sets it + * + * @param entity The entity + * @return The last entity to attack the given entity, or null if none present + */ + @Nullable + public static LivingEntity getLastAttacker(LivingEntity entity) { + return memoryOrDefault(entity, MemoryModuleType.HURT_BY_ENTITY, () -> null); + } + + /** + * Sets the attack target of the given entity, and safely sets the non-brain attack target for compatibility + * purposes.
    + * Provided target can be null to effectively remove an entity's attack target. + * + * @param entity The entity + * @param target The entity to target + */ + public static void setTargetOfEntity(LivingEntity entity, @Nullable LivingEntity target) { + if (entity instanceof Mob mob) + mob.setTarget(target); + + if (target == null) { + clearMemory(entity, MemoryModuleType.ATTACK_TARGET); + } else { + setMemory(entity, MemoryModuleType.ATTACK_TARGET, target); + } + } + + /** + * Replacement of {@link net.minecraft.world.entity.ai.behavior.BehaviorUtils#canSee}, falling back to a raytrace + * check in the event the target entity isn't in the {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory + * + * @param entity The entity to check the brain of + * @param target The target entity + * @return Whether the target entity is known to be visible or not + */ + public static boolean canSee(LivingEntity entity, LivingEntity target) { + Brain brain = entity.getBrain(); + + if (BehaviorUtils.entityIsVisible(brain, target)) + return true; + + return entity.hasLineOfSight(target); + } + + /** + * Sets a {@link SBLMemoryTypes#SPECIAL_ATTACK_COOLDOWN} value for a certain length of time.
    + * This can then be checked via {@link BrainUtils#isOnSpecialCooldown(LivingEntity)} as needed. + * + * @param entity The entity to check the brain of + * @param ticks The length of time (in ticks) the cooldown should apply for + */ + public static void setSpecialCooldown(LivingEntity entity, int ticks) { + setForgettableMemory(entity, SBLMemoryTypes.SPECIAL_ATTACK_COOLDOWN.get(), true, ticks); + } + + /** + * Checks whether the entity has had a {@link SBLMemoryTypes#SPECIAL_ATTACK_COOLDOWN} set, and it hasn't + * expired.
    + * This can be used for cross-behaviour cooldowns and interactions + * + * @param entity The entity to check the brain of + * @return Whether the entity has a cooldown currently active + */ + public static boolean isOnSpecialCooldown(LivingEntity entity) { + return hasMemory(entity, SBLMemoryTypes.SPECIAL_ATTACK_COOLDOWN.get()); + } + + /** + * Returns a stream of all {@link BehaviorControl Behaviours} registered to this brain + */ + public static Stream> getAllBehaviours(Brain brain) { + if (brain instanceof SmartBrain smartBrain) + return smartBrain.getBehaviours(); + + return brain.availableBehaviorsByPriority.values() + .stream() + .map(Map::values) + .flatMap(set -> set.stream().map(value -> value.stream().toList()).flatMap(List::stream)); + } + + /** + * Loops over all {@link BehaviorControl Behaviours} registered to this brain, calling the consumer for each + * + * @param brain The brain to scrape the behaviours of + * @param consumer The consumer called for each + */ + public static void forEachBehaviour(Brain brain, BrainBehaviourConsumer consumer) { + if (brain instanceof SmartBrain smartBrain) { + smartBrain.forEachBehaviour(consumer); + + return; + } + + Set>>>> behaviours = + (Set) brain.availableBehaviorsByPriority.entrySet(); + + for (Map.Entry>>> priorityEntry : behaviours) { + Integer priority = priorityEntry.getKey(); + + for (Map.Entry>> activityEntry : priorityEntry.getValue().entrySet()) { + Activity activity = activityEntry.getKey(); + + for (BehaviorControl behaviour : activityEntry.getValue()) { + consumeBehaviour(priority, activity, behaviour, null, consumer); + } + } + } + } + + private static void consumeBehaviour( + int priority, + Activity activity, + BehaviorControl behaviour, + @Nullable BehaviorControl parentBehaviour, + BrainBehaviourConsumer consumer + ) { + consumer.consume(priority, activity, behaviour, parentBehaviour); + + if (behaviour instanceof GateBehavior groupBehaviour) { + groupBehaviour.behaviors.stream() + .forEach( + childBehaviour -> consumeBehaviour( + priority, + activity, + (BehaviorControl) childBehaviour, + groupBehaviour, + consumer + ) + ); + } else if (behaviour instanceof GroupBehaviour groupBehaviour) { + groupBehaviour.getBehaviours() + .forEachRemaining( + childBehaviour -> consumeBehaviour( + priority, + activity, + (BehaviorControl) childBehaviour, + groupBehaviour, + consumer + ) + ); + } + } + + /** + * Removes any behaviours matching the given predicate from the provided brain.
    + * Removed behaviours are stopped prior to removal + * + * @param entity The owner of the brain + * @param predicate The predicate checked for each + */ + public static void removeBehaviour(E entity, BrainBehaviourPredicate predicate) { + if (entity.getBrain() instanceof SmartBrain smartBrain) { + smartBrain.removeBehaviour(entity, predicate); + + return; + } + + Set>>>> behaviours = (Set) entity + .getBrain().availableBehaviorsByPriority.entrySet(); + + for (Map.Entry>>> priorityEntry : behaviours) { + Integer priority = priorityEntry.getKey(); + + for (Map.Entry>> activityEntry : priorityEntry.getValue().entrySet()) { + Activity activity = activityEntry.getKey(); + + for (Iterator> iterator = activityEntry.getValue().iterator(); iterator.hasNext();) { + BehaviorControl behaviour = iterator.next(); + + checkBehaviour(priority, activity, behaviour, null, predicate, () -> { + if (behaviour.getStatus() == Behavior.Status.RUNNING) + behaviour.doStop((ServerLevel) entity.level(), entity, entity.level().getGameTime()); + + iterator.remove(); + }); + } + } + } + } + + private static void checkBehaviour( + int priority, + Activity activity, + BehaviorControl behaviour, + @Nullable BehaviorControl parentBehaviour, + BrainBehaviourPredicate predicate, + Runnable callback + ) { + if (predicate.isBehaviour(priority, activity, behaviour, parentBehaviour)) { + callback.run(); + } else if (behaviour instanceof GateBehavior groupBehaviour) { + for ( + Iterator> childBehaviourIterator = groupBehaviour.behaviors.iterator(); + childBehaviourIterator.hasNext(); + ) { + checkBehaviour( + priority, + activity, + childBehaviourIterator.next(), + groupBehaviour, + predicate, + childBehaviourIterator::remove + ); + } + + if (!groupBehaviour.behaviors.iterator().hasNext()) + callback.run(); + } else if (behaviour instanceof GroupBehaviour groupBehaviour) { + for ( + Iterator> childBehaviourIterator = groupBehaviour.getBehaviours(); + childBehaviourIterator.hasNext(); + ) { + checkBehaviour( + priority, + activity, + childBehaviourIterator.next(), + groupBehaviour, + predicate, + childBehaviourIterator::remove + ); + } + + if (!groupBehaviour.getBehaviours().hasNext()) + callback.run(); + } + } + + /** + * Safely a new {@link BehaviorControl Behaviour} to the given {@link Brain} + * + * @param brain The brain to add the behaviour to + * @param priority The priority index the behaviour belongs to (lower runs earlier) + * @param activity The activity category the behaviour belongs to + * @param behaviourControl The behaviour to add + */ + public static void addBehaviour(Brain brain, int priority, Activity activity, BehaviorControl behaviourControl) { + if (brain instanceof SmartBrain smartBrain) { + smartBrain.addBehaviour(priority, activity, behaviourControl); + + return; + } + + brain.availableBehaviorsByPriority.computeIfAbsent(priority, priority2 -> Maps.newHashMap()) + .computeIfAbsent(activity, activity2 -> Sets.newLinkedHashSet()) + .add(behaviourControl); + + if (behaviourControl instanceof Behavior behavior) { + for (MemoryModuleType memoryType : behavior.entryCondition.keySet()) { + brain.memories.putIfAbsent(memoryType, Optional.empty()); + } + } + } + + /** + * Adds a full {@link BrainActivityGroup} to the brain, inclusive of activities and conditions + */ + public static void addActivity(Brain brain, BrainActivityGroup behaviourGroup) { + if (brain instanceof SmartBrain smartBrain) { + smartBrain.addActivity(behaviourGroup); + + return; + } + + brain.addActivityAndRemoveMemoriesWhenStopped( + behaviourGroup.getActivity(), + (ImmutableList) behaviourGroup.pairBehaviourPriorities(), + behaviourGroup.getActivityStartMemoryConditions(), + behaviourGroup.getWipedMemoriesOnFinish() + ); + } + + /** + * Adds a sensor to the given brain, additionally allowing for custom instantiation.
    + * Automatically adds detected memories to the brain, but because of the nature of the vanilla brain system, you may + * need to {@link BrainUtils#addMemories add additional memories manually} if Mojang didn't set something up + * properly + */ + public static > void addSensor(Brain brain, SensorType sensorType, S sensor) { + if (brain instanceof SmartBrain smartBrain) { + if (!(sensor instanceof ExtendedSensor extendedSensor)) + throw new IllegalArgumentException( + "Attempted to provide sensor to SmartBrain, only ExtendedSensor subclasses acceptable. Sensor: " + + sensor.getClass() + ); + + smartBrain.addSensor(extendedSensor); + + return; + } + + brain.sensors.put((SensorType) sensorType, (Sensor) sensor); + addMemories(brain, sensor.requires().toArray(new MemoryModuleType[0])); + } + + /** + * Adds the given {@link MemoryModuleType} to the provided brain.
    + * Generally only required if modifying vanilla brains and additional memories are needed. + */ + public static void addMemories(Brain brain, MemoryModuleType... memories) { + if (brain instanceof SmartBrain smartBrain) { + for (MemoryModuleType memoryType : memories) { + smartBrain.getMemory(memoryType); + } + + return; + } + + for (MemoryModuleType memoryType : memories) { + brain.memories.computeIfAbsent(memoryType, key -> Optional.empty()).map(ExpirableValue::getValue); + } + } + + /** + * Adds the given scheduled activity transition to the provided brain's + * {@link net.minecraft.world.entity.schedule.Schedule schedule}, creating a new schedule if required. + * + * @param brain The brain the schedule belongs to + * @param activity The activity to transition to + * @param tickTime The tick-time the activity transition should happen + * @param tickType The type of tick tracking the schedule should use, if a new schedule has to be created. + */ + public static void addScheduledActivityTransition( + Brain brain, + Activity activity, + int tickTime, + SmartBrainSchedule.Type tickType + ) { + if (brain instanceof SmartBrain smartBrain) { + SmartBrainSchedule schedule; + + if ((schedule = smartBrain.getSchedule()) == null) + smartBrain.setSchedule((schedule = new SmartBrainSchedule(tickType))); + + schedule.activityAt(tickTime, activity); + } else { + Schedule schedule; + + if ((schedule = brain.getSchedule()) == Schedule.EMPTY) + brain.setSchedule(new Schedule()); + + Timeline timeline = schedule.timelines.computeIfAbsent(activity, key -> new Timeline()); + + timeline.addKeyframe(tickTime, 1); + + for (Map.Entry entry : schedule.timelines.entrySet()) { + if (entry.getKey() != activity) + entry.getValue().addKeyframe(tickTime, 0); + } + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/EntityRetrievalUtil.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/EntityRetrievalUtil.java index fe544a025..ed3ebcf5a 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/EntityRetrievalUtil.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/util/EntityRetrievalUtil.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.util; @@ -20,312 +19,352 @@ import java.util.function.Predicate; /** - * A helper class for retrieving entities from a given world. This removes a lot - * of the overhead of vanilla's type-checking and redundant stream-collection. - * Ultimately this leaves casting up to the end-user, and streamlines the actual - * retrieval functions to their most optimised form. + * A helper class for retrieving entities from a given world. This removes a lot of the overhead of vanilla's + * type-checking and redundant stream-collection. Ultimately this leaves casting up to the end-user, and streamlines the + * actual retrieval functions to their most optimised form. */ public final class EntityRetrievalUtil { - /** - * Get the nearest entity from an existing list of entities. - * - * @param origin The center-point of the distance comparison - * @param entities The existing list of entities - * @return The closest entity to the origin point, or null if the input list was - * empty - * @param The entity type - */ - @Nullable - public static T getNearest(Vec3 origin, List entities) { - if (entities.isEmpty()) - return null; - double dist = Double.MAX_VALUE; - T closest = null; + /** + * Get the nearest entity from an existing list of entities. + * + * @param origin The center-point of the distance comparison + * @param entities The existing list of entities + * @return The closest entity to the origin point, or null if the input list was empty + * @param The entity type + */ + @Nullable + public static T getNearest(Vec3 origin, List entities) { + if (entities.isEmpty()) + return null; - for (T entity : entities) { - double entityDist = entity.distanceToSqr(origin); + double dist = Double.MAX_VALUE; + T closest = null; - if (entityDist < dist) { - dist = entityDist; - closest = entity; - } - } + for (T entity : entities) { + double entityDist = entity.distanceToSqr(origin); - return closest; - } + if (entityDist < dist) { + dist = entityDist; + closest = entity; + } + } - /** - * Retrieve the nearest entity with a certain radius of a given origin point - * that meet a given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The predicate to filter entities by - * @return The closest entity found that meets the given criteria, or null if - * none found - * @param The output entity subtype - */ - @Nullable - public static T getNearestEntity(Entity origin, double radius, Predicate predicate) { - return getNearestEntity(origin, radius, radius, radius, predicate); - } + return closest; + } - /** - * Retrieve the nearest entity with a certain radius of a given origin point - * that meet a given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The predicate to filter entities by - * @return The closest entity found that meets the given criteria, or null if - * none found - * @param The output entity subtype - */ - @Nullable - public static T getNearestEntity(Entity origin, double radiusX, double radiusY, double radiusZ, Predicate predicate) { - return getNearestEntity(origin.level(), - new AABB(origin.getX() - radiusX, origin.getY() - radiusY, origin.getZ() - radiusZ, - origin.getX() + radiusX, origin.getY() + radiusY, origin.getZ() + radiusZ), - origin.position(), predicate); - } + /** + * Retrieve the nearest entity with a certain radius of a given origin point that meet a given criteria.
    + * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check + * {@code instanceof} in your predicate if you intend to use any subclass of Entity + * + * @param origin The entity to act as the central point of the search radius + * @param radius The radius on the axis to search + * @param predicate The predicate to filter entities by + * @return The closest entity found that meets the given criteria, or null if none found + * @param The output entity subtype + */ + @Nullable + public static T getNearestEntity( + Entity origin, + double radius, + Predicate predicate + ) { + return getNearestEntity(origin, radius, radius, radius, predicate); + } - /** - * Retrieve the nearest entity with a certain radius of a given origin point - * that meet a given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param level The level to search in - * @param area The region to search for entities in - * @param origin The center-point of the search - * @param predicate The predicate to filter entities by - * @return The closest entity found that meets the given criteria, or null if - * none found - * @param The output entity subtype - */ - @Nullable - public static T getNearestEntity(Level level, AABB area, Vec3 origin, Predicate predicate) { - final Predicate typeSafePredicate = (Predicate) predicate; - final MutableDouble dist = new MutableDouble(Double.MAX_VALUE); - final MutableObject closest = new MutableObject<>(null); + /** + * Retrieve the nearest entity with a certain radius of a given origin point that meet a given criteria.
    + * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check + * {@code instanceof} in your predicate if you intend to use any subclass of Entity + * + * @param origin The entity to act as the central point of the search radius + * @param radiusX The radius on the x-axis to search + * @param radiusY The radius on the y-axis to search + * @param radiusZ The radius on the z-axis to search + * @param predicate The predicate to filter entities by + * @return The closest entity found that meets the given criteria, or null if none found + * @param The output entity subtype + */ + @Nullable + public static T getNearestEntity( + Entity origin, + double radiusX, + double radiusY, + double radiusZ, + Predicate predicate + ) { + return getNearestEntity( + origin.level(), + new AABB( + origin.getX() - radiusX, + origin.getY() - radiusY, + origin.getZ() - radiusZ, + origin.getX() + radiusX, + origin.getY() + radiusY, + origin.getZ() + radiusZ + ), + origin.position(), + predicate + ); + } - level.getEntities().get(area, entity -> { - if (typeSafePredicate.test(entity)) { - double entityDist = entity.distanceToSqr(origin); + /** + * Retrieve the nearest entity with a certain radius of a given origin point that meet a given criteria.
    + * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check + * {@code instanceof} in your predicate if you intend to use any subclass of Entity + * + * @param level The level to search in + * @param area The region to search for entities in + * @param origin The center-point of the search + * @param predicate The predicate to filter entities by + * @return The closest entity found that meets the given criteria, or null if none found + * @param The output entity subtype + */ + @Nullable + public static T getNearestEntity( + Level level, + AABB area, + Vec3 origin, + Predicate predicate + ) { + final Predicate typeSafePredicate = (Predicate) predicate; + final MutableDouble dist = new MutableDouble(Double.MAX_VALUE); + final MutableObject closest = new MutableObject<>(null); - if (entityDist < dist.getValue()) { - dist.setValue(entityDist); - closest.setValue(entity); - } - } - }); + level.getEntities().get(area, entity -> { + if (typeSafePredicate.test(entity)) { + double entityDist = entity.distanceToSqr(origin); - return (T) closest.getValue(); - } + if (entityDist < dist.getValue()) { + dist.setValue(entityDist); + closest.setValue(entity); + } + } + }); - /** - * Retrieve the nearest player with a certain radius of a given origin point - * that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The predicate to filter players by - * @return The closest entity found that meets the given criteria, or null if - * none found - */ - @Nullable - public static Player getNearestPlayer(Entity origin, double radius, Predicate predicate) { - return getNearestPlayer(origin, radius, radius, radius, predicate); - } + return (T) closest.getValue(); + } - /** - * Retrieve the nearest player with a certain radius of a given origin point - * that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The predicate to filter players by - * @return The closest entity found that meets the given criteria, or null if - * none found - */ - @Nullable - public static Player getNearestPlayer(Entity origin, double radiusX, double radiusY, double radiusZ, Predicate predicate) { - return getNearestPlayer(origin.level(), - new AABB(origin.getX() - radiusX, origin.getY() - radiusY, origin.getZ() - radiusZ, - origin.getX() + radiusX, origin.getY() + radiusY, origin.getZ() + radiusZ), - origin.position(), predicate); - } + /** + * Retrieve the nearest player with a certain radius of a given origin point that meet a given criteria. + * + * @param origin The entity to act as the central point of the search radius + * @param radius The radius on the axis to search + * @param predicate The predicate to filter players by + * @return The closest entity found that meets the given criteria, or null if none found + */ + @Nullable + public static Player getNearestPlayer(Entity origin, double radius, Predicate predicate) { + return getNearestPlayer(origin, radius, radius, radius, predicate); + } - /** - * Retrieve the nearest player with a certain radius of a given origin point - * that meet a given criteria. - * - * @param level The level to search in - * @param area The region to search for players in - * @param origin The center-point of the search - * @param predicate The predicate to filter players by - * @return The closest entity found that meets the given criteria, or null if - * none found - */ - @Nullable - public static Player getNearestPlayer(Level level, AABB area, Vec3 origin, Predicate predicate) { - double dist = Double.MAX_VALUE; - Player closest = null; + /** + * Retrieve the nearest player with a certain radius of a given origin point that meet a given criteria. + * + * @param origin The entity to act as the central point of the search radius + * @param radiusX The radius on the x-axis to search + * @param radiusY The radius on the y-axis to search + * @param radiusZ The radius on the z-axis to search + * @param predicate The predicate to filter players by + * @return The closest entity found that meets the given criteria, or null if none found + */ + @Nullable + public static Player getNearestPlayer( + Entity origin, + double radiusX, + double radiusY, + double radiusZ, + Predicate predicate + ) { + return getNearestPlayer( + origin.level(), + new AABB( + origin.getX() - radiusX, + origin.getY() - radiusY, + origin.getZ() - radiusZ, + origin.getX() + radiusX, + origin.getY() + radiusY, + origin.getZ() + radiusZ + ), + origin.position(), + predicate + ); + } - for (Player player : level.players()) { - if (area.contains(player.position()) && predicate.test(player)) { - double playerDist = player.distanceToSqr(origin); + /** + * Retrieve the nearest player with a certain radius of a given origin point that meet a given criteria. + * + * @param level The level to search in + * @param area The region to search for players in + * @param origin The center-point of the search + * @param predicate The predicate to filter players by + * @return The closest entity found that meets the given criteria, or null if none found + */ + @Nullable + public static Player getNearestPlayer(Level level, AABB area, Vec3 origin, Predicate predicate) { + double dist = Double.MAX_VALUE; + Player closest = null; - if (playerDist < dist) { - dist = playerDist; - closest = player; - } - } - } + for (Player player : level.players()) { + if (area.contains(player.position()) && predicate.test(player)) { + double playerDist = player.distanceToSqr(origin); - return closest; - } + if (playerDist < dist) { + dist = playerDist; + closest = player; + } + } + } - /** - * Get all players within a given region. - * - * @param level The level in which to search - * @param area The region in which to find players - * @return A list of players that are within the given region - */ - public static List getPlayers(Level level, AABB area) { - return getPlayers(level, area, pl -> true); - } + return closest; + } - /** - * Get all players within a given region that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The criteria to meet for a player to be included in the - * returned list - * @return A list of players that are within the given region that meet the - * criteria in the predicate - */ - public static List getPlayers(Entity origin, double radius, Predicate predicate) { - return getPlayers(origin, radius, radius, radius, predicate); - } + /** + * Get all players within a given region. + * + * @param level The level in which to search + * @param area The region in which to find players + * @return A list of players that are within the given region + */ + public static List getPlayers(Level level, AABB area) { + return getPlayers(level, area, pl -> true); + } - /** - * Get all players within a given region that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The criteria to meet for a player to be included in the - * returned list - * @return A list of players that are within the given region that meet the - * criteria in the predicate - */ - public static List getPlayers(Entity origin, double radiusX, double radiusY, double radiusZ, Predicate predicate) { - return getPlayers(origin.level(), new AABB(origin.getX() - radiusX, origin.getY() - radiusY, - origin.getZ() - radiusZ, origin.getX() + radiusX, origin.getY() + radiusY, origin.getZ() + radiusZ), - predicate); - } + /** + * Get all players within a given region that meet a given criteria. + * + * @param origin The entity to act as the central point of the search radius + * @param radius The radius on the axis to search + * @param predicate The criteria to meet for a player to be included in the returned list + * @return A list of players that are within the given region that meet the criteria in the predicate + */ + public static List getPlayers(Entity origin, double radius, Predicate predicate) { + return getPlayers(origin, radius, radius, radius, predicate); + } - /** - * Get all players within a given region that meet a given criteria. - * - * @param level The level in which to search - * @param area The region in which to find players - * @param predicate The criteria to meet for a player to be included in the - * returned list - * @return A list of players that are within the given region that meet the - * criteria in the predicate - */ - public static List getPlayers(Level level, AABB area, Predicate predicate) { - List players = new ObjectArrayList<>(); + /** + * Get all players within a given region that meet a given criteria. + * + * @param origin The entity to act as the central point of the search radius + * @param radiusX The radius on the x-axis to search + * @param radiusY The radius on the y-axis to search + * @param radiusZ The radius on the z-axis to search + * @param predicate The criteria to meet for a player to be included in the returned list + * @return A list of players that are within the given region that meet the criteria in the predicate + */ + public static List getPlayers( + Entity origin, + double radiusX, + double radiusY, + double radiusZ, + Predicate predicate + ) { + return getPlayers( + origin.level(), + new AABB( + origin.getX() - radiusX, + origin.getY() - radiusY, + origin.getZ() - radiusZ, + origin.getX() + radiusX, + origin.getY() + radiusY, + origin.getZ() + radiusZ + ), + predicate + ); + } - for (Player player : level.players()) { - if (area.contains(player.position()) && predicate.test(player)) - players.add(player); - } + /** + * Get all players within a given region that meet a given criteria. + * + * @param level The level in which to search + * @param area The region in which to find players + * @param predicate The criteria to meet for a player to be included in the returned list + * @return A list of players that are within the given region that meet the criteria in the predicate + */ + public static List getPlayers(Level level, AABB area, Predicate predicate) { + List players = new ObjectArrayList<>(); - return players; - } + for (Player player : level.players()) { + if (area.contains(player.position()) && predicate.test(player)) + players.add(player); + } - /** - * Retrieve all nearby entities from the given area that meet the given - * criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The predicate to filter entities by - * @return A list of entities found in the provided region that meet the - * criteria of the predicate, or an empty list if none match - * @param The output entity subtype - */ - public static List getEntities(Entity origin, double radius, Predicate predicate) { - return getEntities(origin, radius, radius, radius, predicate); - } + return players; + } - /** - * Retrieve all nearby entities from the given area that meet the given - * criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The predicate to filter entities by - * @return A list of entities found in the provided region that meet the - * criteria of the predicate, or an empty list if none match - * @param The output entity subtype - */ - public static List getEntities(Entity origin, double radiusX, double radiusY, double radiusZ, Predicate predicate) { - return getEntities(origin.level(), - new AABB(origin.getX() - radiusX, origin.getY() - radiusY, origin.getZ() - radiusZ, - origin.getX() + radiusX, origin.getY() + radiusY, origin.getZ() + radiusZ), - predicate.and(entity -> entity != origin)); - } + /** + * Retrieve all nearby entities from the given area that meet the given criteria.
    + * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check + * {@code instanceof} in your predicate if you intend to use any subclass of Entity + * + * @param origin The entity to act as the central point of the search radius + * @param radius The radius on the axis to search + * @param predicate The predicate to filter entities by + * @return A list of entities found in the provided region that meet the criteria of the predicate, or an empty list + * if none match + * @param The output entity subtype + */ + public static List getEntities(Entity origin, double radius, Predicate predicate) { + return getEntities(origin, radius, radius, radius, predicate); + } - /** - * Retrieve all nearby entities from the given area that meet the given - * criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param level The level to search in - * @param area The region to search for entities in - * @param predicate The predicate to filter entities by - * @return A list of entities found in the provided region that meet the - * criteria of the predicate, or an empty list if none match - * @param The output entity subtype - */ - public static List getEntities(Level level, AABB area, Predicate predicate) { - Predicate typeSafePredicate = (Predicate) predicate; - List entities = new ObjectArrayList<>(); + /** + * Retrieve all nearby entities from the given area that meet the given criteria.
    + * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check + * {@code instanceof} in your predicate if you intend to use any subclass of Entity + * + * @param origin The entity to act as the central point of the search radius + * @param radiusX The radius on the x-axis to search + * @param radiusY The radius on the y-axis to search + * @param radiusZ The radius on the z-axis to search + * @param predicate The predicate to filter entities by + * @return A list of entities found in the provided region that meet the criteria of the predicate, or an empty list + * if none match + * @param The output entity subtype + */ + public static List getEntities( + Entity origin, + double radiusX, + double radiusY, + double radiusZ, + Predicate predicate + ) { + return getEntities( + origin.level(), + new AABB( + origin.getX() - radiusX, + origin.getY() - radiusY, + origin.getZ() - radiusZ, + origin.getX() + radiusX, + origin.getY() + radiusY, + origin.getZ() + radiusZ + ), + predicate.and(entity -> entity != origin) + ); + } - level.getEntities().get(area, entity -> { - if (typeSafePredicate.test(entity)) - entities.add((T) entity); - }); + /** + * Retrieve all nearby entities from the given area that meet the given criteria.
    + * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check + * {@code instanceof} in your predicate if you intend to use any subclass of Entity + * + * @param level The level to search in + * @param area The region to search for entities in + * @param predicate The predicate to filter entities by + * @return A list of entities found in the provided region that meet the criteria of the predicate, or an empty list + * if none match + * @param The output entity subtype + */ + public static List getEntities(Level level, AABB area, Predicate predicate) { + Predicate typeSafePredicate = (Predicate) predicate; + List entities = new ObjectArrayList<>(); - return entities; - } + level.getEntities().get(area, entity -> { + if (typeSafePredicate.test(entity)) + entities.add((T) entity); + }); + + return entities; + } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/RandomUtil.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/RandomUtil.java index e7f5d1f38..3cc99081d 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/RandomUtil.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/util/RandomUtil.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.util; @@ -23,245 +22,315 @@ * Utility class for easy and legible random functionality. */ public final class RandomUtil { - public static final EasyRandom RANDOM = new EasyRandom(RandomSource.createThreadSafe()); - - public static ThreadLocalRandom getRandomInstance() { - return ThreadLocalRandom.current(); - } - - public static boolean fiftyFifty() { - return RANDOM.fiftyFifty(); - } - - public static boolean oneInNChance(int n) { - return RANDOM.oneInNChance(n); - } - - public static boolean percentChance(double percentChance) { - return RANDOM.percentChance(percentChance); - } - - public static boolean percentChance(float percentChance) { - return RANDOM.percentChance(percentChance); - } - - public static int randomNumberUpTo(int upperBound) { - return RANDOM.randomNumberUpTo(upperBound); - } - - public static float randomValueUpTo(float upperBound) { - return RANDOM.randomValueUpTo(upperBound); - } - - public static double randomValueUpTo(double upperBound) { - return RANDOM.randomValueUpTo(upperBound); - } - - public static double randomGaussianValue() { - return RANDOM.randomGaussianValue(); - } - - public static double randomScaledGaussianValue(double scale) { - return RANDOM.randomScaledGaussianValue(scale); - } - - public static int randomNumberBetween(int min, int max) { - return RANDOM.randomNumberBetween(min, max); - } - - public static double randomValueBetween(double min, double max) { - return RANDOM.randomValueBetween(min, max); - } - - public static T getRandomSelection(@NotNull T... options) { - return RANDOM.getRandomSelection(options); - } - - public static T getRandomSelection(@NotNull List options) { - return RANDOM.getRandomSelection(options); - } - - @NotNull - public static BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius) { - return RANDOM.getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius); - } - - @NotNull - public static BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius, boolean safeSurfacePlacement, Level world) { - return RANDOM.getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, safeSurfacePlacement, world); - } - - @NotNull - public static BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius, int minSpreadX, int minSpreadY, int minSpreadZ, boolean safeSurfacePlacement, Level world, int tries, @Nullable BiPredicate statePredicate) { - return RANDOM.getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, minSpreadX, minSpreadY, minSpreadZ, safeSurfacePlacement, world, tries, statePredicate); - } - - public static final class EasyRandom implements RandomSource { - private final RandomSource random; - - public EasyRandom() { - this(RandomSource.create()); - } - - public EasyRandom(@NotNull RandomSource rand) { - this.random = rand; - } - - public RandomSource getSource() { - return RandomSource.create(); - } - - public boolean fiftyFifty() { - return random.nextBoolean(); - } - - public boolean oneInNChance(int n) { - if (n <= 0) - return false; - - return random.nextFloat() < 1 / (float)n; - } - - public boolean percentChance(double percentChance) { - if (percentChance <= 0) - return false; - - if (percentChance >= 1) - return true; - - return random.nextDouble() < percentChance; - } - - public boolean percentChance(float percentChance) { - if (percentChance <= 0) - return false; - - if (percentChance >= 1) - return true; - - return random.nextDouble() < percentChance; - } - - public int randomNumberUpTo(int upperBound) { - return random.nextInt(upperBound); - } - - public float randomValueUpTo(float upperBound) { - return random.nextFloat() * upperBound; - } - - public double randomValueUpTo(double upperBound) { - return random.nextDouble() * upperBound; - } - - public double randomGaussianValue() { - return random.nextGaussian(); - } - - public double randomScaledGaussianValue(double scale) { - return random.nextGaussian() * scale; - } - - public int randomNumberBetween(int min, int max) { - return min + (int)Math.floor(random.nextDouble() * (1 + max - min)); - } - - public double randomValueBetween(double min, double max) { - return min + random.nextDouble() * (max - min); - } - - public T getRandomSelection(@NotNull T... options) { - return options[random.nextInt(options.length)]; - } - - public T getRandomSelection(@NotNull List options) { - return options.get(random.nextInt(options.size())); - } - - @NotNull - public BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius) { - return getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, false, null); - } - - @NotNull - public BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius, boolean safeSurfacePlacement, Level world) { - return getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, 0, 0, 0, safeSurfacePlacement, world, 1, null); - } - - @NotNull - public BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius, int minSpreadX, int minSpreadY, int minSpreadZ, boolean safeSurfacePlacement, Level world, int tries, @Nullable BiPredicate statePredicate) { BlockPos.MutableBlockPos mutablePos = centerPos.mutable(); - xRadius = Math.max(xRadius - minSpreadX, 0); - yRadius = Math.max(yRadius - minSpreadY, 0); - zRadius = Math.max(zRadius - minSpreadZ, 0); - - for (int i = 0; i < tries; i++) { - double xAdjust = random.nextFloat() * xRadius * 2 - xRadius; - double yAdjust = random.nextFloat() * yRadius * 2 - yRadius; - double zAdjust = random.nextFloat() * zRadius * 2 - zRadius; - int newX = (int)Math.floor(centerPos.getX() + xAdjust + minSpreadX * Math.signum(xAdjust)); - int newY = (int)Math.floor(centerPos.getY() + yAdjust + minSpreadY * Math.signum(yAdjust)); - int newZ = (int)Math.floor(centerPos.getZ() + zAdjust + minSpreadZ * Math.signum(zAdjust)); - - mutablePos.set(newX, newY, newZ); - - if (safeSurfacePlacement && world != null) - mutablePos.set(world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, mutablePos)); - - if (statePredicate == null || statePredicate.test(world.getBlockState(mutablePos), mutablePos.immutable())) - return mutablePos.immutable(); - } - - return centerPos; - } - - @Override - public EasyRandom fork() { - return new EasyRandom(this.random.fork()); - } - - @Override - public PositionalRandomFactory forkPositional() { - return this.random.forkPositional(); - } - - @Override - public void setSeed(long seed) { - this.random.setSeed(seed); - } - - @Override - public int nextInt() { - return this.random.nextInt(); - } - - @Override - public int nextInt(int upperLimit) { - return this.random.nextInt(upperLimit); - } - - @Override - public long nextLong() { - return this.random.nextLong(); - } - - @Override - public boolean nextBoolean() { - return this.random.nextBoolean(); - } - - @Override - public float nextFloat() { - return this.random.nextFloat(); - } - - @Override - public double nextDouble() { - return this.random.nextDouble(); - } - - @Override - public double nextGaussian() { - return this.random.nextGaussian(); - } - } -} \ No newline at end of file + + public static final EasyRandom RANDOM = new EasyRandom(RandomSource.createThreadSafe()); + + public static ThreadLocalRandom getRandomInstance() { + return ThreadLocalRandom.current(); + } + + public static boolean fiftyFifty() { + return RANDOM.fiftyFifty(); + } + + public static boolean oneInNChance(int n) { + return RANDOM.oneInNChance(n); + } + + public static boolean percentChance(double percentChance) { + return RANDOM.percentChance(percentChance); + } + + public static boolean percentChance(float percentChance) { + return RANDOM.percentChance(percentChance); + } + + public static int randomNumberUpTo(int upperBound) { + return RANDOM.randomNumberUpTo(upperBound); + } + + public static float randomValueUpTo(float upperBound) { + return RANDOM.randomValueUpTo(upperBound); + } + + public static double randomValueUpTo(double upperBound) { + return RANDOM.randomValueUpTo(upperBound); + } + + public static double randomGaussianValue() { + return RANDOM.randomGaussianValue(); + } + + public static double randomScaledGaussianValue(double scale) { + return RANDOM.randomScaledGaussianValue(scale); + } + + public static int randomNumberBetween(int min, int max) { + return RANDOM.randomNumberBetween(min, max); + } + + public static double randomValueBetween(double min, double max) { + return RANDOM.randomValueBetween(min, max); + } + + public static T getRandomSelection(@NotNull T... options) { + return RANDOM.getRandomSelection(options); + } + + public static T getRandomSelection(@NotNull List options) { + return RANDOM.getRandomSelection(options); + } + + @NotNull + public static BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius) { + return RANDOM.getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius); + } + + @NotNull + public static BlockPos getRandomPositionWithinRange( + BlockPos centerPos, + int xRadius, + int yRadius, + int zRadius, + boolean safeSurfacePlacement, + Level world + ) { + return RANDOM.getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, safeSurfacePlacement, world); + } + + @NotNull + public static BlockPos getRandomPositionWithinRange( + BlockPos centerPos, + int xRadius, + int yRadius, + int zRadius, + int minSpreadX, + int minSpreadY, + int minSpreadZ, + boolean safeSurfacePlacement, + Level world, + int tries, + @Nullable BiPredicate statePredicate + ) { + return RANDOM.getRandomPositionWithinRange( + centerPos, + xRadius, + yRadius, + zRadius, + minSpreadX, + minSpreadY, + minSpreadZ, + safeSurfacePlacement, + world, + tries, + statePredicate + ); + } + + public static final class EasyRandom implements RandomSource { + + private final RandomSource random; + + public EasyRandom() { + this(RandomSource.create()); + } + + public EasyRandom(@NotNull RandomSource rand) { + this.random = rand; + } + + public RandomSource getSource() { + return RandomSource.create(); + } + + public boolean fiftyFifty() { + return random.nextBoolean(); + } + + public boolean oneInNChance(int n) { + if (n <= 0) + return false; + + return random.nextFloat() < 1 / (float) n; + } + + public boolean percentChance(double percentChance) { + if (percentChance <= 0) + return false; + + if (percentChance >= 1) + return true; + + return random.nextDouble() < percentChance; + } + + public boolean percentChance(float percentChance) { + if (percentChance <= 0) + return false; + + if (percentChance >= 1) + return true; + + return random.nextDouble() < percentChance; + } + + public int randomNumberUpTo(int upperBound) { + return random.nextInt(upperBound); + } + + public float randomValueUpTo(float upperBound) { + return random.nextFloat() * upperBound; + } + + public double randomValueUpTo(double upperBound) { + return random.nextDouble() * upperBound; + } + + public double randomGaussianValue() { + return random.nextGaussian(); + } + + public double randomScaledGaussianValue(double scale) { + return random.nextGaussian() * scale; + } + + public int randomNumberBetween(int min, int max) { + return min + (int) Math.floor(random.nextDouble() * (1 + max - min)); + } + + public double randomValueBetween(double min, double max) { + return min + random.nextDouble() * (max - min); + } + + public T getRandomSelection(@NotNull T... options) { + return options[random.nextInt(options.length)]; + } + + public T getRandomSelection(@NotNull List options) { + return options.get(random.nextInt(options.size())); + } + + @NotNull + public BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius) { + return getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, false, null); + } + + @NotNull + public BlockPos getRandomPositionWithinRange( + BlockPos centerPos, + int xRadius, + int yRadius, + int zRadius, + boolean safeSurfacePlacement, + Level world + ) { + return getRandomPositionWithinRange( + centerPos, + xRadius, + yRadius, + zRadius, + 0, + 0, + 0, + safeSurfacePlacement, + world, + 1, + null + ); + } + + @NotNull + public BlockPos getRandomPositionWithinRange( + BlockPos centerPos, + int xRadius, + int yRadius, + int zRadius, + int minSpreadX, + int minSpreadY, + int minSpreadZ, + boolean safeSurfacePlacement, + Level world, + int tries, + @Nullable BiPredicate statePredicate + ) { + BlockPos.MutableBlockPos mutablePos = centerPos.mutable(); + xRadius = Math.max(xRadius - minSpreadX, 0); + yRadius = Math.max(yRadius - minSpreadY, 0); + zRadius = Math.max(zRadius - minSpreadZ, 0); + + for (int i = 0; i < tries; i++) { + double xAdjust = random.nextFloat() * xRadius * 2 - xRadius; + double yAdjust = random.nextFloat() * yRadius * 2 - yRadius; + double zAdjust = random.nextFloat() * zRadius * 2 - zRadius; + int newX = (int) Math.floor(centerPos.getX() + xAdjust + minSpreadX * Math.signum(xAdjust)); + int newY = (int) Math.floor(centerPos.getY() + yAdjust + minSpreadY * Math.signum(yAdjust)); + int newZ = (int) Math.floor(centerPos.getZ() + zAdjust + minSpreadZ * Math.signum(zAdjust)); + + mutablePos.set(newX, newY, newZ); + + if (safeSurfacePlacement && world != null) + mutablePos.set(world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, mutablePos)); + + if ( + statePredicate == null || statePredicate.test( + world.getBlockState(mutablePos), + mutablePos.immutable() + ) + ) + return mutablePos.immutable(); + } + + return centerPos; + } + + @Override + public EasyRandom fork() { + return new EasyRandom(this.random.fork()); + } + + @Override + public PositionalRandomFactory forkPositional() { + return this.random.forkPositional(); + } + + @Override + public void setSeed(long seed) { + this.random.setSeed(seed); + } + + @Override + public int nextInt() { + return this.random.nextInt(); + } + + @Override + public int nextInt(int upperLimit) { + return this.random.nextInt(upperLimit); + } + + @Override + public long nextLong() { + return this.random.nextLong(); + } + + @Override + public boolean nextBoolean() { + return this.random.nextBoolean(); + } + + @Override + public float nextFloat() { + return this.random.nextFloat(); + } + + @Override + public double nextDouble() { + return this.random.nextDouble(); + } + + @Override + public double nextGaussian() { + return this.random.nextGaussian(); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/SensoryUtils.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/SensoryUtils.java index db4045799..052e2971a 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/SensoryUtils.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/util/SensoryUtils.java @@ -1,59 +1,72 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.util; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; + import mod.azure.azurelib.sblforked.object.ExtendedTargetingConditions; /** * Helper class for sensory-related utility methods. - *

    Mostly this just replaces the poorly implemented methods in {@link net.minecraft.world.entity.ai.sensing.Sensor}

    + *

    + * Mostly this just replaces the poorly implemented methods in {@link net.minecraft.world.entity.ai.sensing.Sensor} + *

    */ public class SensoryUtils { + /** - * Check whether the given target is considered 'targetable' based on sensory and status conditions such as teams and line of sight + * Check whether the given target is considered 'targetable' based on sensory and status conditions such as teams + * and line of sight + * * @return Whether the target is considered targetable */ public static boolean isEntityTargetable(LivingEntity attacker, LivingEntity target) { - final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target ? - ExtendedTargetingConditions.forLookTarget().withFollowRange().skipInvisibilityCheck() : - ExtendedTargetingConditions.forLookTarget().withFollowRange(); + final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target + ? ExtendedTargetingConditions.forLookTarget().withFollowRange().skipInvisibilityCheck() + : ExtendedTargetingConditions.forLookTarget().withFollowRange(); return predicate.test(attacker, target); } /** - * Check whether the given target is considered 'attackable' based on sensory and status conditions such as teams and line of sight + * Check whether the given target is considered 'attackable' based on sensory and status conditions such as teams + * and line of sight + * * @return Whether the target is considered attackable */ public static boolean isEntityAttackable(LivingEntity attacker, LivingEntity target) { - final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target ? - ExtendedTargetingConditions.forAttackTarget().withFollowRange().skipInvisibilityCheck() : - ExtendedTargetingConditions.forAttackTarget().withFollowRange(); + final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target + ? ExtendedTargetingConditions.forAttackTarget().withFollowRange().skipInvisibilityCheck() + : ExtendedTargetingConditions.forAttackTarget().withFollowRange(); return predicate.test(attacker, target); } /** - * Check whether the given target is considered 'attackable' based on sensory and status conditions such as teams and difficulty, but specifically excluding a line of sight check + * Check whether the given target is considered 'attackable' based on sensory and status conditions such as teams + * and difficulty, but specifically excluding a line of sight check + * * @return Whether the target is considered attackable */ public static boolean isEntityAttackableIgnoringLineOfSight(LivingEntity attacker, LivingEntity target) { - final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target ? - ExtendedTargetingConditions.forAttackTarget().ignoreLineOfSight().withFollowRange().skipInvisibilityCheck() : - ExtendedTargetingConditions.forAttackTarget().ignoreLineOfSight().withFollowRange(); + final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target + ? ExtendedTargetingConditions.forAttackTarget() + .ignoreLineOfSight() + .withFollowRange() + .skipInvisibilityCheck() + : ExtendedTargetingConditions.forAttackTarget().ignoreLineOfSight().withFollowRange(); return predicate.test(attacker, target); } /** * Check whether the given target is visible to the entity + * * @return Whether the entity has line of sight to the target */ public static boolean hasLineOfSight(LivingEntity entity, Entity target) { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index 9ed19fbd0..7bfccc8f2 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -1,11 +1,6 @@ package mod.azure.azurelib.fabric; import com.mojang.blaze3d.platform.InputConstants; -import mod.azure.azurelib.common.api.client.helper.ClientUtils; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.network.packet.*; -import mod.azure.azurelib.fabric.core2.example.DroneRenderer; -import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; @@ -13,37 +8,52 @@ import net.minecraft.client.KeyMapping; import org.lwjgl.glfw.GLFW; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.network.packet.*; +import mod.azure.azurelib.fabric.core2.example.DroneRenderer; +import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; + public final class ClientListener implements ClientModInitializer { @Override public void onInitializeClient() { if (AzureLib.hasKeyBindsInitialized) { ClientUtils.RELOAD = new KeyMapping( - "key.azurelib.reload", - InputConstants.Type.KEYSYM, - GLFW.GLFW_KEY_R, - "category.azurelib.binds" + "key.azurelib.reload", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_R, + "category.azurelib.binds" ); KeyBindingHelper.registerKeyBinding(ClientUtils.RELOAD); ClientUtils.SCOPE = new KeyMapping( - "key.azurelib.scope", - InputConstants.Type.KEYSYM, - GLFW.GLFW_KEY_LEFT_ALT, - "category.azurelib.binds" + "key.azurelib.scope", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_LEFT_ALT, + "category.azurelib.binds" ); KeyBindingHelper.registerKeyBinding(ClientUtils.SCOPE); ClientUtils.FIRE_WEAPON = new KeyMapping( - "key.azurelib.fire", - InputConstants.Type.KEYSYM, - GLFW.GLFW_KEY_UNKNOWN, - "category.azurelib.binds" + "key.azurelib.fire", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_UNKNOWN, + "category.azurelib.binds" ); KeyBindingHelper.registerKeyBinding(ClientUtils.FIRE_WEAPON); } - ClientPlayNetworking.registerGlobalReceiver(BlockEntityAnimTriggerPacket.TYPE, (packet, context) -> packet.handle()); - ClientPlayNetworking.registerGlobalReceiver(BlockEntityAnimDataSyncPacket.TYPE, (packet, context) -> packet.handle()); + ClientPlayNetworking.registerGlobalReceiver( + BlockEntityAnimTriggerPacket.TYPE, + (packet, context) -> packet.handle() + ); + ClientPlayNetworking.registerGlobalReceiver( + BlockEntityAnimDataSyncPacket.TYPE, + (packet, context) -> packet.handle() + ); ClientPlayNetworking.registerGlobalReceiver(EntityAnimTriggerPacket.TYPE, (packet, context) -> packet.handle()); - ClientPlayNetworking.registerGlobalReceiver(EntityAnimDataSyncPacket.TYPE, (packet, context) -> packet.handle()); + ClientPlayNetworking.registerGlobalReceiver( + EntityAnimDataSyncPacket.TYPE, + (packet, context) -> packet.handle() + ); ClientPlayNetworking.registerGlobalReceiver(AnimTriggerPacket.TYPE, (packet, context) -> packet.handle()); ClientPlayNetworking.registerGlobalReceiver(AnimDataSyncPacket.TYPE, (packet, context) -> packet.handle()); ClientPlayNetworking.registerGlobalReceiver(SendConfigDataPacket.TYPE, (packet, context) -> packet.handle()); diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index df1eeb91f..49b8136fb 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -1,5 +1,9 @@ package mod.azure.azurelib.fabric; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.AzureLibMod; import mod.azure.azurelib.common.internal.common.config.AzureLibConfig; @@ -15,9 +19,6 @@ import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; import mod.azure.azurelib.fabric.platform.FabricAzureLibNetwork; import mod.azure.azurelib.sblforked.SBLConstants; -import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; -import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; public final class FabricAzureLibMod implements ModInitializer { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java index a4eb87e18..7654a40c0 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java @@ -1,10 +1,11 @@ package mod.azure.azurelib.fabric.core2.example; -import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.level.Level; +import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; + public class Drone extends Monster { private final AzAnimationDispatcher animationDispatcher; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java index 5f67ed1e5..d0bdc102e 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java @@ -1,5 +1,8 @@ package mod.azure.azurelib.fabric.core2.example; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.core2.animation.AzAnimationState; @@ -7,14 +10,13 @@ import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; public class DroneAnimator extends AzEntityAnimator { private static final ResourceLocation ANIMATIONS = AzureLib.modResource("animations/entity/drone.animation.json"); private static final String IDLE_ANIMATION_NAME = "animation.idle"; + private static final AzRawAnimation IDLE_ANIMATION = AzRawAnimation.begin().thenLoop(IDLE_ANIMATION_NAME); @Override diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneRenderer.java index e421d5b96..953218b68 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneRenderer.java @@ -1,16 +1,18 @@ package mod.azure.azurelib.fabric.core2.example; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; -import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; + public class DroneRenderer extends AzEntityRenderer { private static final ResourceLocation MODEL = AzureLib.modResource("geo/entity/drone.geo.json"); + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/drone.png"); public DroneRenderer(EntityRendererProvider.Context context) { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java index 7275502ca..d9205ed5e 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java @@ -1,6 +1,5 @@ package mod.azure.azurelib.fabric.core2.example; -import mod.azure.azurelib.common.internal.common.AzureLib; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; @@ -8,6 +7,8 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobCategory; +import mod.azure.azurelib.common.internal.common.AzureLib; + public class ExampleEntityTypes { public static final EntityType DRONE = register( diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java b/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java index 175daa4f9..7ec2febcb 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java @@ -1,20 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.fabric.event; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.common.api.client.renderer.*; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.client.renderer.MultiBufferSource; @@ -23,8 +14,16 @@ import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.api.client.renderer.*; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + public interface GeoRenderEvent { - + /** * Returns the renderer for this event * @@ -41,6 +40,7 @@ public interface GeoRenderEvent { * Renderer events for armor pieces being rendered by {@link GeoArmorRenderer} */ abstract class Armor implements GeoRenderEvent { + private final GeoArmorRenderer renderer; public Armor(GeoArmorRenderer renderer) { @@ -85,25 +85,42 @@ public EquipmentSlot getEquipmentSlot() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the armor piece will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the armor piece will not be rendered + * and the corresponding {@link Post} event will not be fired. */ public static class Pre extends Armor { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -140,6 +157,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -150,19 +168,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Armor { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -197,6 +231,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -207,11 +242,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Armor { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoArmorRenderer renderer) { super(renderer); @@ -220,7 +260,8 @@ public CompileRenderLayers(GeoArmorRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -231,6 +272,7 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } @@ -240,6 +282,7 @@ public interface Listener { * Renderer events for {@link BlockEntity BlockEntities} being rendered by {@link GeoBlockRenderer} */ abstract class Block implements GeoRenderEvent { + private final GeoBlockRenderer renderer; public Block(GeoBlockRenderer renderer) { @@ -267,25 +310,42 @@ public BlockEntity getBlockEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the block entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the block entity will not be rendered + * and the corresponding {@link Post} event will not be fired. */ public static class Pre extends Block { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -322,6 +382,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -332,19 +393,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Block { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -379,6 +456,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -389,11 +467,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Block { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoBlockRenderer renderer) { super(renderer); @@ -402,7 +485,8 @@ public CompileRenderLayers(GeoBlockRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -413,15 +497,18 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } } /** - * Renderer events for {@link net.minecraft.world.entity.Entity Entities} being rendered by {@link GeoEntityRenderer} + * Renderer events for {@link net.minecraft.world.entity.Entity Entities} being rendered by + * {@link GeoEntityRenderer} */ abstract class Entity implements GeoRenderEvent { + private final GeoEntityRenderer renderer; public Entity(GeoEntityRenderer renderer) { @@ -449,25 +536,42 @@ public net.minecraft.world.entity.Entity getEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the entity will not be rendered and the + * corresponding {@link Post} event will not be fired. */ public static class Pre extends Entity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -504,6 +608,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -514,19 +619,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Entity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -561,6 +682,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -571,11 +693,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Entity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoEntityRenderer renderer) { super(renderer); @@ -584,7 +711,8 @@ public CompileRenderLayers(GeoEntityRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -595,6 +723,7 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } @@ -604,6 +733,7 @@ public interface Listener { * Renderer events for {@link ItemStack Items} being rendered by {@link GeoItemRenderer} */ abstract class Item implements GeoRenderEvent { + private final GeoItemRenderer renderer; public Item(GeoItemRenderer renderer) { @@ -631,25 +761,42 @@ public ItemStack getItemStack() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the ItemStack will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the ItemStack will not be rendered and + * the corresponding {@link Post} event will not be fired. */ public static class Pre extends Item { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -686,6 +833,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -696,19 +844,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Item { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -743,6 +907,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -753,11 +918,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Item { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoItemRenderer renderer) { super(renderer); @@ -766,7 +936,8 @@ public CompileRenderLayers(GeoItemRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -777,6 +948,7 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } @@ -786,6 +958,7 @@ public interface Listener { * Renderer events for miscellaneous {@link GeoAnimatable animatables} being rendered by {@link GeoObjectRenderer} */ abstract class Object implements GeoRenderEvent { + private final GeoObjectRenderer renderer; public Object(GeoObjectRenderer renderer) { @@ -806,25 +979,42 @@ public GeoObjectRenderer getRenderer() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the object will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the object will not be rendered and the + * corresponding {@link Post} event will not be fired. */ public static class Pre extends Object { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -861,6 +1051,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -871,19 +1062,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Object { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -918,6 +1125,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -928,11 +1136,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Object { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoObjectRenderer renderer) { super(renderer); @@ -941,7 +1154,8 @@ public CompileRenderLayers(GeoObjectRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -952,15 +1166,18 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } } /** - * Renderer events for miscellaneous {@link GeoReplacedEntity replaced entities} being rendered by {@link GeoReplacedEntityRenderer} + * Renderer events for miscellaneous {@link GeoReplacedEntity replaced entities} being rendered by + * {@link GeoReplacedEntityRenderer} */ abstract class ReplacedEntity implements GeoRenderEvent { + private final GeoReplacedEntityRenderer renderer; public ReplacedEntity(GeoReplacedEntityRenderer renderer) { @@ -988,25 +1205,42 @@ public net.minecraft.world.entity.Entity getReplacedEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the entity will not be rendered and the + * corresponding {@link Post} event will not be fired. */ public static class Pre extends ReplacedEntity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -1043,6 +1277,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -1053,19 +1288,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends ReplacedEntity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -1100,6 +1351,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -1110,11 +1362,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends ReplacedEntity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoReplacedEntityRenderer renderer) { super(renderer); @@ -1123,7 +1380,8 @@ public CompileRenderLayers(GeoReplacedEntityRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -1134,6 +1392,7 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/integration/ModMenuIntegration.java b/fabric/src/main/java/mod/azure/azurelib/fabric/integration/ModMenuIntegration.java index 0e27889fe..b59ed48eb 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/integration/ModMenuIntegration.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/integration/ModMenuIntegration.java @@ -2,15 +2,16 @@ import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ModMenuApi; -import mod.azure.azurelib.common.internal.client.AzureLibClient; -import mod.azure.azurelib.common.internal.common.config.ConfigHolder; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; -import mod.azure.azurelib.common.platform.Services; import java.util.HashMap; import java.util.List; import java.util.Map; +import mod.azure.azurelib.common.internal.client.AzureLibClient; +import mod.azure.azurelib.common.internal.common.config.ConfigHolder; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; +import mod.azure.azurelib.common.platform.Services; + public class ModMenuIntegration implements ModMenuApi { @Override diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/AzureLibEventsFabric.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/AzureLibEventsFabric.java index 587c72349..2e2e114f5 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/AzureLibEventsFabric.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/AzureLibEventsFabric.java @@ -1,35 +1,54 @@ package mod.azure.azurelib.fabric.platform; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; + import mod.azure.azurelib.common.api.client.renderer.*; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; import mod.azure.azurelib.common.platform.services.AzureEvents; import mod.azure.azurelib.fabric.event.GeoRenderEvent; -import net.minecraft.client.renderer.MultiBufferSource; public class AzureLibEventsFabric implements AzureEvents { + /** * Fire the {@link GeoRenderEvent.Block.CompileRenderLayers} event */ @Override public void fireCompileBlockRenderLayers(GeoBlockRenderer renderer) { - GeoRenderEvent.Block.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.Block.CompileRenderLayers(renderer)); + GeoRenderEvent.Block.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.Block.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.Block.Pre} event */ @Override - public boolean fireBlockPreRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.Block.Pre.EVENT.invoker().handle(new GeoRenderEvent.Block.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireBlockPreRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.Block.Pre.EVENT.invoker() + .handle(new GeoRenderEvent.Block.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** * Fire the {@link GeoRenderEvent.Block.Post} event */ @Override - public void fireBlockPostRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.Block.Post.EVENT.invoker().handle(new GeoRenderEvent.Block.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireBlockPostRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.Block.Post.EVENT.invoker() + .handle(new GeoRenderEvent.Block.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** @@ -37,23 +56,40 @@ public void fireBlockPostRender(GeoBlockRenderer renderer, PoseStack poseStac */ @Override public void fireCompileArmorRenderLayers(GeoArmorRenderer renderer) { - GeoRenderEvent.Armor.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.Armor.CompileRenderLayers(renderer)); + GeoRenderEvent.Armor.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.Armor.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.Armor.Pre} event */ @Override - public boolean fireArmorPreRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.Armor.Pre.EVENT.invoker().handle(new GeoRenderEvent.Armor.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireArmorPreRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.Armor.Pre.EVENT.invoker() + .handle(new GeoRenderEvent.Armor.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** * Fire the {@link GeoRenderEvent.Armor.Post} event */ @Override - public void fireArmorPostRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.Armor.Post.EVENT.invoker().handle(new GeoRenderEvent.Armor.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireArmorPostRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.Armor.Post.EVENT.invoker() + .handle(new GeoRenderEvent.Armor.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** @@ -61,23 +97,40 @@ public void fireArmorPostRender(GeoArmorRenderer renderer, PoseStack poseStac */ @Override public void fireCompileEntityRenderLayers(GeoEntityRenderer renderer) { - GeoRenderEvent.Entity.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.Entity.CompileRenderLayers(renderer)); + GeoRenderEvent.Entity.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.Entity.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.Entity.Pre} event */ @Override - public boolean fireEntityPreRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.Entity.Pre.EVENT.invoker().handle(new GeoRenderEvent.Entity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireEntityPreRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.Entity.Pre.EVENT.invoker() + .handle(new GeoRenderEvent.Entity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** * Fire the {@link GeoRenderEvent.Entity.Post} event */ @Override - public void fireEntityPostRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.Entity.Post.EVENT.invoker().handle(new GeoRenderEvent.Entity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireEntityPostRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.Entity.Post.EVENT.invoker() + .handle(new GeoRenderEvent.Entity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** @@ -85,23 +138,58 @@ public void fireEntityPostRender(GeoEntityRenderer renderer, PoseStack poseSt */ @Override public void fireCompileReplacedEntityRenderLayers(GeoReplacedEntityRenderer renderer) { - GeoRenderEvent.ReplacedEntity.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.ReplacedEntity.CompileRenderLayers(renderer)); + GeoRenderEvent.ReplacedEntity.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.ReplacedEntity.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.ReplacedEntity.Pre} event */ @Override - public boolean fireReplacedEntityPreRender(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.ReplacedEntity.Pre.EVENT.invoker().handle(new GeoRenderEvent.ReplacedEntity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireReplacedEntityPreRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.ReplacedEntity.Pre.EVENT.invoker() + .handle( + new GeoRenderEvent.ReplacedEntity.Pre( + renderer, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ) + ); } /** * Fire the {@link GeoRenderEvent.ReplacedEntity.Post} event */ @Override - public void fireReplacedEntityPostRender(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.ReplacedEntity.Post.EVENT.invoker().handle(new GeoRenderEvent.ReplacedEntity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireReplacedEntityPostRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.ReplacedEntity.Post.EVENT.invoker() + .handle( + new GeoRenderEvent.ReplacedEntity.Post( + renderer, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ) + ); } /** @@ -109,23 +197,40 @@ public void fireReplacedEntityPostRender(GeoReplacedEntityRenderer rendere */ @Override public void fireCompileItemRenderLayers(GeoItemRenderer renderer) { - GeoRenderEvent.Item.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.Item.CompileRenderLayers(renderer)); + GeoRenderEvent.Item.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.Item.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.Item.Pre} event */ @Override - public boolean fireItemPreRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.Item.Pre.EVENT.invoker().handle(new GeoRenderEvent.Item.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireItemPreRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.Item.Pre.EVENT.invoker() + .handle(new GeoRenderEvent.Item.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** * Fire the {@link GeoRenderEvent.Item.Post} event */ @Override - public void fireItemPostRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.Item.Post.EVENT.invoker().handle(new GeoRenderEvent.Item.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireItemPostRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.Item.Post.EVENT.invoker() + .handle(new GeoRenderEvent.Item.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** @@ -133,22 +238,39 @@ public void fireItemPostRender(GeoItemRenderer renderer, PoseStack poseStack, */ @Override public void fireCompileObjectRenderLayers(GeoObjectRenderer renderer) { - GeoRenderEvent.Object.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.Object.CompileRenderLayers(renderer)); + GeoRenderEvent.Object.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.Object.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.Object.Pre} event */ @Override - public boolean fireObjectPreRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.Object.Pre.EVENT.invoker().handle(new GeoRenderEvent.Object.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireObjectPreRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.Object.Pre.EVENT.invoker() + .handle(new GeoRenderEvent.Object.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** * Fire the {@link GeoRenderEvent.Object.Post} event */ @Override - public void fireObjectPostRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.Object.Post.EVENT.invoker().handle(new GeoRenderEvent.Object.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireObjectPostRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.Object.Post.EVENT.invoker() + .handle(new GeoRenderEvent.Object.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } -} \ No newline at end of file +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibInitializer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibInitializer.java index 70bec4d0d..54e8c3ada 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibInitializer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibInitializer.java @@ -1,8 +1,5 @@ package mod.azure.azurelib.fabric.platform; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.cache.AzureLibCache; -import mod.azure.azurelib.common.platform.services.AzureLibInitializer; import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.minecraft.resources.ResourceLocation; @@ -15,36 +12,40 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.cache.AzureLibCache; +import mod.azure.azurelib.common.platform.services.AzureLibInitializer; + public class FabricAzureLibInitializer implements AzureLibInitializer { @Override public void initialize() { ResourceManagerHelper.get(PackType.CLIENT_RESOURCES) - .registerReloadListener(new IdentifiableResourceReloadListener() { + .registerReloadListener(new IdentifiableResourceReloadListener() { - @Override - public ResourceLocation getFabricId() { - return AzureLib.modResource("models"); - } + @Override + public ResourceLocation getFabricId() { + return AzureLib.modResource("models"); + } - @Override - public @NotNull CompletableFuture reload( - PreparableReloadListener.PreparationBarrier synchronizer, - ResourceManager manager, - ProfilerFiller prepareProfiler, - ProfilerFiller applyProfiler, - Executor prepareExecutor, - Executor applyExecutor - ) { - return AzureLibCache.reload( - synchronizer, - manager, - prepareProfiler, - applyProfiler, - prepareExecutor, - applyExecutor - ); - } - }); + @Override + public @NotNull CompletableFuture reload( + PreparableReloadListener.PreparationBarrier synchronizer, + ResourceManager manager, + ProfilerFiller prepareProfiler, + ProfilerFiller applyProfiler, + Executor prepareExecutor, + Executor applyExecutor + ) { + return AzureLibCache.reload( + synchronizer, + manager, + prepareProfiler, + applyProfiler, + prepareExecutor, + applyExecutor + ); + } + }); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibNetwork.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibNetwork.java index 47c4ca7a5..64f233fd8 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibNetwork.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibNetwork.java @@ -1,9 +1,5 @@ package mod.azure.azurelib.fabric.platform; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; @@ -12,24 +8,35 @@ import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; -import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + public class FabricAzureLibNetwork implements AzureLibNetwork { - public static void registerPacket(CustomPacketPayload.Type

    packetType, StreamCodec codec) { + public static void registerPacket( + CustomPacketPayload.Type

    packetType, + StreamCodec codec + ) { PayloadTypeRegistry.playS2C().register(packetType, (StreamCodec) codec); ClientPlayNetworking.registerGlobalReceiver(packetType, (packet, context) -> packet.handle()); } @Override - public void registerPacketInternal(CustomPacketPayload.Type

    payloadType, StreamCodec codec, boolean isClientBound) { + public void registerPacketInternal( + CustomPacketPayload.Type

    payloadType, + StreamCodec codec, + boolean isClientBound + ) { if (isClientBound) { - if (Services.PLATFORM.isEnvironmentClient()) FabricAzureLibNetwork.registerPacket(payloadType, codec); + if (Services.PLATFORM.isEnvironmentClient()) + FabricAzureLibNetwork.registerPacket(payloadType, codec); } else { PayloadTypeRegistry.playC2S().register(payloadType, (StreamCodec) codec); ServerPlayNetworking.registerGlobalReceiver(payloadType, (packet, context) -> packet.handle()); @@ -42,7 +49,8 @@ public FriendlyByteBuf createFriendlyByteBuf() { @Override public void sendToTrackingEntityAndSelf(AbstractPacket packet, Entity entityToTrack) { - if (entityToTrack instanceof ServerPlayer pl) sendToPlayer(packet, pl); + if (entityToTrack instanceof ServerPlayer pl) + sendToPlayer(packet, pl); for (ServerPlayer player : PlayerLookup.tracking(entityToTrack)) { sendToPlayer(packet, player); diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricCommonRegistry.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricCommonRegistry.java index a131334e7..4121926a6 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricCommonRegistry.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricCommonRegistry.java @@ -1,7 +1,6 @@ package mod.azure.azurelib.fabric.platform; import com.mojang.serialization.MapCodec; -import mod.azure.azurelib.common.platform.services.CommonRegistry; import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -27,22 +26,44 @@ import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.services.CommonRegistry; + public class FabricCommonRegistry implements CommonRegistry { - private static > Supplier registerSupplier(R registry, String modID, String id, Supplier object) { - final T registeredObject = Registry.register((Registry) registry, - ResourceLocation.fromNamespaceAndPath(modID, id), object.get()); + private static > Supplier registerSupplier( + R registry, + String modID, + String id, + Supplier object + ) { + final T registeredObject = Registry.register( + (Registry) registry, + ResourceLocation.fromNamespaceAndPath(modID, id), + object.get() + ); return () -> registeredObject; } - private static > Holder registerHolder(R registry, String modID, String id, Supplier object) { - return Registry.registerForHolder((Registry) registry, ResourceLocation.fromNamespaceAndPath(modID, id), - object.get()); + private static > Holder registerHolder( + R registry, + String modID, + String id, + Supplier object + ) { + return Registry.registerForHolder( + (Registry) registry, + ResourceLocation.fromNamespaceAndPath(modID, id), + object.get() + ); } @Override - public Supplier> registerBlockEntity(String modID, String blockEntityName, Supplier> blockEntityType) { + public Supplier> registerBlockEntity( + String modID, + String blockEntityName, + Supplier> blockEntityType + ) { return registerSupplier(BuiltInRegistries.BLOCK_ENTITY_TYPE, modID, blockEntityName, blockEntityType); } @@ -52,12 +73,20 @@ public Supplier registerBlock(String modID, String blockNam } @Override - public Supplier> registerEntity(String modID, String entityName, Supplier> entity) { + public Supplier> registerEntity( + String modID, + String entityName, + Supplier> entity + ) { return registerSupplier(BuiltInRegistries.ENTITY_TYPE, modID, entityName, entity); } @Override - public Holder registerArmorMaterial(String modID, String matName, Supplier armorMaterial) { + public Holder registerArmorMaterial( + String modID, + String matName, + Supplier armorMaterial + ) { return registerHolder(BuiltInRegistries.ARMOR_MATERIAL, modID, matName, armorMaterial); } @@ -77,7 +106,11 @@ public > Supplier registerScreen(String modID, String s } @Override - public Supplier> registerStructure(String modID, String structureName, MapCodec structure) { + public Supplier> registerStructure( + String modID, + String structureName, + MapCodec structure + ) { return registerSupplier(BuiltInRegistries.STRUCTURE_TYPE, modID, structureName, () -> typeConvert(structure)); } @@ -86,17 +119,29 @@ private static StructureType typeConvert(MapCodec co } @Override - public > Supplier registerParticle(String modID, String particleName, Supplier particle) { + public > Supplier registerParticle( + String modID, + String particleName, + Supplier particle + ) { return registerSupplier(BuiltInRegistries.PARTICLE_TYPE, modID, particleName, particle); } @Override - public Supplier registerCreativeModeTab(String modID, String tabName, Supplier tab) { + public Supplier registerCreativeModeTab( + String modID, + String tabName, + Supplier tab + ) { return registerSupplier(BuiltInRegistries.CREATIVE_MODE_TAB, modID, tabName, tab); } @Override - public Holder registerStatusEffect(String modID, String effectName, Supplier statusEffect) { + public Holder registerStatusEffect( + String modID, + String effectName, + Supplier statusEffect + ) { return registerHolder(BuiltInRegistries.MOB_EFFECT, modID, effectName, statusEffect); } @@ -106,7 +151,12 @@ public Supplier registerFluid(String modID, String fluidNam } @Override - public Supplier makeSpawnEggFor(Supplier> entityType, int primaryEggColour, int secondaryEggColour, Item.Properties itemProperties) { + public Supplier makeSpawnEggFor( + Supplier> entityType, + int primaryEggColour, + int secondaryEggColour, + Item.Properties itemProperties + ) { return () -> new SpawnEggItem(entityType.get(), primaryEggColour, secondaryEggColour, itemProperties); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricPlatformHelper.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricPlatformHelper.java index 69ac973a4..259d21420 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricPlatformHelper.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricPlatformHelper.java @@ -1,22 +1,18 @@ package mod.azure.azurelib.fabric.platform; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; -import mod.azure.azurelib.common.platform.services.IPlatformHelper; -import mod.azure.azurelib.fabric.FabricAzureLibMod; import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponentType; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.level.block.entity.BlockEntityType; import java.nio.file.Path; import java.util.function.Supplier; import java.util.function.UnaryOperator; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.platform.services.IPlatformHelper; + public class FabricPlatformHelper implements IPlatformHelper { @Override @@ -40,9 +36,15 @@ public boolean isServerEnvironment() { } @Override - public Supplier> registerDataComponent(String id, UnaryOperator> builder) { - final DataComponentType componentType = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, - AzureLib.modResource(id).toString(), builder.apply(DataComponentType.builder()).build()); + public Supplier> registerDataComponent( + String id, + UnaryOperator> builder + ) { + final DataComponentType componentType = Registry.register( + BuiltInRegistries.DATA_COMPONENT_TYPE, + AzureLib.modResource(id).toString(), + builder.apply(DataComponentType.builder()).build() + ); return () -> componentType; } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricSBLForked.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricSBLForked.java index 48c57f389..d52ef4000 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricSBLForked.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricSBLForked.java @@ -1,17 +1,11 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.fabric.platform; import com.mojang.serialization.Codec; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.sblforked.SBLLoader; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; @@ -22,6 +16,12 @@ import java.util.Optional; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.sblforked.SBLLoader; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; +import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; +import mod.azure.azurelib.sblforked.registry.SBLSensors; + public class FabricSBLForked implements SBLLoader { public void init(Object eventBus) { @@ -41,7 +41,11 @@ public Supplier> registerMemoryType(String id) { @Override public Supplier> registerMemoryType(String id, Optional> codec) { - MemoryModuleType memoryType = Registry.register(BuiltInRegistries.MEMORY_MODULE_TYPE, ResourceLocation.fromNamespaceAndPath(AzureLib.MOD_ID, id), new MemoryModuleType<>(codec)); + MemoryModuleType memoryType = Registry.register( + BuiltInRegistries.MEMORY_MODULE_TYPE, + ResourceLocation.fromNamespaceAndPath(AzureLib.MOD_ID, id), + new MemoryModuleType<>(codec) + ); return () -> memoryType; } @@ -49,7 +53,10 @@ public Supplier> registerMemoryType(String id, Optional< @Override public > Supplier> registerSensorType(String id, Supplier sensor) { SensorType sensorType = Registry.register( - BuiltInRegistries.SENSOR_TYPE, ResourceLocation.fromNamespaceAndPath(AzureLib.MOD_ID, id), new SensorType<>(sensor)); + BuiltInRegistries.SENSOR_TYPE, + ResourceLocation.fromNamespaceAndPath(AzureLib.MOD_ID, id), + new SensorType<>(sensor) + ); return () -> sensorType; } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/ClientModListener.java b/neo/src/main/java/mod/azure/azurelib/neoforge/ClientModListener.java index 4c17fe9c9..a119a05df 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/ClientModListener.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/ClientModListener.java @@ -1,22 +1,15 @@ package mod.azure.azurelib.neoforge; import com.mojang.blaze3d.platform.InputConstants; -import mod.azure.azurelib.common.api.client.helper.ClientUtils; -import mod.azure.azurelib.common.internal.client.AzureLibClient; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.ConfigHolder; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; import net.minecraft.client.KeyMapping; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.ModContainer; import net.neoforged.fml.ModList; -import net.neoforged.fml.ModLoadingContext; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; import net.neoforged.neoforge.client.gui.IConfigScreenFactory; -import net.neoforged.neoforge.common.NeoForge; import org.lwjgl.glfw.GLFW; import java.util.List; @@ -24,21 +17,38 @@ import java.util.Optional; import java.util.function.Supplier; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.internal.client.AzureLibClient; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.ConfigHolder; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; + @EventBusSubscriber(modid = AzureLib.MOD_ID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public class ClientModListener { @SubscribeEvent public static void registerKeys(final RegisterKeyMappingsEvent event) { if (AzureLib.hasKeyBindsInitialized) { - ClientUtils.RELOAD = new KeyMapping("key.azurelib.reload", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_R, - "category.azurelib.binds"); + ClientUtils.RELOAD = new KeyMapping( + "key.azurelib.reload", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_R, + "category.azurelib.binds" + ); event.register(ClientUtils.RELOAD); - ClientUtils.SCOPE = new KeyMapping("key.azurelib.scope", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_LEFT_ALT, - "category.azurelib.binds"); + ClientUtils.SCOPE = new KeyMapping( + "key.azurelib.scope", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_LEFT_ALT, + "category.azurelib.binds" + ); event.register(ClientUtils.SCOPE); - ClientUtils.FIRE_WEAPON = new KeyMapping("key.azurelib.fire", InputConstants.Type.KEYSYM, - GLFW.GLFW_KEY_UNKNOWN, - "category.azurelib.binds"); + ClientUtils.FIRE_WEAPON = new KeyMapping( + "key.azurelib.fire", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_UNKNOWN, + "category.azurelib.binds" + ); event.register(ClientUtils.FIRE_WEAPON); } } @@ -52,14 +62,16 @@ public static void clientInit(final FMLClientSetupEvent event) { Optional optional = modList.getModContainerById(modId); optional.ifPresent(modContainer -> { List> list = entry.getValue(); - modContainer.registerExtensionPoint(IConfigScreenFactory.class, (Supplier) () -> (container, screen) -> { - if (list.size() == 1) { - return AzureLibClient.getConfigScreen(list.get(0).getConfigId(), screen); + modContainer.registerExtensionPoint( + IConfigScreenFactory.class, + (Supplier) () -> (container, screen) -> { + if (list.size() == 1) { + return AzureLibClient.getConfigScreen(list.get(0).getConfigId(), screen); + } + return AzureLibClient.getConfigScreenByGroup(list, modId, screen); } - return AzureLibClient.getConfigScreenByGroup(list, modId, screen); - }); + ); }); } - } } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java index 27cc9dbdb..684866256 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java @@ -1,36 +1,28 @@ package mod.azure.azurelib.neoforge; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; +import net.neoforged.neoforge.registries.DeferredRegister; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.AzureLibMod; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; import mod.azure.azurelib.common.internal.common.config.AzureLibConfig; import mod.azure.azurelib.common.internal.common.config.format.ConfigFormats; import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; import mod.azure.azurelib.common.internal.common.network.packet.*; -import mod.azure.azurelib.neoforge.platform.NeoForgeAzureLibNetwork; import mod.azure.azurelib.neoforge.platform.NeoForgeCommonRegistry; import mod.azure.azurelib.sblforked.SBLConstants; -import net.minecraft.core.registries.Registries; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.material.PushReaction; -import net.neoforged.bus.api.IEventBus; -import net.neoforged.fml.common.Mod; -import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; -import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; -import net.neoforged.neoforge.network.registration.PayloadRegistrar; -import net.neoforged.neoforge.registries.DeferredRegister; - -import java.util.function.Supplier; @Mod(AzureLib.MOD_ID) public final class NeoForgeAzureLibMod { - public static final DeferredRegister.DataComponents DATA_COMPONENTS_REGISTER = DeferredRegister.createDataComponents( - AzureLib.MOD_ID); + public static final DeferredRegister.DataComponents DATA_COMPONENTS_REGISTER = DeferredRegister + .createDataComponents( + AzureLib.MOD_ID + ); public NeoForgeAzureLibMod(IEventBus modEventBus) { AzureLib.initialize(); @@ -53,10 +45,26 @@ private void init(FMLCommonSetupEvent event) { public void registerMessages(RegisterPayloadHandlersEvent event) { PayloadRegistrar registrar = event.registrar(AzureLib.MOD_ID); - registrar.playBidirectional(BlockEntityAnimTriggerPacket.TYPE, BlockEntityAnimTriggerPacket.CODEC, (msg, ctx) -> msg.handle()); - registrar.playBidirectional(BlockEntityAnimDataSyncPacket.TYPE, BlockEntityAnimDataSyncPacket.CODEC, (msg, ctx) -> msg.handle()); - registrar.playBidirectional(EntityAnimTriggerPacket.TYPE, EntityAnimTriggerPacket.CODEC, (msg, ctx) -> msg.handle()); - registrar.playBidirectional(EntityAnimDataSyncPacket.TYPE, EntityAnimDataSyncPacket.CODEC, (msg, ctx) -> msg.handle()); + registrar.playBidirectional( + BlockEntityAnimTriggerPacket.TYPE, + BlockEntityAnimTriggerPacket.CODEC, + (msg, ctx) -> msg.handle() + ); + registrar.playBidirectional( + BlockEntityAnimDataSyncPacket.TYPE, + BlockEntityAnimDataSyncPacket.CODEC, + (msg, ctx) -> msg.handle() + ); + registrar.playBidirectional( + EntityAnimTriggerPacket.TYPE, + EntityAnimTriggerPacket.CODEC, + (msg, ctx) -> msg.handle() + ); + registrar.playBidirectional( + EntityAnimDataSyncPacket.TYPE, + EntityAnimDataSyncPacket.CODEC, + (msg, ctx) -> msg.handle() + ); registrar.playBidirectional(AnimTriggerPacket.TYPE, AnimTriggerPacket.CODEC, (msg, ctx) -> msg.handle()); registrar.playBidirectional(AnimDataSyncPacket.TYPE, AnimDataSyncPacket.CODEC, (msg, ctx) -> msg.handle()); registrar.playBidirectional(SendConfigDataPacket.TYPE, SendConfigDataPacket.CODEC, (msg, ctx) -> msg.handle()); diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidNavigationElement.java b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidNavigationElement.java index c35b06632..62905e7a1 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidNavigationElement.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidNavigationElement.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under the MIT License. */ package mod.azure.azurelib.neoforge.api.core.navigation; @@ -10,15 +8,17 @@ import net.neoforged.neoforge.fluids.FluidType; /** - * Extracted interface to act as a helper utility for extensible implementations of (Neo)Forge's fluid API overhaul into pathfinding + * Extracted interface to act as a helper utility for extensible implementations of (Neo)Forge's fluid API overhaul into + * pathfinding */ public interface MultiFluidNavigationElement { + /** * Determine whether a given fluidType is one that the given entity can actively navigate through *

    * Note that the provided entity may not necessarily be in the given fluid at the time of this call * - * @param mob The entity to check the pathing capabilities for + * @param mob The entity to check the pathing capabilities for * @param fluidType The FluidType to check */ default boolean canSwimInFluid(Mob mob, FluidType fluidType) { @@ -30,8 +30,8 @@ default boolean canSwimInFluid(Mob mob, FluidType fluidType) { *

    * Note that the provided entity may not necessarily be in the given fluid at the time of this call * - * @param mob The entity to check the pathing capabilities for - * @param fluidType The FluidType to check + * @param mob The entity to check the pathing capabilities for + * @param fluidType The FluidType to check * @param fluidHeight The depth of the given fluid in the block. I.E. the percentage of the block the fluid is deep */ default boolean canSwimInFluid(Mob mob, FluidType fluidType, double fluidHeight) { diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidSmoothGroundNavigation.java b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidSmoothGroundNavigation.java index e8a8474ab..76a66204c 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidSmoothGroundNavigation.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidSmoothGroundNavigation.java @@ -1,13 +1,9 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under the MIT License. */ package mod.azure.azurelib.neoforge.api.core.navigation; -import mod.azure.azurelib.neoforge.api.core.navigation.nodeevaluator.MultiFluidWalkNodeEvaluator; -import mod.azure.azurelib.sblforked.api.core.navigation.SmoothGroundNavigation; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.Mth; @@ -18,14 +14,19 @@ import net.minecraft.world.level.pathfinder.Path; import net.minecraft.world.level.pathfinder.PathFinder; +import mod.azure.azurelib.neoforge.api.core.navigation.nodeevaluator.MultiFluidWalkNodeEvaluator; +import mod.azure.azurelib.sblforked.api.core.navigation.SmoothGroundNavigation; + /** - * An extension of {@link SmoothGroundNavigation} to allow for fluid-agnostic pathfinding based on (Neo)Forge's fluid API overhaul + * An extension of {@link SmoothGroundNavigation} to allow for fluid-agnostic pathfinding based on (Neo)Forge's fluid + * API overhaul *

    * This allows for entities to pathfind in fluids other than water as necessary * * @see MultiFluidNavigationElement */ public class MultiFluidSmoothGroundNavigation extends SmoothGroundNavigation implements MultiFluidNavigationElement { + public MultiFluidSmoothGroundNavigation(Mob mob, Level level) { super(mob, level); } @@ -44,23 +45,32 @@ protected PathFinder createPathFinder(int maxVisitedNodes) { /** * Whether the navigator should consider the entity's current state valid for navigating through a path *

    - * Note that this does not specifically apply to any given path (and the entity's path may even be null at times when this is called) + * Note that this does not specifically apply to any given path (and the entity's path may even be null at times + * when this is called) */ @Override protected boolean canUpdatePath() { - return this.mob.onGround() || this.mob.isInFluidType((fluidType, height) -> canSwimInFluid(this.mob, fluidType, height), true) || this.mob.isPassenger(); + return this.mob.onGround() || this.mob.isInFluidType( + (fluidType, height) -> canSwimInFluid(this.mob, fluidType, height), + true + ) || this.mob.isPassenger(); } /** - * Helper override to allow end-users to modify the fluids an entity can swim in, extensibly patching in (Neo)Forge's fluid API + * Helper override to allow end-users to modify the fluids an entity can swim in, extensibly patching in + * (Neo)Forge's fluid API *

    - * Don't use this method to adjust which fluids are 'swimmable', use {@link MultiFluidNavigationElement#canSwimInFluid} + * Don't use this method to adjust which fluids are 'swimmable', use + * {@link MultiFluidNavigationElement#canSwimInFluid} * * @return The nearest safe surface height for the entity */ @Override public int getSurfaceY() { - if (this.mob.isInFluidType((fluidType, height) -> canSwimInFluid(this.mob, fluidType, height), true) && canFloat()) { + if ( + this.mob.isInFluidType((fluidType, height) -> canSwimInFluid(this.mob, fluidType, height), true) + && canFloat() + ) { final int basePos = this.mob.getBlockY(); BlockPos.MutableBlockPos pos = BlockPos.containing(this.mob.getX(), basePos, this.mob.getZ()).mutable(); BlockState state = this.level.getBlockState(pos); diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/nodeevaluator/MultiFluidWalkNodeEvaluator.java b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/nodeevaluator/MultiFluidWalkNodeEvaluator.java index ebaf7a3cf..94064231a 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/nodeevaluator/MultiFluidWalkNodeEvaluator.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/nodeevaluator/MultiFluidWalkNodeEvaluator.java @@ -1,12 +1,9 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under the MIT License. */ package mod.azure.azurelib.neoforge.api.core.navigation.nodeevaluator; -import mod.azure.azurelib.neoforge.api.core.navigation.MultiFluidNavigationElement; import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; import net.minecraft.world.level.BlockGetter; @@ -18,27 +15,42 @@ import net.minecraft.world.phys.AABB; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.neoforge.api.core.navigation.MultiFluidNavigationElement; + /** - * An extension of {@link WalkNodeEvaluator} to allow for fluid-agnostic pathfinding based on (Neo)Forge's fluid API overhaul + * An extension of {@link WalkNodeEvaluator} to allow for fluid-agnostic pathfinding based on (Neo)Forge's fluid API + * overhaul *

    * This allows for entities to pathfind in fluids other than water as necessary * * @see MultiFluidNavigationElement */ public class MultiFluidWalkNodeEvaluator extends WalkNodeEvaluator implements MultiFluidNavigationElement { + /** * Determine and create a path node for the current starting position based on the surrounding environment */ @Override public @NotNull Node getStart() { int groundY = this.mob.getBlockY(); - final BlockPos.MutableBlockPos testPos = new BlockPos.MutableBlockPos(this.mob.getX(), groundY, this.mob.getZ()); + final BlockPos.MutableBlockPos testPos = new BlockPos.MutableBlockPos( + this.mob.getX(), + groundY, + this.mob.getZ() + ); BlockState groundState = this.currentContext.getBlockState(testPos); if (!this.mob.canStandOnFluid(groundState.getFluidState())) { - if (canFloat() && this.mob.isInFluidType((fluidType, height) -> canSwimInFluid(this.mob, fluidType, height))) { + if ( + canFloat() && this.mob.isInFluidType((fluidType, height) -> canSwimInFluid(this.mob, fluidType, height)) + ) { while (true) { - if (groundState.getFluidState().isEmpty() || !canSwimInFluid(this.mob, groundState.getFluidState().getFluidType())) { + if ( + groundState.getFluidState().isEmpty() || !canSwimInFluid( + this.mob, + groundState.getFluidState().getFluidType() + ) + ) { groundY--; break; @@ -46,11 +58,9 @@ public class MultiFluidWalkNodeEvaluator extends WalkNodeEvaluator implements Mu groundState = this.currentContext.getBlockState(testPos.setY(++groundY)); } - } - else if (this.mob.onGround()) { + } else if (this.mob.onGround()) { groundY = Mth.floor(this.mob.getY() + 0.5d); - } - else { + } else { testPos.setY(Mth.floor(this.mob.getY() + 1)); while (testPos.getY() > this.currentContext.level().getMinBuildHeight()) { @@ -62,8 +72,7 @@ else if (this.mob.onGround()) { break; } } - } - else { + } else { while (this.mob.canStandOnFluid(groundState.getFluidState())) { groundState = this.currentContext.getBlockState(testPos.setY(++groundY)); } @@ -74,10 +83,12 @@ else if (this.mob.onGround()) { if (!canStartAt(testPos.setY(groundY))) { AABB entityBounds = this.mob.getBoundingBox(); - if (canStartAt(testPos.set(entityBounds.minX, groundY, entityBounds.minZ)) + if ( + canStartAt(testPos.set(entityBounds.minX, groundY, entityBounds.minZ)) || canStartAt(testPos.set(entityBounds.minX, groundY, entityBounds.maxZ)) || canStartAt(testPos.set(entityBounds.maxX, groundY, entityBounds.minZ)) - || canStartAt(testPos.set(entityBounds.maxX, groundY, entityBounds.maxZ))) { + || canStartAt(testPos.set(entityBounds.maxX, groundY, entityBounds.maxZ)) + ) { return getStartNode(testPos); } } @@ -93,8 +104,12 @@ protected double getFloorLevel(@NotNull BlockPos pos) { final BlockGetter blockGetter = this.currentContext.level(); FluidState fluidState = blockGetter.getFluidState(pos); - return (canFloat() || isAmphibious()) && canSwimInFluid(this.mob, fluidState.getFluidType(), fluidState.getHeight(blockGetter, pos)) - ? pos.getY() + 0.5d - : getFloorLevel(blockGetter, pos); + return (canFloat() || isAmphibious()) && canSwimInFluid( + this.mob, + fluidState.getFluidType(), + fluidState.getHeight(blockGetter, pos) + ) + ? pos.getY() + 0.5d + : getFloorLevel(blockGetter, pos); } } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/event/GeoRenderEvent.java b/neo/src/main/java/mod/azure/azurelib/neoforge/event/GeoRenderEvent.java index f9c798b19..e5f953ce2 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/event/GeoRenderEvent.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/event/GeoRenderEvent.java @@ -1,20 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.neoforge.event; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.common.api.client.renderer.*; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.item.ItemStack; @@ -23,7 +14,16 @@ import net.neoforged.bus.api.ICancellableEvent; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.api.client.renderer.*; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + public interface GeoRenderEvent { + /** * Returns the renderer for this event * @@ -40,6 +40,7 @@ public interface GeoRenderEvent { * Renderer events for armor pieces being rendered by {@link GeoArmorRenderer} */ abstract class Armor extends Event implements GeoRenderEvent { + private final GeoArmorRenderer renderer; public Armor(GeoArmorRenderer renderer) { @@ -84,16 +85,29 @@ public EquipmentSlot getEquipmentSlot() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the armor piece will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the armor piece will not be rendered and the corresponding {@link Post} event will + * not be fired. */ - public static class Pre extends Armor implements ICancellableEvent { + public static class Pre extends Armor implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -130,13 +144,25 @@ public int getPackedLight() { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Armor { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -173,6 +199,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Armor { + public CompileRenderLayers(GeoArmorRenderer renderer) { super(renderer); } @@ -180,7 +207,8 @@ public CompileRenderLayers(GeoArmorRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -192,6 +220,7 @@ public void addLayer(GeoRenderLayer renderLayer) { * Renderer events for {@link BlockEntity BlockEntities} being rendered by {@link GeoBlockRenderer} */ abstract class Block extends Event implements GeoRenderEvent { + private final GeoBlockRenderer renderer; public Block(GeoBlockRenderer renderer) { @@ -219,16 +248,29 @@ public BlockEntity getBlockEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the block entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the block entity will not be rendered and the corresponding {@link Post} event + * will not be fired. */ - public static class Pre extends Block implements ICancellableEvent { + public static class Pre extends Block implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -265,13 +307,25 @@ public int getPackedLight() { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Block { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -308,6 +362,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Block { + public CompileRenderLayers(GeoBlockRenderer renderer) { super(renderer); } @@ -315,7 +370,8 @@ public CompileRenderLayers(GeoBlockRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -324,9 +380,11 @@ public void addLayer(GeoRenderLayer renderLayer) { } /** - * Renderer events for {@link net.minecraft.world.entity.Entity Entities} being rendered by {@link GeoEntityRenderer}, as well as + * Renderer events for {@link net.minecraft.world.entity.Entity Entities} being rendered by + * {@link GeoEntityRenderer}, as well as */ abstract class Entity extends Event implements GeoRenderEvent { + private final GeoEntityRenderer renderer; public Entity(GeoEntityRenderer renderer) { @@ -354,16 +412,29 @@ public net.minecraft.world.entity.Entity getEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the entity will not be rendered and the corresponding {@link Post} event will not + * be fired. */ - public static class Pre extends Entity implements ICancellableEvent { + public static class Pre extends Entity implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -400,13 +471,25 @@ public int getPackedLight() { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Entity { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -443,6 +526,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Entity { + public CompileRenderLayers(GeoEntityRenderer renderer) { super(renderer); } @@ -450,7 +534,8 @@ public CompileRenderLayers(GeoEntityRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -462,6 +547,7 @@ public void addLayer(GeoRenderLayer renderLayer) { * Renderer events for {@link ItemStack Items} being rendered by {@link GeoItemRenderer} */ abstract class Item extends Event implements GeoRenderEvent { + private final GeoItemRenderer renderer; public Item(GeoItemRenderer renderer) { @@ -489,16 +575,29 @@ public ItemStack getItemStack() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the ItemStack will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the ItemStack will not be rendered and the corresponding {@link Post} event will + * not be fired. */ - public static class Pre extends Item implements ICancellableEvent { + public static class Pre extends Item implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -535,13 +634,25 @@ public int getPackedLight() { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Item { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -578,6 +689,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Item { + public CompileRenderLayers(GeoItemRenderer renderer) { super(renderer); } @@ -585,7 +697,8 @@ public CompileRenderLayers(GeoItemRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -597,6 +710,7 @@ public void addLayer(GeoRenderLayer renderLayer) { * Renderer events for miscellaneous {@link GeoAnimatable animatables} being rendered by {@link GeoObjectRenderer} */ abstract class Object extends Event implements GeoRenderEvent { + private final GeoObjectRenderer renderer; public Object(GeoObjectRenderer renderer) { @@ -617,16 +731,29 @@ public GeoObjectRenderer getRenderer() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the object will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the object will not be rendered and the corresponding {@link Post} event will not + * be fired. */ - public static class Pre extends Object implements ICancellableEvent { + public static class Pre extends Object implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -659,17 +786,29 @@ public int getPackedLight() { /** * Post-render event for miscellaneous animatables being rendered by {@link GeoObjectRenderer} -

    + *

    * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Object { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -706,6 +845,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Object { + public CompileRenderLayers(GeoObjectRenderer renderer) { super(renderer); } @@ -713,7 +853,8 @@ public CompileRenderLayers(GeoObjectRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -722,9 +863,11 @@ public void addLayer(GeoRenderLayer renderLayer) { } /** - * Renderer events for miscellaneous {@link GeoReplacedEntity replaced entities} being rendered by {@link GeoReplacedEntityRenderer} + * Renderer events for miscellaneous {@link GeoReplacedEntity replaced entities} being rendered by + * {@link GeoReplacedEntityRenderer} */ abstract class ReplacedEntity extends Event implements GeoRenderEvent { + private final GeoReplacedEntityRenderer renderer; public ReplacedEntity(GeoReplacedEntityRenderer renderer) { @@ -752,16 +895,29 @@ public net.minecraft.world.entity.Entity getReplacedEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the entity will not be rendered and the corresponding {@link Post} event will not + * be fired. */ public static class Pre extends ReplacedEntity implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -798,13 +954,25 @@ public int getPackedLight() { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends ReplacedEntity { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -841,6 +1009,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends ReplacedEntity { + public CompileRenderLayers(GeoReplacedEntityRenderer renderer) { super(renderer); } @@ -848,11 +1017,12 @@ public CompileRenderLayers(GeoReplacedEntityRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); } } } -} \ No newline at end of file +} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/ClientHooksMixin.java b/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/ClientHooksMixin.java index 710e2e494..71ef1a7d3 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/ClientHooksMixin.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/ClientHooksMixin.java @@ -1,14 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.neoforge.mixins; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.Model; import net.minecraft.world.entity.EquipmentSlot; @@ -20,21 +16,24 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; + @Mixin(ClientHooks.class) public class ClientHooksMixin { @Inject(method = "getArmorModel", at = @At("RETURN"), remap = false, cancellable = true) private static void injectAzureArmors( - LivingEntity entityLiving, - ItemStack itemStack, - EquipmentSlot slot, - HumanoidModel _default, - CallbackInfoReturnable cir + LivingEntity entityLiving, + ItemStack itemStack, + EquipmentSlot slot, + HumanoidModel _default, + CallbackInfoReturnable cir ) { if (itemStack.getItem() instanceof GeoItem) cir.setReturnValue( - RenderProvider.of(itemStack) - .getGenericArmorModel(entityLiving, itemStack, slot, (HumanoidModel) _default) + RenderProvider.of(itemStack) + .getGenericArmorModel(entityLiving, itemStack, slot, (HumanoidModel) _default) ); } } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java b/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java index de0bb193c..aebd6dd60 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.neoforge.mixins; @@ -11,9 +9,6 @@ import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalRef; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.Model; import net.minecraft.client.renderer.MultiBufferSource; @@ -30,35 +25,75 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; + @Mixin(HumanoidArmorLayer.class) public abstract class MixinHumanoidArmorLayer> { @ModifyExpressionValue( - method = "renderArmorPiece(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/EquipmentSlot;ILnet/minecraft/client/model/HumanoidModel;FFFFFF)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/entity/LivingEntity;getItemBySlot(Lnet/minecraft/world/entity/EquipmentSlot;)Lnet/minecraft/world/item/ItemStack;" - ) + method = "renderArmorPiece(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/EquipmentSlot;ILnet/minecraft/client/model/HumanoidModel;FFFFFF)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;getItemBySlot(Lnet/minecraft/world/entity/EquipmentSlot;)Lnet/minecraft/world/item/ItemStack;" + ) ) - private ItemStack azurelib$captureItemBySlot(ItemStack original, @Share("item_by_slot") LocalRef itemBySlotRef) { + private ItemStack azurelib$captureItemBySlot( + ItemStack original, + @Share("item_by_slot") LocalRef itemBySlotRef + ) { itemBySlotRef.set(original); return original; } - @Inject(method = "renderArmorPiece(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/EquipmentSlot;ILnet/minecraft/client/model/HumanoidModel;FFFFFF)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;usesInnerModel(Lnet/minecraft/world/entity/EquipmentSlot;)Z"), cancellable = true) - public void azurelib$renderAzurelibModel(PoseStack poseStack, MultiBufferSource bufferSource, LivingEntity entity, EquipmentSlot equipmentSlot, int packedLight, HumanoidModel baseModel, float limbSwing, float limbSwingAmount, float partialTick, float ageInTicks, float netHeadYaw, float headPitch, CallbackInfo ci, @Share("item_by_slot") LocalRef itemBySlotRef) { + @Inject( + method = "renderArmorPiece(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/EquipmentSlot;ILnet/minecraft/client/model/HumanoidModel;FFFFFF)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;usesInnerModel(Lnet/minecraft/world/entity/EquipmentSlot;)Z" + ), cancellable = true + ) + public void azurelib$renderAzurelibModel( + PoseStack poseStack, + MultiBufferSource bufferSource, + LivingEntity entity, + EquipmentSlot equipmentSlot, + int packedLight, + HumanoidModel baseModel, + float limbSwing, + float limbSwingAmount, + float partialTick, + float ageInTicks, + float netHeadYaw, + float headPitch, + CallbackInfo ci, + @Share("item_by_slot") LocalRef itemBySlotRef + ) { final ItemStack stack = itemBySlotRef.get(); - final Model azurelibModel = RenderProvider.of(stack).getGenericArmorModel(entity, stack, equipmentSlot, - (HumanoidModel) baseModel); + final Model azurelibModel = RenderProvider.of(stack) + .getGenericArmorModel( + entity, + stack, + equipmentSlot, + (HumanoidModel) baseModel + ); if (azurelibModel != null && stack.getItem() instanceof GeoItem) { if (azurelibModel instanceof GeoArmorRenderer geoArmorRenderer) geoArmorRenderer.prepForRender(entity, stack, equipmentSlot, baseModel); baseModel.copyPropertiesTo((A) azurelibModel); - azurelibModel.renderToBuffer(poseStack, null, packedLight, OverlayTexture.NO_OVERLAY, stack.is( - ItemTags.DYEABLE) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(stack, -6265536)) : -1); + azurelibModel.renderToBuffer( + poseStack, + null, + packedLight, + OverlayTexture.NO_OVERLAY, + stack.is( + ItemTags.DYEABLE + ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(stack, -6265536)) : -1 + ); ci.cancel(); } } -} \ No newline at end of file +} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/AzureLibEventsNeoForge.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/AzureLibEventsNeoForge.java index 6d996e468..1d996151d 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/AzureLibEventsNeoForge.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/AzureLibEventsNeoForge.java @@ -1,14 +1,16 @@ package mod.azure.azurelib.neoforge.platform; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; +import net.neoforged.neoforge.common.NeoForge; + import mod.azure.azurelib.common.api.client.renderer.*; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; import mod.azure.azurelib.common.platform.services.AzureEvents; import mod.azure.azurelib.neoforge.event.GeoRenderEvent; -import net.minecraft.client.renderer.MultiBufferSource; -import net.neoforged.neoforge.common.NeoForge; public class AzureLibEventsNeoForge implements AzureEvents { + /** * Fire the {@link GeoRenderEvent.Block.CompileRenderLayers} event */ @@ -21,16 +23,34 @@ public void fireCompileBlockRenderLayers(GeoBlockRenderer renderer) { * Fire the {@link GeoRenderEvent.Block.Pre} event */ @Override - public boolean fireBlockPreRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.Block.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireBlockPreRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Block.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.Block.Post} event */ @Override - public void fireBlockPostRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.Block.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireBlockPostRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Block.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } /** @@ -45,16 +65,34 @@ public void fireCompileArmorRenderLayers(GeoArmorRenderer renderer) { * Fire the {@link GeoRenderEvent.Armor.Pre} event */ @Override - public boolean fireArmorPreRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.Armor.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireArmorPreRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Armor.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.Armor.Post} event */ @Override - public void fireArmorPostRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.Armor.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireArmorPostRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Armor.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } /** @@ -69,16 +107,34 @@ public void fireCompileEntityRenderLayers(GeoEntityRenderer renderer) { * Fire the {@link GeoRenderEvent.Entity.Pre} event */ @Override - public boolean fireEntityPreRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.Entity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireEntityPreRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Entity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.Entity.Post} event */ @Override - public void fireEntityPostRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.Entity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireEntityPostRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Entity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } /** @@ -93,16 +149,34 @@ public void fireCompileReplacedEntityRenderLayers(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.ReplacedEntity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireReplacedEntityPreRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.ReplacedEntity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.ReplacedEntity.Post} event */ @Override - public void fireReplacedEntityPostRender(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.ReplacedEntity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireReplacedEntityPostRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.ReplacedEntity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } /** @@ -117,16 +191,34 @@ public void fireCompileItemRenderLayers(GeoItemRenderer renderer) { * Fire the {@link GeoRenderEvent.Item.Pre} event */ @Override - public boolean fireItemPreRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.Item.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireItemPreRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Item.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.Item.Post} event */ @Override - public void fireItemPostRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.Item.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireItemPostRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Item.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } /** @@ -141,15 +233,33 @@ public void fireCompileObjectRenderLayers(GeoObjectRenderer renderer) { * Fire the {@link GeoRenderEvent.Object.Pre} event */ @Override - public boolean fireObjectPreRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.Object.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireObjectPreRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Object.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.Object.Post} event */ @Override - public void fireObjectPostRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.Object.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireObjectPostRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Object.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibInitializer.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibInitializer.java index 727bef300..96eaeec05 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibInitializer.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibInitializer.java @@ -1,10 +1,11 @@ package mod.azure.azurelib.neoforge.platform; -import mod.azure.azurelib.common.internal.common.cache.AzureLibCache; -import mod.azure.azurelib.common.platform.services.AzureLibInitializer; import net.neoforged.api.distmarker.Dist; import net.neoforged.fml.loading.FMLEnvironment; +import mod.azure.azurelib.common.internal.common.cache.AzureLibCache; +import mod.azure.azurelib.common.platform.services.AzureLibInitializer; + public class NeoForgeAzureLibInitializer implements AzureLibInitializer { @Override diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibNetwork.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibNetwork.java index cf2945537..e4d008e7d 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibNetwork.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibNetwork.java @@ -1,8 +1,5 @@ package mod.azure.azurelib.neoforge.platform; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; @@ -14,18 +11,32 @@ import net.neoforged.neoforge.network.PacketDistributor; import net.neoforged.neoforge.network.registration.PayloadRegistrar; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + public class NeoForgeAzureLibNetwork implements AzureLibNetwork { private static PayloadRegistrar registrar = null; @Override - public void registerPacketInternal(CustomPacketPayload.Type

    payloadType, StreamCodec codec, boolean isClientBound) { + public void registerPacketInternal( + CustomPacketPayload.Type

    payloadType, + StreamCodec codec, + boolean isClientBound + ) { if (isClientBound) { - registrar.playToClient(payloadType, (StreamCodec) codec, - (packet, context) -> packet.handle()); + registrar.playToClient( + payloadType, + (StreamCodec) codec, + (packet, context) -> packet.handle() + ); } else { - registrar.playToServer(payloadType, (StreamCodec) codec, - (packet, context) -> packet.handle()); + registrar.playToServer( + payloadType, + (StreamCodec) codec, + (packet, context) -> packet.handle() + ); } } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeCommonRegistry.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeCommonRegistry.java index 328f4090c..47fbd3697 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeCommonRegistry.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeCommonRegistry.java @@ -1,7 +1,6 @@ package mod.azure.azurelib.neoforge.platform; import com.mojang.serialization.MapCodec; -import mod.azure.azurelib.common.platform.services.CommonRegistry; import net.minecraft.core.Holder; import net.minecraft.core.particles.ParticleType; import net.minecraft.core.registries.Registries; @@ -26,79 +25,111 @@ import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.services.CommonRegistry; + public class NeoForgeCommonRegistry implements CommonRegistry { + public static DeferredRegister> blockEntityTypeDeferredRegister; + public static DeferredRegister blockDeferredRegister; + public static DeferredRegister> entityTypeDeferredRegister; + public static DeferredRegister armorMaterialDeferredRegister; + public static DeferredRegister itemDeferredRegister; + public static DeferredRegister soundEventDeferredRegister; + public static DeferredRegister> menuTypeDeferredRegister; + public static DeferredRegister> structureTypeDeferredRegister; + public static DeferredRegister> particleTypeDeferredRegister; + public static DeferredRegister creativeModeTabDeferredRegister; + public static DeferredRegister statusEffectDeferredRegister; + public static DeferredRegister fluidDeferredRegister; @Override - public Supplier> registerBlockEntity(String modID, String blockEntityName, Supplier> blockEntityType) { - if (modID.isEmpty()) modID = "minecraft"; + public Supplier> registerBlockEntity( + String modID, + String blockEntityName, + Supplier> blockEntityType + ) { + if (modID.isEmpty()) + modID = "minecraft"; blockEntityTypeDeferredRegister = DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, modID); return blockEntityTypeDeferredRegister.register(blockEntityName, blockEntityType); } @Override public Supplier registerBlock(String modID, String blockName, Supplier block) { - if (modID.isEmpty()) modID = "minecraft"; + if (modID.isEmpty()) + modID = "minecraft"; blockDeferredRegister = DeferredRegister.create(Registries.BLOCK, modID); return blockDeferredRegister.register(blockName, block); } @Override - public Supplier> registerEntity(String modID, String entityName, Supplier> entity) { -// if (modID.isEmpty()) modID = "minecraft"; -// entityTypeDeferredRegister = DeferredRegister.create(Registries.ENTITY_TYPE, modID); -// return entityTypeDeferredRegister.register(entityName, entity); + public Supplier> registerEntity( + String modID, + String entityName, + Supplier> entity + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // entityTypeDeferredRegister = DeferredRegister.create(Registries.ENTITY_TYPE, modID); + // return entityTypeDeferredRegister.register(entityName, entity); return null; } @Override - public Holder registerArmorMaterial(String modID, String matName, Supplier armorMaterial) { -// if (modID.isEmpty()) modID = "minecraft"; -// armorMaterialDeferredRegister = DeferredRegister.create(Registries.ARMOR_MATERIAL, modID); -// return (Holder) armorMaterialDeferredRegister.register(matName, armorMaterial); + public Holder registerArmorMaterial( + String modID, + String matName, + Supplier armorMaterial + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // armorMaterialDeferredRegister = DeferredRegister.create(Registries.ARMOR_MATERIAL, modID); + // return (Holder) armorMaterialDeferredRegister.register(matName, armorMaterial); return null; } @Override public Supplier registerItem(String modID, String itemName, Supplier item) { -// if (modID.isEmpty()) modID = "minecraft"; -// itemDeferredRegister = DeferredRegister.create(Registries.ITEM, modID); -// return itemDeferredRegister.register(itemName, item); + // if (modID.isEmpty()) modID = "minecraft"; + // itemDeferredRegister = DeferredRegister.create(Registries.ITEM, modID); + // return itemDeferredRegister.register(itemName, item); return null; } @Override public Supplier registerSound(String modID, String soundName, Supplier sound) { -// if (modID.isEmpty()) modID = "minecraft"; -// soundEventDeferredRegister = DeferredRegister.create(Registries.SOUND_EVENT, modID); -// return soundEventDeferredRegister.register(soundName, sound); + // if (modID.isEmpty()) modID = "minecraft"; + // soundEventDeferredRegister = DeferredRegister.create(Registries.SOUND_EVENT, modID); + // return soundEventDeferredRegister.register(soundName, sound); return null; } @Override public > Supplier registerScreen(String modID, String screenName, Supplier menuType) { -// if (modID.isEmpty()) modID = "minecraft"; -// menuTypeDeferredRegister = DeferredRegister.create(Registries.MENU, modID); -// return menuTypeDeferredRegister.register(screenName, menuType); + // if (modID.isEmpty()) modID = "minecraft"; + // menuTypeDeferredRegister = DeferredRegister.create(Registries.MENU, modID); + // return menuTypeDeferredRegister.register(screenName, menuType); return null; } @Override - public Supplier> registerStructure(String modID, String structureName, MapCodec structure) { -// if (modID.isEmpty()) modID = "minecraft"; -// structureTypeDeferredRegister = DeferredRegister.create(Registries.STRUCTURE_TYPE, modID); -// return structureTypeDeferredRegister.register(structureName, () -> typeConvert(structure)); + public Supplier> registerStructure( + String modID, + String structureName, + MapCodec structure + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // structureTypeDeferredRegister = DeferredRegister.create(Registries.STRUCTURE_TYPE, modID); + // return structureTypeDeferredRegister.register(structureName, () -> typeConvert(structure)); return null; } @@ -107,39 +138,56 @@ private static StructureType typeConvert(MapCodec co } @Override - public > Supplier registerParticle(String modID, String particleName, Supplier particle) { -// if (modID.isEmpty()) modID = "minecraft"; -// particleTypeDeferredRegister = DeferredRegister.create(Registries.PARTICLE_TYPE, modID); -// return particleTypeDeferredRegister.register(particleName, particle); + public > Supplier registerParticle( + String modID, + String particleName, + Supplier particle + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // particleTypeDeferredRegister = DeferredRegister.create(Registries.PARTICLE_TYPE, modID); + // return particleTypeDeferredRegister.register(particleName, particle); return null; } @Override - public Supplier registerCreativeModeTab(String modID, String tabName, Supplier tab) { -// if (modID.isEmpty()) modID = "minecraft"; -// creativeModeTabDeferredRegister = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, modID); -// return creativeModeTabDeferredRegister.register(tabName, tab); + public Supplier registerCreativeModeTab( + String modID, + String tabName, + Supplier tab + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // creativeModeTabDeferredRegister = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, modID); + // return creativeModeTabDeferredRegister.register(tabName, tab); return null; } @Override - public Holder registerStatusEffect(String modID, String effectName, Supplier statusEffect) { -// if (modID.isEmpty()) modID = "minecraft"; -// statusEffectDeferredRegister = DeferredRegister.create(Registries.MOB_EFFECT, modID); -// return (Holder) statusEffectDeferredRegister.register(effectName, statusEffect); + public Holder registerStatusEffect( + String modID, + String effectName, + Supplier statusEffect + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // statusEffectDeferredRegister = DeferredRegister.create(Registries.MOB_EFFECT, modID); + // return (Holder) statusEffectDeferredRegister.register(effectName, statusEffect); return null; } @Override public Supplier registerFluid(String modID, String fluidName, Supplier fluid) { -// if (modID.isEmpty()) modID = "minecraft"; -// fluidDeferredRegister = DeferredRegister.create(Registries.FLUID, modID); -// return fluidDeferredRegister.register(fluidName, fluid); + // if (modID.isEmpty()) modID = "minecraft"; + // fluidDeferredRegister = DeferredRegister.create(Registries.FLUID, modID); + // return fluidDeferredRegister.register(fluidName, fluid); return null; } @Override - public Supplier makeSpawnEggFor(Supplier> entityType, int primaryEggColour, int secondaryEggColour, Item.Properties itemProperties) { + public Supplier makeSpawnEggFor( + Supplier> entityType, + int primaryEggColour, + int secondaryEggColour, + Item.Properties itemProperties + ) { return () -> new DeferredSpawnEggItem(entityType, primaryEggColour, secondaryEggColour, itemProperties); } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgePlatformHelper.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgePlatformHelper.java index b14a412d6..adcbc913c 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgePlatformHelper.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgePlatformHelper.java @@ -1,11 +1,6 @@ package mod.azure.azurelib.neoforge.platform; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; -import mod.azure.azurelib.common.platform.services.IPlatformHelper; -import mod.azure.azurelib.neoforge.NeoForgeAzureLibMod; import net.minecraft.core.component.DataComponentType; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.neoforged.fml.loading.FMLEnvironment; import net.neoforged.fml.loading.FMLLoader; @@ -13,6 +8,9 @@ import java.util.function.Supplier; import java.util.function.UnaryOperator; +import mod.azure.azurelib.common.platform.services.IPlatformHelper; +import mod.azure.azurelib.neoforge.NeoForgeAzureLibMod; + public class NeoForgePlatformHelper implements IPlatformHelper { @Override @@ -36,7 +34,10 @@ public boolean isServerEnvironment() { } @Override - public Supplier> registerDataComponent(String id, UnaryOperator> builder) { + public Supplier> registerDataComponent( + String id, + UnaryOperator> builder + ) { return NeoForgeAzureLibMod.DATA_COMPONENTS_REGISTER.registerComponentType(id, builder); } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeSBLForked.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeSBLForked.java index 1eeb07718..43ab23265 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeSBLForked.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeSBLForked.java @@ -1,17 +1,11 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.neoforge.platform; import com.mojang.serialization.Codec; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.sblforked.SBLLoader; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; import net.minecraft.core.registries.Registries; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.ai.memory.MemoryModuleType; @@ -23,13 +17,31 @@ import java.util.Optional; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.sblforked.SBLLoader; +import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; +import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; +import mod.azure.azurelib.sblforked.registry.SBLSensors; + public class NeoForgeSBLForked implements SBLLoader { - public static final DeferredRegister> MEMORY_TYPES = DeferredRegister.create(Registries.MEMORY_MODULE_TYPE, AzureLib.MOD_ID); - public static final DeferredRegister> SENSORS = DeferredRegister.create(Registries.SENSOR_TYPE, AzureLib.MOD_ID); - public static final DeferredRegister> ENTITY_TYPES = DeferredRegister.create(Registries.ENTITY_TYPE, AzureLib.MOD_ID); + + public static final DeferredRegister> MEMORY_TYPES = DeferredRegister.create( + Registries.MEMORY_MODULE_TYPE, + AzureLib.MOD_ID + ); + + public static final DeferredRegister> SENSORS = DeferredRegister.create( + Registries.SENSOR_TYPE, + AzureLib.MOD_ID + ); + + public static final DeferredRegister> ENTITY_TYPES = DeferredRegister.create( + Registries.ENTITY_TYPE, + AzureLib.MOD_ID + ); public void init(Object eventBus) { - final IEventBus modEventBus = (IEventBus)eventBus; + final IEventBus modEventBus = (IEventBus) eventBus; MEMORY_TYPES.register(modEventBus); SENSORS.register(modEventBus); From 279216635bf63b156e2ebb66a8c4f5a7e8808a03 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:29:41 -0500 Subject: [PATCH 022/224] 3.0.0-alpha1 --- changelog.md | 10 +++++++--- gradle.properties | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 55f6d406c..bbd9babd3 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,8 @@ -v2.3.27 +v3.0.0 -- Remove format version check, unneeded -- Add GeoItemRender#useNewOffset() which will remove the y offset on item displays, due to change in BlockBench 4.11 item displays \ No newline at end of file +- Rewrite Entity animation system. + - No longer have to supply a cache. + - Render pipeline completely rewritten. + - MORE WIP +- Move to new Az Naming scheme from Geo +- MORE WIP \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 8c640c6b2..82dcd4448 100644 --- a/gradle.properties +++ b/gradle.properties @@ -51,5 +51,5 @@ mod_logo = azurelib.png mod_name = AzureLib mod_sources = https://github.com/AzureDoom/AzureLib mod_url = https://modrinth.com/mod/azurelib -version = 2.3.27 +version = 3.0.0-alpha1 modrinth_id = 7zlUOZvb From de60bcd137f7bbe3e5c1ef143fba170d0aae8338 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Wed, 11 Dec 2024 16:25:01 -0500 Subject: [PATCH 023/224] Cleaned up az animation accessing. Signed-off-by: = --- .../EntityMixin_AzEntityAnimatorCache.java | 2 +- .../animation/AzAnimationDispatcher.java | 18 ++++------------ .../core2/animation/AzAnimatorAccessor.java | 21 ++++++++++++++++++- .../core2/render/entity/AzEntityRenderer.java | 8 +++---- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java index b0bc24077..c060df5b8 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java @@ -21,7 +21,7 @@ public void setAnimator(@Nullable AzAnimator animator) { } @Override - public @Nullable AzAnimator getAnimator() { + public @Nullable AzAnimator getAnimatorOrNull() { return animator; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java index 4a450c9f1..fb23ea1cf 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java @@ -5,7 +5,6 @@ import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimTriggerPacket; import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; public class AzAnimationDispatcher { @@ -17,19 +16,10 @@ public AzAnimationDispatcher(T entity) { public void dispatch(@Nullable String controllerName, String animationName) { if (entity.level().isClientSide()) { - @SuppressWarnings("unchecked") - var entityAnimatorCache = (AzAnimatorAccessor) entity; - var cachedEntityAnimator = (AzEntityAnimator) entityAnimatorCache.getAnimator(); - - if (cachedEntityAnimator == null) { - return; - } - - var controller = cachedEntityAnimator.getAnimationControllerContainer().getOrNull(controllerName); - - if (controller != null) { - controller.tryTriggerAnimation(animationName); - } + AzAnimatorAccessor.get(entity) + .map(AzAnimator::getAnimationControllerContainer) + .map(container -> container.getOrNull(controllerName)) + .ifPresent(controller -> controller.tryTriggerAnimation(animationName)); } else { var entityId = entity.getId(); var entityAnimTriggerPacket = new EntityAnimTriggerPacket( diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java index e09894262..5644403df 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java @@ -2,10 +2,29 @@ import org.jetbrains.annotations.Nullable; +import java.util.Optional; + public interface AzAnimatorAccessor { @Nullable - AzAnimator getAnimator(); + AzAnimator getAnimatorOrNull(); void setAnimator(AzAnimator animator); + + default Optional> getAnimator() { + return Optional.ofNullable(getAnimatorOrNull()); + } + + @SuppressWarnings("unchecked") + static AzAnimatorAccessor cast(T target) { + return (AzAnimatorAccessor) target; + } + + static AzAnimator getOrNull(T target) { + return cast(target).getAnimatorOrNull(); + } + + static Optional> get(T target) { + return Optional.ofNullable(getOrNull(target)); + } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index f4d52b26b..76893b7fa 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -101,9 +101,8 @@ public void render( protected @Nullable AzEntityAnimator provideAnimator(T entity) { // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for the // entity. - @SuppressWarnings("unchecked") - var entityAnimatorCache = (AzAnimatorAccessor) entity; - var cachedEntityAnimator = (AzEntityAnimator) entityAnimatorCache.getAnimator(); + var accessor = AzAnimatorAccessor.cast(entity); + var cachedEntityAnimator = (AzEntityAnimator) accessor.getAnimatorOrNull(); if (cachedEntityAnimator == null) { // If the cached animator is null, create a new one. We use a separate reference here just for some @@ -113,9 +112,10 @@ public void render( // If the new animator we created is not null, then register its controllers. cachedEntityAnimator.registerControllers(cachedEntityAnimator.getAnimationControllerContainer()); // Also cache the animator so that the next time we fetch the animator, it's ready for us. - entityAnimatorCache.setAnimator(cachedEntityAnimator); + accessor.setAnimator(cachedEntityAnimator); } } + return cachedEntityAnimator; } From 0587c175ce2cdceb03764edbe441d178399b3771 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Wed, 11 Dec 2024 16:25:48 -0500 Subject: [PATCH 024/224] Fixed improper packet being sent for az animation dispatching. Signed-off-by: = --- .../packet/AzEntityAnimTriggerPacket.java | 61 +++++++++++++++++++ .../platform/services/AzureLibNetwork.java | 2 + .../animation/AzAnimationDispatcher.java | 5 +- 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityAnimTriggerPacket.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityAnimTriggerPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityAnimTriggerPacket.java new file mode 100644 index 000000000..9720ff294 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityAnimTriggerPacket.java @@ -0,0 +1,61 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.common.internal.common.network.packet; + +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.NotNull; + +/** + * Packet for syncing user-definable animations that can be triggered from the server for + * {@link Entity Entities} + */ +public record AzEntityAnimTriggerPacket( + int entityId, + String controllerName, + String animName +) implements AbstractPacket { + + public static final Type TYPE = new Type<>( + AzureLibNetwork.AZ_ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID + ); + + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, + AzEntityAnimTriggerPacket::entityId, + ByteBufCodecs.STRING_UTF8, + AzEntityAnimTriggerPacket::controllerName, + ByteBufCodecs.STRING_UTF8, + AzEntityAnimTriggerPacket::animName, + AzEntityAnimTriggerPacket::new + ); + + public void handle() { + var entity = ClientUtils.getLevel().getEntity(this.entityId); + + if (entity == null) { + return; + } + + AzAnimatorAccessor.get(entity) + .map(AzAnimator::getAnimationControllerContainer) + .map(container -> container.getOrNull(controllerName)) + .ifPresent(controller -> controller.tryTriggerAnimation(animName)); + } + + @Override + public @NotNull Type type() { + return TYPE; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java index 033f891f8..35cabb8d3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java @@ -24,6 +24,8 @@ public interface AzureLibNetwork { ResourceLocation ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("anim_trigger_sync"); + ResourceLocation AZ_ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("az_entity_anim_trigger_sync"); + ResourceLocation ENTITY_ANIM_DATA_SYNC_PACKET_ID = AzureLib.modResource("entity_anim_data_sync"); ResourceLocation ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("entity_anim_trigger_sync"); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java index fb23ea1cf..72adaf70d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java @@ -1,9 +1,9 @@ package mod.azure.azurelib.core2.animation; +import mod.azure.azurelib.common.internal.common.network.packet.AzEntityAnimTriggerPacket; import net.minecraft.world.entity.Entity; import org.jetbrains.annotations.Nullable; -import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimTriggerPacket; import mod.azure.azurelib.common.platform.Services; public class AzAnimationDispatcher { @@ -22,9 +22,8 @@ public void dispatch(@Nullable String controllerName, String animationName) { .ifPresent(controller -> controller.tryTriggerAnimation(animationName)); } else { var entityId = entity.getId(); - var entityAnimTriggerPacket = new EntityAnimTriggerPacket( + var entityAnimTriggerPacket = new AzEntityAnimTriggerPacket( entityId, - false, controllerName, animationName ); From 80621ac61d1bcd5cd7cbb0c8340e8a620457616d Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Wed, 11 Dec 2024 16:36:11 -0500 Subject: [PATCH 025/224] Split AzAnimationDispatcher#dispatch into dispatchFromClient and dispatchFromServer. Signed-off-by: = --- .../packet/AzEntityAnimTriggerPacket.java | 16 ++++---- .../animation/AzAnimationDispatcher.java | 39 +++++++++++++------ .../azurelib/fabric/core2/example/Drone.java | 2 +- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityAnimTriggerPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityAnimTriggerPacket.java index 9720ff294..95630fa38 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityAnimTriggerPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityAnimTriggerPacket.java @@ -5,11 +5,6 @@ */ package mod.azure.azurelib.common.internal.common.network.packet; -import mod.azure.azurelib.common.api.client.helper.ClientUtils; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; -import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; @@ -17,9 +12,14 @@ import net.minecraft.world.entity.Entity; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; + /** - * Packet for syncing user-definable animations that can be triggered from the server for - * {@link Entity Entities} + * Packet for syncing user-definable animations that can be triggered from the server for {@link Entity Entities} */ public record AzEntityAnimTriggerPacket( int entityId, @@ -50,7 +50,7 @@ public void handle() { AzAnimatorAccessor.get(entity) .map(AzAnimator::getAnimationControllerContainer) - .map(container -> container.getOrNull(controllerName)) + .map(controllerContainer -> controllerContainer.getOrNull(controllerName)) .ifPresent(controller -> controller.tryTriggerAnimation(animName)); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java index 72adaf70d..150e8aa28 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java @@ -1,9 +1,10 @@ package mod.azure.azurelib.core2.animation; -import mod.azure.azurelib.common.internal.common.network.packet.AzEntityAnimTriggerPacket; import net.minecraft.world.entity.Entity; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.network.packet.AzEntityAnimTriggerPacket; import mod.azure.azurelib.common.platform.Services; public class AzAnimationDispatcher { @@ -14,20 +15,34 @@ public AzAnimationDispatcher(T entity) { this.entity = entity; } - public void dispatch(@Nullable String controllerName, String animationName) { - if (entity.level().isClientSide()) { - AzAnimatorAccessor.get(entity) - .map(AzAnimator::getAnimationControllerContainer) - .map(container -> container.getOrNull(controllerName)) - .ifPresent(controller -> controller.tryTriggerAnimation(animationName)); - } else { - var entityId = entity.getId(); - var entityAnimTriggerPacket = new AzEntityAnimTriggerPacket( - entityId, + public void dispatchFromClient(@Nullable String controllerName, String animationName) { + if (!entity.level().isClientSide) { + AzureLib.LOGGER.warn( + "Attempted client-side animation dispatch from server side. Animation will not play! Controller: {}, Animation: {}", + controllerName, + animationName + ); + return; + } + + AzAnimatorAccessor.get(entity) + .map(AzAnimator::getAnimationControllerContainer) + .map(controllerContainer -> controllerContainer.getOrNull(controllerName)) + .ifPresent(controller -> controller.tryTriggerAnimation(animationName)); + } + + public void dispatchFromServer(@Nullable String controllerName, String animationName) { + if (entity.level().isClientSide) { + AzureLib.LOGGER.warn( + "Attempted server-side animation dispatch from client side. Controller: {}, Animation: {}", controllerName, animationName ); - Services.NETWORK.sendToTrackingEntityAndSelf(entityAnimTriggerPacket, entity); + return; } + + var entityId = entity.getId(); + var packet = new AzEntityAnimTriggerPacket(entityId, controllerName, animationName); + Services.NETWORK.sendToTrackingEntityAndSelf(packet, entity); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java index 7654a40c0..5baf980b7 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java @@ -19,7 +19,7 @@ public void tick() { super.tick(); if (this.level().isClientSide) { - animationDispatcher.dispatch("base_controller", "animation.idle"); + animationDispatcher.dispatchFromClient("base_controller", "animation.idle"); } } } From d07f818aef66b64b6efcc3c2ad29e54c795cb469 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Wed, 11 Dec 2024 16:59:09 -0500 Subject: [PATCH 026/224] Added more deprecations. Signed-off-by: = --- .../api/client/renderer/GeoReplacedEntityRenderer.java | 3 +++ .../common/api/common/animatable/GeoBlockEntity.java | 2 ++ .../azurelib/common/api/common/animatable/GeoEntity.java | 2 ++ .../azurelib/common/api/common/animatable/GeoItem.java | 2 ++ .../common/api/common/animatable/GeoReplacedEntity.java | 3 +++ .../azurelib/common/internal/client/RenderProvider.java | 3 +++ .../common/internal/common/cache/AnimatableIdCache.java | 3 +++ .../common/internal/common/cache/AzureLibCache.java | 6 +++--- .../common/internal/common/cache/object/BakedGeoModel.java | 3 ++- .../common/internal/common/cache/object/GeoBone.java | 3 +++ .../common/internal/common/cache/object/GeoCube.java | 2 ++ .../common/internal/common/cache/object/GeoQuad.java | 2 ++ .../common/internal/common/cache/object/GeoVertex.java | 1 + .../internal/common/cache/texture/AnimatableTexture.java | 2 ++ .../internal/common/cache/texture/AutoGlowingTexture.java | 2 ++ .../internal/common/cache/texture/GeoAbstractTexture.java | 2 ++ .../common/cache/texture/GeoGlowingTextureMeta.java | 2 ++ .../common/internal/common/constant/DataTickets.java | 3 +++ .../common/internal/common/constant/DefaultAnimations.java | 3 +++ .../internal/common/network/SerializableDataTicket.java | 3 +++ .../internal/common/network/packet/AnimDataSyncPacket.java | 3 +++ .../internal/common/network/packet/AnimTriggerPacket.java | 2 ++ .../network/packet/BlockEntityAnimDataSyncPacket.java | 3 +++ .../common/network/packet/BlockEntityAnimTriggerPacket.java | 2 ++ .../common/network/packet/EntityAnimDataSyncPacket.java | 3 +++ .../common/network/packet/EntityAnimTriggerPacket.java | 2 ++ .../common/internal/mixins/MixinHumanoidArmorLayer.java | 4 ++++ .../azurelib/common/internal/mixins/MixinItemRenderer.java | 3 +++ .../common/internal/mixins/TextureManagerMixin.java | 4 ++++ .../mod/azure/azurelib/core/animatable/GeoAnimatable.java | 1 + .../core/animatable/instance/AnimatableInstanceCache.java | 1 + .../instance/InstancedAnimatableInstanceCache.java | 1 + .../instance/SingletonAnimatableInstanceCache.java | 1 + .../azurelib/core/animatable/model/CoreBakedGeoModel.java | 2 +- .../azure/azurelib/core/animation/AnimatableManager.java | 1 + .../java/mod/azure/azurelib/core/animation/Animation.java | 1 + .../azure/azurelib/core/animation/AnimationController.java | 1 + .../azure/azurelib/core/animation/AnimationProcessor.java | 1 + .../mod/azure/azurelib/core/animation/AnimationState.java | 1 + .../core/animation/ContextAwareAnimatableManager.java | 1 + .../mod/azure/azurelib/core/animation/RawAnimation.java | 3 ++- .../core/keyframe/event/CustomInstructionKeyframeEvent.java | 3 ++- .../azure/azurelib/core/keyframe/event/KeyFrameEvent.java | 3 ++- .../azurelib/core/keyframe/event/ParticleKeyframeEvent.java | 3 ++- .../azurelib/core/keyframe/event/SoundKeyframeEvent.java | 3 ++- .../java/mod/azure/azurelib/core/object/DataTicket.java | 3 +++ .../mod/azure/azurelib/fabric/event/GeoRenderEvent.java | 3 +++ 47 files changed, 101 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java index 8b8f4862a..8ccc0e5e7 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java @@ -50,7 +50,10 @@ /** * An alternate to {@link GeoEntityRenderer}, used specifically for replacing existing non-AzureLib entities with * AzureLib rendering dynamically, without the need for an additional entity class + * + * @deprecated */ +@Deprecated(forRemoval = true) public class GeoReplacedEntityRenderer extends EntityRenderer implements GeoRenderer { protected final GeoModel model; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java index e47c06966..b754f09a2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java @@ -23,6 +23,8 @@ /** * The {@link GeoAnimatable} interface specific to {@link BlockEntity BlockEntities} + * + * @deprecated */ public interface GeoBlockEntity extends GeoAnimatable { diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java index b3d2330b5..b2c393978 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java @@ -23,6 +23,8 @@ * to Projectiles and other Entity subclasses.
    * NOTE: This cannot be used for entities using the {@link GeoReplacedEntityRenderer} as you aren't * extending {@code Entity}. Use {@link GeoReplacedEntity} instead. + * + * @deprecated */ public interface GeoEntity extends GeoAnimatable { diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java index 0383be6ec..0bd150817 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java @@ -33,6 +33,8 @@ /** * The {@link GeoAnimatable GeoAnimatable} interface specific to {@link net.minecraft.world.item.Item Items}. This also * applies to armor, as they are just items too. + * + * @deprecated */ public interface GeoItem extends SingletonGeoAnimatable { diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java index eb601e5ac..beb5b5436 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java @@ -25,7 +25,10 @@ /** * The {@link GeoAnimatable} interface specific to {@link Entity Entities}. This interface is specifically for * entities replacing the rendering of other, existing entities. + * + * @deprecated */ +@Deprecated(forRemoval = true) public interface GeoReplacedEntity extends SingletonGeoAnimatable { /** diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java index 5ff882093..607605054 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java @@ -19,7 +19,10 @@ /** * Internal interface for safely providing a custom renderer instances at runtime.
    * This can be safely instantiated as a new anonymous class inside your {@link Item} class + * + * @deprecated */ +@Deprecated(forRemoval = true) public interface RenderProvider { RenderProvider DEFAULT = new RenderProvider() {}; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java index ca6a6066a..42d6f859c 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java @@ -17,7 +17,10 @@ * Storage class that keeps track of the last animatable id used, and provides new ones on request.
    * Generally only used for {@link net.minecraft.world.item.Item Items}, but any {@link SingletonAnimatableInstanceCache * singleton} will likely use this. + * + * @deprecated */ +@Deprecated(forRemoval = true) public final class AnimatableIdCache extends SavedData { private static final String DATA_KEY = "AzureLib_id_cache"; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java index 8182ac74d..c1e2afb6d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java @@ -40,7 +40,7 @@ /** * Cache class for holding loaded {@link Animation Animations} and {@link CoreGeoModel Models} * - * @deprecated Use {@link mod.azure.azurelib.core2.model.cache.AzBakedModelCache AzBakedModelCache}, instead. + * @deprecated Use {@link AzBakedModelCache} and {@link AzBakedAnimationCache} instead. */ public final class AzureLibCache { @@ -72,7 +72,7 @@ private AzureLibCache() { } /** - * @deprecated + * @deprecated Use {@link AzBakedAnimationCache} instead. */ public static Map getBakedAnimations() { if (!AzureLib.hasInitialized) @@ -82,7 +82,7 @@ public static Map getBakedAnimations() { } /** - * @deprecated + * @deprecated Use {@link AzBakedModelCache} instead. */ public static Map getBakedModels() { if (!AzureLib.hasInitialized) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java index 0e29386f1..ee411567d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java @@ -16,8 +16,9 @@ /** * Baked model object for AzureLib models. * - * @deprecated + * @deprecated Use {@link mod.azure.azurelib.core2.model.AzBakedModel} instead. */ +@Deprecated(forRemoval = true) public class BakedGeoModel implements CoreBakedGeoModel { public final Map bonesByName; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java index 47f4f07cd..a2fde7602 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java @@ -21,7 +21,10 @@ /** * Mutable bone object representing a set of cubes, as well as child bones.
    * This is the object that is directly modified by animations to handle movement + * + * @deprecated Use {@link mod.azure.azurelib.core2.model.AzBone} instead. */ +@Deprecated(forRemoval = true) public class GeoBone implements CoreGeoBone { private final GeoBone parent; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java index 2ca7c7663..4a0922d3a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java @@ -9,6 +9,8 @@ /** * Baked cuboid for a {@link GeoBone} + * + * @deprecated */ public record GeoCube( GeoQuad[] quads, diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java index b49294489..2a432f4b3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java @@ -10,6 +10,8 @@ /** * Quad data holder + * + * @deprecated */ public record GeoQuad( GeoVertex[] vertices, diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java index 627f369ec..44ba7d642 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java @@ -13,6 +13,7 @@ * @param position The position of the vertex * @param texU The texture U coordinate * @param texV The texture V coordinate + * @deprecated */ public record GeoVertex( Vector3f position, diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java index 9c636f4a3..cac61bd80 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java @@ -31,6 +31,8 @@ /** * Wrapper for {@link SimpleTexture SimpleTexture} implementation allowing for casual use of animated non-atlas textures + * + * @deprecated */ public class AnimatableTexture extends SimpleTexture { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java index 6d213ad25..2ce2b551d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java @@ -34,6 +34,8 @@ /** * Texture object type responsible for AzureLib's emissive render textures + * + * @deprecated */ public class AutoGlowingTexture extends GeoAbstractTexture { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java index 1503f717b..e0dfb617e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java @@ -26,6 +26,8 @@ /** * Abstract texture wrapper for AzureLib textures.
    * Mostly just handles boilerplate + * + * @deprecated */ public abstract class GeoAbstractTexture extends AbstractTexture { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java index 103b0ac00..99c633be9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java @@ -23,6 +23,8 @@ /** * Metadata class that stores the data for AzureLib's {@link AutoGlowingGeoLayer emissive texture feature} for a given * texture + * + * @deprecated */ public class GeoGlowingTextureMeta { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java index a5e615949..bfd6046c2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java @@ -25,7 +25,10 @@ /** * Stores the default (builtin) {@link DataTicket DataTickets} used in AzureLib.
    * Additionally handles registration of {@link SerializableDataTicket SerializableDataTickets} + * + * @deprecated */ +@Deprecated(forRemoval = true) public final class DataTickets { // Builtin tickets diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java index 1c7ef1c47..8e71ead4b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java @@ -25,7 +25,10 @@ * Optionally usable class that holds constants for recommended animation paths.
    * Using these won't affect much, but it may help keep some consistency in animation namings.
    * Additionally, it encourages use of cached {@link RawAnimation RawAnimations}, to reduce overheads. + * + * @deprecated */ +@Deprecated(forRemoval = true) public record DefaultAnimations() { public static final RawAnimation ITEM_ON_USE = RawAnimation.begin().thenPlay("item.use"); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java index 6952e0c03..b60e857f1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java @@ -16,7 +16,10 @@ /** * Network-compatible {@link DataTicket} implementation. Used for sending data from server -> client in an easy manner + * + * @deprecated */ +@Deprecated(forRemoval = true) public abstract class SerializableDataTicket extends DataTicket { public static final StreamCodec> STREAM_CODEC = StreamCodec diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java index c991aa3fa..debffe187 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java @@ -19,7 +19,10 @@ /** * Packet for syncing user-definable animation data for {@link SingletonGeoAnimatable} instances + * + * @deprecated */ +@Deprecated(forRemoval = true) public record AnimDataSyncPacket( String syncableId, long instanceId, diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java index 07ed0b95f..9f4edbf42 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java @@ -18,6 +18,8 @@ /** * Packet for syncing user-definable animations that can be triggered from the server + * + * @deprecated */ public record AnimTriggerPacket( String syncableId, diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java index c89a11c36..f61bc9ef9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java @@ -20,7 +20,10 @@ /** * Packet for syncing user-definable animation data for {@link BlockEntity BlockEntities} + * + * @deprecated */ +@Deprecated(forRemoval = true) public record BlockEntityAnimDataSyncPacket( BlockPos blockPos, SerializableDataTicket dataTicket, diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java index 0643f2cfe..1df11dcd2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java @@ -22,6 +22,8 @@ /** * Packet for syncing user-definable animations that can be triggered from the server for * {@link net.minecraft.world.level.block.entity.BlockEntity BlockEntities} + * + * @deprecated */ public record BlockEntityAnimTriggerPacket( BlockPos blockPos, diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java index 8dfe07ef8..bf9f62f2b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java @@ -21,7 +21,10 @@ /** * Packet for syncing user-definable animation data for {@link net.minecraft.world.entity.Entity Entities} + * + * @deprecated */ +@Deprecated(forRemoval = true) public record EntityAnimDataSyncPacket( int entityId, boolean isReplacedEntity, diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java index 344237cd9..841ec1a70 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java @@ -22,6 +22,8 @@ /** * Packet for syncing user-definable animations that can be triggered from the server for * {@link net.minecraft.world.entity.Entity Entities} + * + * @deprecated Use {@link AzEntityAnimTriggerPacket} instead. */ public record EntityAnimTriggerPacket( int entityId, diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java index f061a9ece..010718698 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java @@ -29,7 +29,11 @@ import mod.azure.azurelib.common.api.common.animatable.GeoItem; import mod.azure.azurelib.common.internal.client.RenderProvider; +/** + * @deprecated + */ @Mixin(HumanoidArmorLayer.class) +@Deprecated(forRemoval = true) public abstract class MixinHumanoidArmorLayer> { @ModifyExpressionValue( diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java index d132a132a..c3b64ba3a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java @@ -21,8 +21,11 @@ /** * Render hook to inject AzureLib's ISTER rendering callback + * + * @deprecated */ @Mixin(ItemRenderer.class) +@Deprecated(forRemoval = true) public class MixinItemRenderer { @Inject( diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java index dfe740c71..1e2816d35 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java @@ -19,7 +19,11 @@ import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +/** + * @deprecated + */ @Mixin(TextureManager.class) +@Deprecated(forRemoval = true) public abstract class TextureManagerMixin { @Shadow diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java b/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java index 09679873d..4b07b9526 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java @@ -25,6 +25,7 @@ * * @deprecated */ +@Deprecated(forRemoval = true) public interface GeoAnimatable { /** diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java index 3bf1a0fb1..7cf873c3d 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java @@ -24,6 +24,7 @@ * * @deprecated */ +@Deprecated(forRemoval = true) public abstract class AnimatableInstanceCache { protected final GeoAnimatable animatable; diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java index 011f1ddf4..8f227ca6a 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java @@ -14,6 +14,7 @@ * * @deprecated */ +@Deprecated(forRemoval = true) public class InstancedAnimatableInstanceCache extends AnimatableInstanceCache { protected AnimatableManager manager; diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java index 4c1c16e5d..9fbf88998 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java @@ -17,6 +17,7 @@ * * @deprecated */ +@Deprecated(forRemoval = true) public class SingletonAnimatableInstanceCache extends AnimatableInstanceCache { protected final Long2ObjectMap> managers = new Long2ObjectOpenHashMap<>(); diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java index 72bd6139a..e97aa9a07 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java @@ -12,7 +12,7 @@ * Baked model object for AzureLib models.
    * Mostly an internal placeholder to allow for splitting up core (non-Minecraft) libraries * - * @deprecated + * @deprecated Use {@link mod.azure.azurelib.core2.model.AzBakedModel} instead. */ public interface CoreBakedGeoModel { diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java index 0ec4f9ee6..2e9197cae 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimatableManager.java @@ -24,6 +24,7 @@ * * @deprecated */ +@Deprecated(forRemoval = true) public class AnimatableManager { private final Map boneSnapshotCollection = new Object2ObjectOpenHashMap<>(); diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java index ccedc9cc5..89b5391df 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java @@ -24,6 +24,7 @@ * * @deprecated */ +@Deprecated(forRemoval = true) public record Animation( String name, double length, diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java index 45a693d28..400e2e236 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java @@ -40,6 +40,7 @@ * * @deprecated */ +@Deprecated(forRemoval = true) public class AnimationController { protected static final Logger LOGGER = LoggerFactory.getLogger(AnimationController.class); diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java index 9be9afc62..5363da646 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java @@ -23,6 +23,7 @@ /** * @deprecated */ +@Deprecated(forRemoval = true) public class AnimationProcessor { private static final Logger LOGGER = LoggerFactory.getLogger(AnimationProcessor.class); diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java index 55e577be7..4e0d90671 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java @@ -21,6 +21,7 @@ * * @deprecated */ +@Deprecated(forRemoval = true) public class AnimationState { private final T animatable; diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java b/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java index 756274fd6..d2dd236da 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java @@ -21,6 +21,7 @@ * * @deprecated */ +@Deprecated(forRemoval = true) public abstract class ContextAwareAnimatableManager extends AnimatableManager { private final Map> managers; diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java index ce55c0510..e0df28c8e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java @@ -24,8 +24,9 @@ * RawAnimation.begin().thenPlay("action.open_box").thenLoop("state.stay_open") * }

    - * This is a quick algorithm based on Andy Hall's voxel-aabb-sweep + * This is a quick algorithm based on Andy Hall's voxel-aabb-sweep * * @param traversalVector The vector that represents the angle and length of traversal to cover * @param minBoundsPos The negative-most position representing the minimum corner of the bounds @@ -182,7 +203,7 @@ default Vec3 getEntityPosAtNode(int nodeIndex) { * @return Whether the given traversal is free from collisions */ default boolean isCollisionFreeTraversal(Vec3 traversalVector, Vec3 minBoundsPos, Vec3 leadingEdgePos) { - final float traversalDistance = (float)traversalVector.length(); + final float traversalDistance = (float) traversalVector.length(); if (traversalDistance < EPSILON) return true; @@ -201,15 +222,19 @@ default boolean isCollisionFreeTraversal(Vec3 traversalVector, Vec3 minBoundsPos ray.trailingEdgeBound[index] = Mth.floor(ray.minPos[index] + ray.absStep[index] * EPSILON); ray.axisLengthNormalised[index] = axisLength / traversalDistance; ray.axisSteps[index] = Mth.abs(traversalDistance / axisLength); - final float dist = isPositive ? (ray.leadingEdgeBound[index] + 1 - maxPos) : (maxPos - ray.leadingEdgeBound[index]); - ray.rayTargetLength[index] = ray.axisSteps[index] < Float.POSITIVE_INFINITY ? ray.axisSteps[index] * dist : Float.POSITIVE_INFINITY; + final float dist = isPositive + ? (ray.leadingEdgeBound[index] + 1 - maxPos) + : (maxPos - ray.leadingEdgeBound[index]); + ray.rayTargetLength[index] = ray.axisSteps[index] < Float.POSITIVE_INFINITY + ? ray.axisSteps[index] * dist + : Float.POSITIVE_INFINITY; } return collidesWhileTraversing(ray, traversalDistance); } /** - * @param ray The details container for the ray traversal + * @param ray The details container for the ray traversal * @param traversalDistance The direct length of the traversal vector * @return Whether the given bounds would collide for the given trajectory */ @@ -223,9 +248,9 @@ default boolean collidesWhileTraversing(VoxelRayDetails ray, float traversalDist float target = 0; do { - final Direction.Axis longestEdge = ray.rayTargetLength[0] < ray.rayTargetLength[1] ? - ray.rayTargetLength[0] < ray.rayTargetLength[2] ? Direction.Axis.X : Direction.Axis.Z : - ray.rayTargetLength[1] < ray.rayTargetLength[2] ? Direction.Axis.Y : Direction.Axis.Z; + final Direction.Axis longestEdge = ray.rayTargetLength[0] < ray.rayTargetLength[1] + ? ray.rayTargetLength[0] < ray.rayTargetLength[2] ? Direction.Axis.X : Direction.Axis.Z + : ray.rayTargetLength[1] < ray.rayTargetLength[2] ? Direction.Axis.Y : Direction.Axis.Z; final int index = longestEdge.ordinal(); final float rayDelta = ray.rayTargetLength[index] - target; target = ray.rayTargetLength[index]; @@ -255,10 +280,19 @@ default boolean collidesWhileTraversing(VoxelRayDetails ray, float traversalDist return false; } - if (!canPathOnto(nodeEvaluator.getPathType(new PathfindingContext(level, mob), x, yBound - 1, z))) + if ( + !canPathOnto( + nodeEvaluator.getPathType(new PathfindingContext(level, mob), x, yBound - 1, z) + ) + ) return false; - final PathType insidePathType = nodeEvaluator.getPathType(new PathfindingContext(level, mob), x, yBound, z); + final PathType insidePathType = nodeEvaluator.getPathType( + new PathfindingContext(level, mob), + x, + yBound, + z + ); final float pathMalus = mob.getPathfindingMalus(insidePathType); if (pathMalus < 0 || pathMalus >= 8) @@ -287,7 +321,16 @@ default boolean collidesWhileTraversing(VoxelRayDetails ray, float traversalDist * @param rayTargetLength How long the ray should be to account for traversal * @param axisLengthNormalised Fraction of the full distance the given length of this axis represents */ - record VoxelRayDetails(float[] minPos, int[] leadingEdgeBound, int[] trailingEdgeBound, int[] absStep, float[] axisSteps, float[] rayTargetLength, float[] axisLengthNormalised) { + record VoxelRayDetails( + float[] minPos, + int[] leadingEdgeBound, + int[] trailingEdgeBound, + int[] absStep, + float[] axisSteps, + float[] rayTargetLength, + float[] axisLengthNormalised + ) { + public VoxelRayDetails() { this(new float[3], new int[3], new int[3], new int[3], new float[3], new float[3], new float[3]); } @@ -297,6 +340,6 @@ public VoxelRayDetails() { * @return The vector length for the given axis */ default float lengthForAxis(Vec3 vector, Direction.Axis axis) { - return (float)axis.choose(vector.x, vector.y, vector.z); + return (float) axis.choose(vector.x, vector.y, vector.z); } } diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothAmphibiousPathNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothAmphibiousPathNavigation.java index 662364dd8..a0a766b43 100644 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothAmphibiousPathNavigation.java +++ b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothAmphibiousPathNavigation.java @@ -1,8 +1,7 @@ /** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. + * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: + * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: + * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. */ package mod.azure.azurelib.sblforked.api.core.navigation; @@ -17,13 +16,15 @@ /** * Extension of the vanilla {@link AmphibiousPathNavigation} with some tweaks for smoother pathfinding: *

    * - * @deprecated + * @deprecated Use {@link mod.azure.azurelib.core2.animation.primitive.AzRawAnimation} instead. */ +@Deprecated(forRemoval = true) public final class RawAnimation { private final List animationList = new ObjectArrayList<>(); diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java index 0d2344e86..870589815 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java @@ -13,8 +13,9 @@ * The {@link KeyFrameEvent} specific to the {@link AnimationController#customKeyframeHandler}.
    * Called when a custom instruction keyframe is encountered * - * @deprecated + * @deprecated Use {@link mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent} instead. */ +@Deprecated(forRemoval = true) public class CustomInstructionKeyframeEvent extends KeyFrameEvent { public CustomInstructionKeyframeEvent( diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java index 1d59e5085..127a3e26f 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java @@ -17,8 +17,9 @@ * @see CustomInstructionKeyframeEvent * @see ParticleKeyframeEvent * @see SoundKeyframeEvent - * @deprecated + * @deprecated Use {@link mod.azure.azurelib.core2.animation.event.AzKeyFrameEvent} instead. */ +@Deprecated(forRemoval = true) public abstract class KeyFrameEvent { private final T animatable; diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java index 5ada20342..bdc096098 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java @@ -13,8 +13,9 @@ * The {@link KeyFrameEvent} specific to the {@link AnimationController#particleKeyframeHandler}.
    * Called when a particle instruction keyframe is encountered * - * @deprecated + * @deprecated Use {@link mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent} instead. */ +@Deprecated(forRemoval = true) public class ParticleKeyframeEvent extends KeyFrameEvent { public ParticleKeyframeEvent( diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java index c42f4ed73..b61df3a96 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java @@ -13,8 +13,9 @@ * The {@link KeyFrameEvent} specific to the {@link AnimationController#soundKeyframeHandler}.
    * Called when a sound instruction keyframe is encountered * - * @deprecated + * @deprecated Use {@link mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent} instead. */ +@Deprecated(forRemoval = true) public class SoundKeyframeEvent extends KeyFrameEvent { /** diff --git a/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java b/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java index 91e9e9bf7..51fd26cc2 100644 --- a/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java +++ b/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java @@ -10,7 +10,10 @@ /** * Ticket object to define a typed data object + * + * @deprecated */ +@Deprecated(forRemoval = true) public class DataTicket { private final String id; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java b/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java index 7ec2febcb..f52577eb5 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java @@ -1175,7 +1175,10 @@ public interface Listener { /** * Renderer events for miscellaneous {@link GeoReplacedEntity replaced entities} being rendered by * {@link GeoReplacedEntityRenderer} + * + * @deprecated */ + @Deprecated(forRemoval = true) abstract class ReplacedEntity implements GeoRenderEvent { private final GeoReplacedEntityRenderer renderer; From ccb5d09606df4cd95fc913eeda194de07df12673 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Wed, 11 Dec 2024 17:28:28 -0500 Subject: [PATCH 027/224] Oopsies. Signed-off-by: = --- .../main/java/mod/azure/azurelib/fabric/ClientListener.java | 4 ++++ .../java/mod/azure/azurelib/fabric/FabricAzureLibMod.java | 2 ++ .../mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index 7bfccc8f2..1220a670b 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -50,6 +50,10 @@ public void onInitializeClient() { (packet, context) -> packet.handle() ); ClientPlayNetworking.registerGlobalReceiver(EntityAnimTriggerPacket.TYPE, (packet, context) -> packet.handle()); + ClientPlayNetworking.registerGlobalReceiver( + AzEntityAnimTriggerPacket.TYPE, + (packet, context) -> packet.handle() + ); ClientPlayNetworking.registerGlobalReceiver( EntityAnimDataSyncPacket.TYPE, (packet, context) -> packet.handle() diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 49b8136fb..18dee14ff 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -11,6 +11,7 @@ import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; import mod.azure.azurelib.common.internal.common.network.packet.AnimDataSyncPacket; import mod.azure.azurelib.common.internal.common.network.packet.AnimTriggerPacket; +import mod.azure.azurelib.common.internal.common.network.packet.AzEntityAnimTriggerPacket; import mod.azure.azurelib.common.internal.common.network.packet.BlockEntityAnimDataSyncPacket; import mod.azure.azurelib.common.internal.common.network.packet.BlockEntityAnimTriggerPacket; import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimDataSyncPacket; @@ -34,6 +35,7 @@ public void onInitialize() { PayloadTypeRegistry.playS2C().register(BlockEntityAnimTriggerPacket.TYPE, BlockEntityAnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(BlockEntityAnimDataSyncPacket.TYPE, BlockEntityAnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(EntityAnimTriggerPacket.TYPE, EntityAnimTriggerPacket.CODEC); + PayloadTypeRegistry.playS2C().register(AzEntityAnimTriggerPacket.TYPE, AzEntityAnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(EntityAnimDataSyncPacket.TYPE, EntityAnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(AnimTriggerPacket.TYPE, AnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(AnimDataSyncPacket.TYPE, AnimDataSyncPacket.CODEC); diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java index 684866256..b6fd0cb2c 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java @@ -60,6 +60,11 @@ public void registerMessages(RegisterPayloadHandlersEvent event) { EntityAnimTriggerPacket.CODEC, (msg, ctx) -> msg.handle() ); + registrar.playBidirectional( + AzEntityAnimTriggerPacket.TYPE, + AzEntityAnimTriggerPacket.CODEC, + (msg, ctx) -> msg.handle() + ); registrar.playBidirectional( EntityAnimDataSyncPacket.TYPE, EntityAnimDataSyncPacket.CODEC, From 1a6aa4849b5fa8e4cf211a13e046856343341f71 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:08:37 -0500 Subject: [PATCH 028/224] Bump MDG from 2.0.1-beta to 2.0.58-beta --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 82dcd4448..f1190e3be 100644 --- a/gradle.properties +++ b/gradle.properties @@ -27,7 +27,7 @@ neo_loader_version_range = [3,) mapping_channel = official mapping_version = 1.21.1 minecraft_version_range = [1.21.1, 1.21.2) -neo_moddev = 2.0.1-beta +neo_moddev = 2.0.58-beta neo_version = 21.1.62 neo_version_range = [21,) From 27f445169e8c00096d81270b37cce9de5dd7f763 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:08:45 -0500 Subject: [PATCH 029/224] alpha5 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f1190e3be..3c762cad8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -51,5 +51,5 @@ mod_logo = azurelib.png mod_name = AzureLib mod_sources = https://github.com/AzureDoom/AzureLib mod_url = https://modrinth.com/mod/azurelib -version = 3.0.0-alpha1 +version = 3.0.0-alpha5 modrinth_id = 7zlUOZvb From 08df3d0399be728fbba6f20e842d2d0a1e19c4e1 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 13:16:33 -0500 Subject: [PATCH 030/224] Removed AzAnimationStateHandler.java and stateHandler callback in AzAnimationController.java. Signed-off-by: = --- .../controller/AzAnimationController.java | 37 ++----------------- .../handler/AzAnimationStateHandler.java | 34 ----------------- .../fabric/core2/example/DroneAnimator.java | 8 +--- 3 files changed, 5 insertions(+), 74 deletions(-) delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 82451cf0b..adf855806 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -32,7 +32,6 @@ import mod.azure.azurelib.core2.animation.AzAnimationProcessor; import mod.azure.azurelib.core2.animation.AzAnimationState; import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.controller.handler.AzAnimationStateHandler; import mod.azure.azurelib.core2.animation.controller.handler.AzCustomKeyframeHandler; import mod.azure.azurelib.core2.animation.controller.handler.AzParticleKeyframeHandler; import mod.azure.azurelib.core2.animation.controller.handler.AzSoundKeyframeHandler; @@ -54,8 +53,6 @@ public class AzAnimationController { protected final String name; - protected final AzAnimationStateHandler stateHandler; - protected final Map boneAnimationQueues = new Object2ObjectOpenHashMap<>(); protected final Map boneSnapshots = new Object2ObjectOpenHashMap<>(); @@ -110,19 +107,11 @@ public class AzAnimationController { * @param name The name of the controller - should represent what animations it handles * @param transitionTickTime The amount of time (in ticks) that the controller should take to transition * between animations. Lerping is automatically applied where possible - * @param animationHandler The {@link AzAnimationStateHandler} animation state handler responsible for deciding - * which animations to play */ - public AzAnimationController( - AzAnimator animator, - String name, - int transitionTickTime, - AzAnimationStateHandler animationHandler - ) { + public AzAnimationController(AzAnimator animator, String name, int transitionTickTime) { this.animator = animator; this.name = name; this.transitionLength = transitionTickTime; - this.stateHandler = animationHandler; } /** @@ -224,20 +213,6 @@ public AzAnimationController triggerableAnim(String name, AzRawAnimation anim return this; } - /** - * Tells the AnimationController that you want to receive the {@link AzAnimationStateHandler} while a triggered - * animation is playing.
    - *
    - * This has no effect if no triggered animation has been registered, or one isn't currently playing.
    - * If a triggered animation is playing, it can be checked in your AnimationStateHandler via - * {@link AzAnimationController#isPlayingTriggeredAnimation()} - */ - public AzAnimationController receiveTriggeredAnimations() { - this.handlingTriggeredAnimations = true; - - return this; - } - /** * Gets the controller's name. * @@ -338,7 +313,6 @@ public AzRawAnimation getCurrentRawAnimation() { /** * Returns whether the controller is currently playing a triggered animation registered in * {@link AzAnimationController#triggerableAnim}
    - * Used for custom handling if {@link AzAnimationController#receiveTriggeredAnimations()} was marked */ public boolean isPlayingTriggeredAnimation() { return triggeredAnimation != null && !hasAnimationFinished(); @@ -413,11 +387,7 @@ protected PlayState handleAnimationState(AzAnimationState state) { setAnimation(state.getAnimatable(), triggeredAnimation); - if ( - !hasAnimationFinished() && (!handlingTriggeredAnimations || stateHandler.handle( - state - ) == PlayState.CONTINUE) - ) { + if (!hasAnimationFinished() && !handlingTriggeredAnimations) { return PlayState.CONTINUE; } @@ -425,7 +395,8 @@ protected PlayState handleAnimationState(AzAnimationState state) { this.needsAnimationReload = true; } - return stateHandler.handle(state); + // TODO: Revisit this. + return PlayState.CONTINUE; } /** diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java deleted file mode 100644 index 38ca3c3e8..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzAnimationStateHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -package mod.azure.azurelib.core2.animation.controller.handler; - -import mod.azure.azurelib.core.object.PlayState; -import mod.azure.azurelib.core2.animation.AzAnimationState; - -/** - * Every render frame, the {@code AzAnimationController} will call this handler for each animatable that is being - * rendered. This handler defines which animation should be currently playing, and returning a {@link PlayState} to tell - * the controller what to do next.
    - * Example Usage:
    - * - *
    {@code
    - *
    - * AzAnimationFrameHandler myIdleWalkHandler = state -> {
    - *     if (state.isMoving()) {
    - *         state.getController().setAnimation(myWalkAnimation);
    - *     } else {
    - *         state.getController().setAnimation(myIdleAnimation);
    - *     }
    - *
    - *     return PlayState.CONTINUE;
    - * };
    - * }
    - */ -@FunctionalInterface -public interface AzAnimationStateHandler { - - /** - * The handling method, called each frame. Return {@link PlayState#CONTINUE} to tell the controller to continue - * animating, or return {@link PlayState#STOP} to tell it to stop playing all animations and wait for the next - * {@code PlayState.CONTINUE} return. - */ - PlayState handle(AzAnimationState state); -} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java index d0bdc102e..b05bc7f93 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java @@ -4,8 +4,6 @@ import org.jetbrains.annotations.NotNull; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core.object.PlayState; -import mod.azure.azurelib.core2.animation.AzAnimationState; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; @@ -22,15 +20,11 @@ public class DroneAnimator extends AzEntityAnimator { @Override public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( - new AzAnimationController<>(this, "base_controller", 0, this::handle) + new AzAnimationController<>(this, "base_controller", 0) .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) ); } - public PlayState handle(AzAnimationState event) { - return PlayState.CONTINUE; - } - @Override public @NotNull ResourceLocation getAnimationLocation(Drone drone) { return ANIMATIONS; From 5b60469436c0d5f0298aa5877a16c61bf50c1e75 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 13:19:59 -0500 Subject: [PATCH 031/224] Removed handlingTriggeredAnimations field (triggered anims now the default). Signed-off-by: = --- .../core2/animation/controller/AzAnimationController.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index adf855806..8986c8175 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -81,8 +81,6 @@ public class AzAnimationController { protected AzRawAnimation triggeredAnimation = null; - protected boolean handlingTriggeredAnimations = false; - protected double transitionLength; protected AzRawAnimation currentRawAnimation; @@ -387,7 +385,7 @@ protected PlayState handleAnimationState(AzAnimationState state) { setAnimation(state.getAnimatable(), triggeredAnimation); - if (!hasAnimationFinished() && !handlingTriggeredAnimations) { + if (!hasAnimationFinished()) { return PlayState.CONTINUE; } From 5222fdd66c2726034107efd86fd066eec7eb4ec2 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 13:38:58 -0500 Subject: [PATCH 032/224] Implemented AzAnimationControllerCallbacks, function extraction. Signed-off-by: = --- .../controller/AzAnimationController.java | 104 +++++++----------- .../AzAnimationControllerCallbacks.java | 100 +++++++++++++++++ 2 files changed, 140 insertions(+), 64 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerCallbacks.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 8986c8175..6ea39bd78 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -32,9 +32,6 @@ import mod.azure.azurelib.core2.animation.AzAnimationProcessor; import mod.azure.azurelib.core2.animation.AzAnimationState; import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.controller.handler.AzCustomKeyframeHandler; -import mod.azure.azurelib.core2.animation.controller.handler.AzParticleKeyframeHandler; -import mod.azure.azurelib.core2.animation.controller.handler.AzSoundKeyframeHandler; import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; @@ -73,11 +70,7 @@ public class AzAnimationController { protected boolean justStartedTransition = false; - protected AzSoundKeyframeHandler soundKeyframeHandler = null; - - protected AzParticleKeyframeHandler particleKeyframeHandler = null; - - protected AzCustomKeyframeHandler customKeyframeHandler = null; + protected AzAnimationControllerCallbacks callbacks; protected AzRawAnimation triggeredAnimation = null; @@ -112,41 +105,8 @@ public AzAnimationController(AzAnimator animator, String name, int transition this.transitionLength = transitionTickTime; } - /** - * Applies the given {@link AzSoundKeyframeHandler} to this controller, for handling {@link AzSoundKeyframeEvent - * sound keyframe instructions}. - * - * @return this - */ - public AzAnimationController setSoundKeyframeHandler(AzSoundKeyframeHandler soundHandler) { - this.soundKeyframeHandler = soundHandler; - - return this; - } - - /** - * Applies the given {@link AzParticleKeyframeHandler} to this controller, for handling - * {@link AzParticleKeyframeEvent particle keyframe instructions}. - * - * @return this - */ - public AzAnimationController setParticleKeyframeHandler(AzParticleKeyframeHandler particleHandler) { - this.particleKeyframeHandler = particleHandler; - - return this; - } - - /** - * Applies the given {@link AzCustomKeyframeHandler} to this controller, for handling - * {@link AzCustomInstructionKeyframeEvent sound keyframe instructions}. - * - * @return this - */ - public AzAnimationController setCustomInstructionKeyframeHandler( - AzCustomKeyframeHandler customInstructionHandler - ) { - this.customKeyframeHandler = customInstructionHandler; - + public AzAnimationController setCallbacks(AzAnimationControllerCallbacks callbacks) { + this.callbacks = callbacks; return this; } @@ -614,24 +574,47 @@ protected void processCurrentAnimation( adjustedTick += this.transitionLength; - for (var keyframeData : currentAnimation.animation().keyFrames().sounds()) { + handleSoundKeyframes(animatable, adjustedTick); + handleParticleKeyframes(animatable, adjustedTick); + handleCustomKeyframes(animatable, adjustedTick); + + if ( + this.transitionLength == 0 && this.shouldResetTick + && this.animationState == AzAnimationControllerState.TRANSITIONING + ) { + this.currentAnimation = this.animationQueue.poll(); + } + } + + private void handleCustomKeyframes(T animatable, double adjustedTick) { + for ( + var keyframeData : currentAnimation.animation() + .keyFrames() + .customInstructions() + ) { + var customKeyframeHandler = callbacks.getCustomKeyframeHandler(); + if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { - if (soundKeyframeHandler == null) { + if (customKeyframeHandler == null) { LOGGER.warn( - "Sound Keyframe found for {} -> {}, but no keyframe handler registered", + "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", animatable.getClass().getSimpleName(), getName() ); break; } - soundKeyframeHandler.handle( - new AzSoundKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) + customKeyframeHandler.handle( + new AzCustomInstructionKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) ); } } + } + private void handleParticleKeyframes(T animatable, double adjustedTick) { for (var keyframeData : currentAnimation.animation().keyFrames().particles()) { + var particleKeyframeHandler = callbacks.getParticleKeyframeHandler(); + if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { if (particleKeyframeHandler == null) { LOGGER.warn( @@ -647,34 +630,27 @@ protected void processCurrentAnimation( ); } } + } + + private void handleSoundKeyframes(T animatable, double adjustedTick) { + for (var keyframeData : currentAnimation.animation().keyFrames().sounds()) { + var soundKeyframeHandler = callbacks.getSoundKeyframeHandler(); - for ( - var keyframeData : currentAnimation.animation() - .keyFrames() - .customInstructions() - ) { if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { - if (customKeyframeHandler == null) { + if (soundKeyframeHandler == null) { LOGGER.warn( - "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", + "Sound Keyframe found for {} -> {}, but no keyframe handler registered", animatable.getClass().getSimpleName(), getName() ); break; } - customKeyframeHandler.handle( - new AzCustomInstructionKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) + soundKeyframeHandler.handle( + new AzSoundKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) ); } } - - if ( - this.transitionLength == 0 && this.shouldResetTick - && this.animationState == AzAnimationControllerState.TRANSITIONING - ) { - this.currentAnimation = this.animationQueue.poll(); - } } /** diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerCallbacks.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerCallbacks.java new file mode 100644 index 000000000..24be9406d --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerCallbacks.java @@ -0,0 +1,100 @@ +package mod.azure.azurelib.core2.animation.controller; + +import mod.azure.azurelib.core2.animation.controller.handler.AzCustomKeyframeHandler; +import mod.azure.azurelib.core2.animation.controller.handler.AzParticleKeyframeHandler; +import mod.azure.azurelib.core2.animation.controller.handler.AzSoundKeyframeHandler; +import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; +import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; +import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; + +public class AzAnimationControllerCallbacks { + + private final AzCustomKeyframeHandler customKeyframeHandler; + + private final AzParticleKeyframeHandler particleKeyframeHandler; + + private final AzSoundKeyframeHandler soundKeyframeHandler; + + private AzAnimationControllerCallbacks( + AzCustomKeyframeHandler customKeyframeHandler, + AzParticleKeyframeHandler particleKeyframeHandler, + AzSoundKeyframeHandler soundKeyframeHandler + ) { + this.customKeyframeHandler = customKeyframeHandler; + this.particleKeyframeHandler = particleKeyframeHandler; + this.soundKeyframeHandler = soundKeyframeHandler; + } + + public AzCustomKeyframeHandler getCustomKeyframeHandler() { + return customKeyframeHandler; + } + + public AzParticleKeyframeHandler getParticleKeyframeHandler() { + return particleKeyframeHandler; + } + + public AzSoundKeyframeHandler getSoundKeyframeHandler() { + return soundKeyframeHandler; + } + + public static Builder builder() { + return new Builder<>(); + } + + public static class Builder { + + private AzCustomKeyframeHandler customKeyframeHandler; + + private AzParticleKeyframeHandler particleKeyframeHandler; + + private AzSoundKeyframeHandler soundKeyframeHandler; + + private Builder() {} + + /** + * Applies the given {@link AzSoundKeyframeHandler} to this controller, for handling {@link AzSoundKeyframeEvent + * sound keyframe instructions}. + * + * @return this + */ + public Builder setSoundKeyframeHandler(AzSoundKeyframeHandler soundHandler) { + this.soundKeyframeHandler = soundHandler; + + return this; + } + + /** + * Applies the given {@link AzParticleKeyframeHandler} to this controller, for handling + * {@link AzParticleKeyframeEvent particle keyframe instructions}. + * + * @return this + */ + public Builder setParticleKeyframeHandler(AzParticleKeyframeHandler particleHandler) { + this.particleKeyframeHandler = particleHandler; + + return this; + } + + /** + * Applies the given {@link AzCustomKeyframeHandler} to this controller, for handling + * {@link AzCustomInstructionKeyframeEvent sound keyframe instructions}. + * + * @return this + */ + public Builder setCustomInstructionKeyframeHandler( + AzCustomKeyframeHandler customInstructionHandler + ) { + this.customKeyframeHandler = customInstructionHandler; + + return this; + } + + public AzAnimationControllerCallbacks build() { + return new AzAnimationControllerCallbacks<>( + customKeyframeHandler, + particleKeyframeHandler, + soundKeyframeHandler + ); + } + } +} From d430610b4812bd01f9445cb8555e5707910e708d Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 14:00:12 -0500 Subject: [PATCH 033/224] Implemented AzKeyFrameCallbackManager.java. Signed-off-by: = --- .../controller/AzAnimationController.java | 105 +++------------- .../controller/AzKeyFrameCallbackManager.java | 119 ++++++++++++++++++ ...allbacks.java => AzKeyFrameCallbacks.java} | 8 +- 3 files changed, 137 insertions(+), 95 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbackManager.java rename common/src/main/java/mod/azure/azurelib/core2/animation/controller/{AzAnimationControllerCallbacks.java => AzKeyFrameCallbacks.java} (94%) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 6ea39bd78..9a25a4a8d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -1,7 +1,6 @@ package mod.azure.azurelib.core2.animation.controller; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,7 +10,6 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Queue; -import java.util.Set; import java.util.function.Function; import java.util.function.ToDoubleFunction; @@ -21,7 +19,6 @@ import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; import mod.azure.azurelib.core.keyframe.Keyframe; import mod.azure.azurelib.core.keyframe.KeyframeLocation; -import mod.azure.azurelib.core.keyframe.event.data.KeyFrameData; import mod.azure.azurelib.core.math.Constant; import mod.azure.azurelib.core.math.IValue; import mod.azure.azurelib.core.molang.MolangParser; @@ -32,9 +29,6 @@ import mod.azure.azurelib.core2.animation.AzAnimationProcessor; import mod.azure.azurelib.core2.animation.AzAnimationState; import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; -import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; -import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; @@ -56,10 +50,10 @@ public class AzAnimationController { protected final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); - protected final Set executedKeyFrames = new ObjectOpenHashSet<>(); - private final AzAnimator animator; + private final AzKeyFrameCallbackManager keyFrameCallbackManager; + protected Queue animationQueue = new LinkedList<>(); protected boolean isJustStarting = false; @@ -70,7 +64,7 @@ public class AzAnimationController { protected boolean justStartedTransition = false; - protected AzAnimationControllerCallbacks callbacks; + protected AzKeyFrameCallbacks keyFrameCallbacks; protected AzRawAnimation triggeredAnimation = null; @@ -103,10 +97,11 @@ public AzAnimationController(AzAnimator animator, String name, int transition this.animator = animator; this.name = name; this.transitionLength = transitionTickTime; + this.keyFrameCallbackManager = new AzKeyFrameCallbackManager<>(this); } - public AzAnimationController setCallbacks(AzAnimationControllerCallbacks callbacks) { - this.callbacks = callbacks; + public AzAnimationController setKeyFrameCallbacks(AzKeyFrameCallbacks keyFrameCallbacks) { + this.keyFrameCallbacks = keyFrameCallbacks; return this; } @@ -419,7 +414,7 @@ public void process( this.justStartedTransition = false; this.currentAnimation = animationQueue.poll(); - resetEventKeyFrames(); + keyFrameCallbackManager.reset(); if (currentAnimation == null) { return; @@ -510,12 +505,12 @@ protected void processCurrentAnimation( this.shouldResetTick = true; adjustedTick = adjustTick(animatable, seekTime); - resetEventKeyFrames(); + keyFrameCallbackManager.reset(); } } else { var nextAnimation = animationQueue.peek(); - resetEventKeyFrames(); + keyFrameCallbackManager.reset(); if (nextAnimation == null) { this.animationState = AzAnimationControllerState.STOPPED; @@ -574,9 +569,7 @@ protected void processCurrentAnimation( adjustedTick += this.transitionLength; - handleSoundKeyframes(animatable, adjustedTick); - handleParticleKeyframes(animatable, adjustedTick); - handleCustomKeyframes(animatable, adjustedTick); + keyFrameCallbackManager.handle(animatable, adjustedTick); if ( this.transitionLength == 0 && this.shouldResetTick @@ -586,73 +579,6 @@ protected void processCurrentAnimation( } } - private void handleCustomKeyframes(T animatable, double adjustedTick) { - for ( - var keyframeData : currentAnimation.animation() - .keyFrames() - .customInstructions() - ) { - var customKeyframeHandler = callbacks.getCustomKeyframeHandler(); - - if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { - if (customKeyframeHandler == null) { - LOGGER.warn( - "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", - animatable.getClass().getSimpleName(), - getName() - ); - break; - } - - customKeyframeHandler.handle( - new AzCustomInstructionKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) - ); - } - } - } - - private void handleParticleKeyframes(T animatable, double adjustedTick) { - for (var keyframeData : currentAnimation.animation().keyFrames().particles()) { - var particleKeyframeHandler = callbacks.getParticleKeyframeHandler(); - - if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { - if (particleKeyframeHandler == null) { - LOGGER.warn( - "Particle Keyframe found for {} -> {}, but no keyframe handler registered", - animatable.getClass().getSimpleName(), - getName() - ); - break; - } - - particleKeyframeHandler.handle( - new AzParticleKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) - ); - } - } - } - - private void handleSoundKeyframes(T animatable, double adjustedTick) { - for (var keyframeData : currentAnimation.animation().keyFrames().sounds()) { - var soundKeyframeHandler = callbacks.getSoundKeyframeHandler(); - - if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { - if (soundKeyframeHandler == null) { - LOGGER.warn( - "Sound Keyframe found for {} -> {}, but no keyframe handler registered", - animatable.getClass().getSimpleName(), - getName() - ); - break; - } - - soundKeyframeHandler.handle( - new AzSoundKeyframeEvent<>(animatable, adjustedTick, this, keyframeData) - ); - } - } - } - /** * Prepare the {@link BoneAnimationQueue} map for the current render frame * @@ -772,13 +698,6 @@ protected KeyframeLocation> getCurrentKeyFrameLocation( return new KeyframeLocation<>(frames.get(frames.size() - 1), ageInTicks); } - /** - * Clear the {@link KeyFrameData} cache in preparation for the next animation - */ - protected void resetEventKeyFrames() { - executedKeyFrames.clear(); - } - /** * Returns the current state of this controller. */ @@ -789,4 +708,8 @@ public AzAnimationControllerState getAnimationState() { public void setAnimationState(AzAnimationControllerState animationState) { this.animationState = animationState; } + + public AzKeyFrameCallbacks getKeyFrameCallbacks() { + return keyFrameCallbacks; + } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbackManager.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbackManager.java new file mode 100644 index 000000000..84f14945b --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbackManager.java @@ -0,0 +1,119 @@ +package mod.azure.azurelib.core2.animation.controller; + +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Set; + +import mod.azure.azurelib.core.keyframe.event.data.KeyFrameData; +import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; +import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; +import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; + +public class AzKeyFrameCallbackManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(AzKeyFrameCallbackManager.class); + + private final AzAnimationController animationController; + + private final Set executedKeyFrames; + + public AzKeyFrameCallbackManager(AzAnimationController animationController) { + this.animationController = animationController; + this.executedKeyFrames = new ObjectOpenHashSet<>(); + } + + public void handle(T animatable, double adjustedTick) { + handleSoundKeyframes(animatable, adjustedTick); + handleParticleKeyframes(animatable, adjustedTick); + handleCustomKeyframes(animatable, adjustedTick); + } + + private void handleCustomKeyframes(T animatable, double adjustedTick) { + for ( + var keyframeData : getCurrentAnimation().animation() + .keyFrames() + .customInstructions() + ) { + var customKeyframeHandler = getCallbacks().getCustomKeyframeHandler(); + + if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { + if (customKeyframeHandler == null) { + LOGGER.warn( + "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + getName() + ); + break; + } + + customKeyframeHandler.handle( + new AzCustomInstructionKeyframeEvent<>(animatable, adjustedTick, animationController, keyframeData) + ); + } + } + } + + private void handleParticleKeyframes(T animatable, double adjustedTick) { + for (var keyframeData : getCurrentAnimation().animation().keyFrames().particles()) { + var particleKeyframeHandler = getCallbacks().getParticleKeyframeHandler(); + + if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { + if (particleKeyframeHandler == null) { + LOGGER.warn( + "Particle Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + getName() + ); + break; + } + + particleKeyframeHandler.handle( + new AzParticleKeyframeEvent<>(animatable, adjustedTick, animationController, keyframeData) + ); + } + } + } + + private void handleSoundKeyframes(T animatable, double adjustedTick) { + for (var keyframeData : getCurrentAnimation().animation().keyFrames().sounds()) { + var soundKeyframeHandler = getCallbacks().getSoundKeyframeHandler(); + + if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { + if (soundKeyframeHandler == null) { + LOGGER.warn( + "Sound Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + getName() + ); + break; + } + + soundKeyframeHandler.handle( + new AzSoundKeyframeEvent<>(animatable, adjustedTick, animationController, keyframeData) + ); + } + } + } + + /** + * Clear the {@link KeyFrameData} cache in preparation for the next animation + */ + public void reset() { + executedKeyFrames.clear(); + } + + private AzKeyFrameCallbacks getCallbacks() { + return animationController.getKeyFrameCallbacks(); + } + + private AzQueuedAnimation getCurrentAnimation() { + return animationController.getCurrentAnimation(); + } + + private String getName() { + return animationController.getName(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerCallbacks.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbacks.java similarity index 94% rename from common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerCallbacks.java rename to common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbacks.java index 24be9406d..48fd053c6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerCallbacks.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbacks.java @@ -7,7 +7,7 @@ import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; -public class AzAnimationControllerCallbacks { +public class AzKeyFrameCallbacks { private final AzCustomKeyframeHandler customKeyframeHandler; @@ -15,7 +15,7 @@ public class AzAnimationControllerCallbacks { private final AzSoundKeyframeHandler soundKeyframeHandler; - private AzAnimationControllerCallbacks( + private AzKeyFrameCallbacks( AzCustomKeyframeHandler customKeyframeHandler, AzParticleKeyframeHandler particleKeyframeHandler, AzSoundKeyframeHandler soundKeyframeHandler @@ -89,8 +89,8 @@ public Builder setCustomInstructionKeyframeHandler( return this; } - public AzAnimationControllerCallbacks build() { - return new AzAnimationControllerCallbacks<>( + public AzKeyFrameCallbacks build() { + return new AzKeyFrameCallbacks<>( customKeyframeHandler, particleKeyframeHandler, soundKeyframeHandler From f0adc12e81c4c4ad20b3685a993de18473220b02 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 14:00:47 -0500 Subject: [PATCH 034/224] Refactor. Signed-off-by: = --- .../core2/animation/controller/AzAnimationController.java | 2 ++ .../{ => keyframe}/AzKeyFrameCallbackManager.java | 3 ++- .../controller/{ => keyframe}/AzKeyFrameCallbacks.java | 8 ++++---- .../{ => keyframe}/handler/AzCustomKeyframeHandler.java | 2 +- .../{ => keyframe}/handler/AzParticleKeyframeHandler.java | 2 +- .../{ => keyframe}/handler/AzSoundKeyframeHandler.java | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) rename common/src/main/java/mod/azure/azurelib/core2/animation/controller/{ => keyframe}/AzKeyFrameCallbackManager.java (96%) rename common/src/main/java/mod/azure/azurelib/core2/animation/controller/{ => keyframe}/AzKeyFrameCallbacks.java (89%) rename common/src/main/java/mod/azure/azurelib/core2/animation/controller/{ => keyframe}/handler/AzCustomKeyframeHandler.java (86%) rename common/src/main/java/mod/azure/azurelib/core2/animation/controller/{ => keyframe}/handler/AzParticleKeyframeHandler.java (86%) rename common/src/main/java/mod/azure/azurelib/core2/animation/controller/{ => keyframe}/handler/AzSoundKeyframeHandler.java (85%) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 9a25a4a8d..8da099d5b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -1,6 +1,8 @@ package mod.azure.azurelib.core2.animation.controller; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbackManager.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java similarity index 96% rename from common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbackManager.java rename to common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java index 84f14945b..50988fecc 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbackManager.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java @@ -1,6 +1,7 @@ -package mod.azure.azurelib.core2.animation.controller; +package mod.azure.azurelib.core2.animation.controller.keyframe; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbacks.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbacks.java similarity index 89% rename from common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbacks.java rename to common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbacks.java index 48fd053c6..f0246590d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzKeyFrameCallbacks.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbacks.java @@ -1,8 +1,8 @@ -package mod.azure.azurelib.core2.animation.controller; +package mod.azure.azurelib.core2.animation.controller.keyframe; -import mod.azure.azurelib.core2.animation.controller.handler.AzCustomKeyframeHandler; -import mod.azure.azurelib.core2.animation.controller.handler.AzParticleKeyframeHandler; -import mod.azure.azurelib.core2.animation.controller.handler.AzSoundKeyframeHandler; +import mod.azure.azurelib.core2.animation.controller.keyframe.handler.AzCustomKeyframeHandler; +import mod.azure.azurelib.core2.animation.controller.keyframe.handler.AzParticleKeyframeHandler; +import mod.azure.azurelib.core2.animation.controller.keyframe.handler.AzSoundKeyframeHandler; import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzCustomKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzCustomKeyframeHandler.java similarity index 86% rename from common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzCustomKeyframeHandler.java rename to common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzCustomKeyframeHandler.java index 014828458..02a5b4907 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzCustomKeyframeHandler.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzCustomKeyframeHandler.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.animation.controller.handler; +package mod.azure.azurelib.core2.animation.controller.keyframe.handler; import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzParticleKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzParticleKeyframeHandler.java similarity index 86% rename from common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzParticleKeyframeHandler.java rename to common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzParticleKeyframeHandler.java index 864f459da..48ea313a9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzParticleKeyframeHandler.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzParticleKeyframeHandler.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.animation.controller.handler; +package mod.azure.azurelib.core2.animation.controller.keyframe.handler; import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzSoundKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzSoundKeyframeHandler.java similarity index 85% rename from common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzSoundKeyframeHandler.java rename to common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzSoundKeyframeHandler.java index 55b709723..e8cf45c5c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/handler/AzSoundKeyframeHandler.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzSoundKeyframeHandler.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.animation.controller.handler; +package mod.azure.azurelib.core2.animation.controller.keyframe.handler; import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; From c7b9d4bfc4a9fd167a679cafdbf7754d4fa4d75b Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 14:18:00 -0500 Subject: [PATCH 035/224] Refactor. Signed-off-by: = --- .../keyframe/AzKeyFrameCallbackManager.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java index 50988fecc..da8848b09 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java @@ -13,6 +13,7 @@ import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; +// TODO: reduce the boilerplate of the specialized handle functions in this class. public class AzKeyFrameCallbackManager { private static final Logger LOGGER = LoggerFactory.getLogger(AzKeyFrameCallbackManager.class); @@ -33,13 +34,10 @@ public void handle(T animatable, double adjustedTick) { } private void handleCustomKeyframes(T animatable, double adjustedTick) { - for ( - var keyframeData : getCurrentAnimation().animation() - .keyFrames() - .customInstructions() - ) { - var customKeyframeHandler = getCallbacks().getCustomKeyframeHandler(); + var customKeyframeHandler = getCallbacks().getCustomKeyframeHandler(); + var customInstructions = getCurrentAnimation().animation().keyFrames().customInstructions(); + for (var keyframeData : customInstructions) { if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { if (customKeyframeHandler == null) { LOGGER.warn( @@ -58,9 +56,10 @@ private void handleCustomKeyframes(T animatable, double adjustedTick) { } private void handleParticleKeyframes(T animatable, double adjustedTick) { - for (var keyframeData : getCurrentAnimation().animation().keyFrames().particles()) { - var particleKeyframeHandler = getCallbacks().getParticleKeyframeHandler(); + var particleKeyframeHandler = getCallbacks().getParticleKeyframeHandler(); + var particleInstructions = getCurrentAnimation().animation().keyFrames().particles(); + for (var keyframeData : particleInstructions) { if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { if (particleKeyframeHandler == null) { LOGGER.warn( @@ -79,9 +78,10 @@ private void handleParticleKeyframes(T animatable, double adjustedTick) { } private void handleSoundKeyframes(T animatable, double adjustedTick) { - for (var keyframeData : getCurrentAnimation().animation().keyFrames().sounds()) { - var soundKeyframeHandler = getCallbacks().getSoundKeyframeHandler(); + var soundKeyframeHandler = getCallbacks().getSoundKeyframeHandler(); + var soundInstructions = getCurrentAnimation().animation().keyFrames().sounds(); + for (var keyframeData : soundInstructions) { if (adjustedTick >= keyframeData.getStartTick() && executedKeyFrames.add(keyframeData)) { if (soundKeyframeHandler == null) { LOGGER.warn( From 07cb1fcde0fb5df4fa4bcb0f858746799ade8244 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:43:34 -0500 Subject: [PATCH 036/224] No more SBL, no longer needed with new system of animating. --- LICENSE_SBLForked | 373 ---------- changelog.md | 1 + .../mod/azure/azurelib/sblforked/APIOnly.java | 19 - .../azurelib/sblforked/SBLConstants.java | 13 - .../azure/azurelib/sblforked/SBLLoader.java | 32 - .../sblforked/api/SmartBrainOwner.java | 162 ----- .../api/core/BrainActivityGroup.java | 132 ---- .../sblforked/api/core/SmartBrain.java | 527 -------------- .../api/core/SmartBrainProvider.java | 154 ----- .../behaviour/AllApplicableBehaviours.java | 140 ---- .../api/core/behaviour/DelayedBehaviour.java | 86 --- .../api/core/behaviour/ExtendedBehaviour.java | 325 --------- .../behaviour/FirstApplicableBehaviour.java | 45 -- .../api/core/behaviour/GroupBehaviour.java | 121 ---- .../api/core/behaviour/HeldBehaviour.java | 70 -- .../core/behaviour/OneRandomBehaviour.java | 47 -- .../core/behaviour/SequentialBehaviour.java | 80 --- .../custom/attack/AnimatableMeleeAttack.java | 102 --- .../custom/attack/AnimatableRangedAttack.java | 120 ---- .../behaviour/custom/attack/BowAttack.java | 52 -- .../custom/attack/ConditionlessAttack.java | 124 ---- .../attack/ConditionlessHeldAttack.java | 83 --- .../custom/look/LookAtAttackTarget.java | 62 -- .../behaviour/custom/look/LookAtTarget.java | 52 -- .../core/behaviour/custom/misc/AvoidSun.java | 48 -- .../custom/misc/BlockWithShield.java | 85 --- .../behaviour/custom/misc/BreakBlock.java | 165 ----- .../custom/misc/BreedWithPartner.java | 169 ----- .../custom/misc/CustomBehaviour.java | 53 -- .../custom/misc/CustomDelayedBehaviour.java | 35 - .../custom/misc/CustomHeldBehaviour.java | 55 -- .../core/behaviour/custom/misc/HoldItem.java | 99 --- .../api/core/behaviour/custom/misc/Idle.java | 33 - .../custom/misc/InvalidateMemory.java | 75 -- .../api/core/behaviour/custom/misc/Panic.java | 229 ------ .../custom/misc/ReactToUnreachableTarget.java | 94 --- .../behaviour/custom/move/AvoidEntity.java | 148 ---- .../core/behaviour/custom/move/EscapeSun.java | 124 ---- .../behaviour/custom/move/FleeTarget.java | 111 --- .../custom/move/FloatToSurfaceOfFluid.java | 65 -- .../behaviour/custom/move/FollowEntity.java | 246 ------- .../behaviour/custom/move/FollowOwner.java | 34 - .../behaviour/custom/move/FollowParent.java | 70 -- .../custom/move/FollowTemptation.java | 176 ----- .../custom/move/MoveToWalkTarget.java | 174 ----- .../StayWithinDistanceOfAttackTarget.java | 176 ----- .../behaviour/custom/move/StrafeTarget.java | 129 ---- .../custom/move/WalkOrRunToWalkTarget.java | 35 - .../custom/path/SeekRandomNearbyPosition.java | 177 ----- .../custom/path/SetRandomFlyingTarget.java | 72 -- .../custom/path/SetRandomHoverTarget.java | 159 ----- .../custom/path/SetRandomSwimTarget.java | 133 ---- .../custom/path/SetRandomWalkTarget.java | 164 ----- .../path/SetWalkTargetToAttackTarget.java | 107 --- .../custom/path/SetWalkTargetToBlock.java | 118 ---- .../custom/target/InvalidateAttackTarget.java | 106 --- .../target/SetAdditionalAttackTargets.java | 166 ----- .../custom/target/SetAttackTarget.java | 104 --- .../custom/target/SetPlayerLookTarget.java | 78 --- .../custom/target/SetRandomLookTarget.java | 85 --- .../custom/target/SetRetaliateTarget.java | 140 ---- .../custom/target/TargetOrRetaliate.java | 185 ----- .../core/navigation/ExtendedNavigator.java | 345 ---------- .../SmoothAmphibiousPathNavigation.java | 62 -- .../SmoothFlyingPathNavigation.java | 52 -- .../navigation/SmoothGroundNavigation.java | 114 --- .../SmoothWallClimberNavigation.java | 67 -- .../SmoothWaterBoundPathNavigation.java | 64 -- .../api/core/schedule/SmartBrainSchedule.java | 211 ------ .../core/sensor/EntityFilteringSensor.java | 73 -- .../api/core/sensor/ExtendedSensor.java | 107 --- .../api/core/sensor/PredicateSensor.java | 51 -- .../custom/GenericAttackTargetSensor.java | 52 -- .../custom/IncomingProjectilesSensor.java | 78 --- .../sensor/custom/NearbyBlocksSensor.java | 100 --- .../core/sensor/custom/NearbyItemsSensor.java | 93 --- .../custom/UnreachableTargetSensor.java | 92 --- .../sensor/vanilla/AxolotlSpecificSensor.java | 74 -- .../sensor/vanilla/FrogSpecificSensor.java | 70 -- .../sensor/vanilla/HoglinSpecificSensor.java | 88 --- .../api/core/sensor/vanilla/HurtBySensor.java | 73 -- .../core/sensor/vanilla/InWaterSensor.java | 57 -- .../sensor/vanilla/ItemTemptingSensor.java | 141 ---- .../sensor/vanilla/NearbyAdultSensor.java | 50 -- .../core/sensor/vanilla/NearbyBabySensor.java | 51 -- .../sensor/vanilla/NearbyGolemSensor.java | 90 --- .../sensor/vanilla/NearbyHostileSensor.java | 104 --- .../vanilla/NearbyLivingEntitySensor.java | 109 --- .../sensor/vanilla/NearbyPlayersSensor.java | 123 ---- .../sensor/vanilla/NearestHomeSensor.java | 116 ---- .../sensor/vanilla/NearestItemSensor.java | 95 --- .../vanilla/PiglinBruteSpecificSensor.java | 70 -- .../sensor/vanilla/PiglinSpecificSensor.java | 155 ----- .../sensor/vanilla/SecondaryPoiSensor.java | 111 --- .../sensor/vanilla/WardenSpecificSensor.java | 72 -- .../object/BrainBehaviourConsumer.java | 30 - .../object/BrainBehaviourPredicate.java | 35 - .../object/ExtendedTargetingConditions.java | 157 ----- .../FixedNearestVisibleLivingEntities.java | 48 -- .../sblforked/object/FreePositionTracker.java | 35 - .../sblforked/object/SBLShufflingList.java | 124 ---- .../sblforked/object/SquareRadius.java | 40 -- .../sblforked/object/TriPredicate.java | 33 - .../sblforked/registry/SBLMemoryTypes.java | 52 -- .../sblforked/registry/SBLSensors.java | 139 ---- .../azurelib/sblforked/util/BrainUtils.java | 650 ------------------ .../sblforked/util/EntityRetrievalUtil.java | 370 ---------- .../azurelib/sblforked/util/RandomUtil.java | 336 --------- .../azurelib/sblforked/util/SensoryUtils.java | 78 --- .../src/main/resources/azurelib.accesswidener | 36 - .../azurelib/fabric/FabricAzureLibMod.java | 2 - .../fabric/platform/FabricSBLForked.java | 63 -- .../neoforge/NeoForgeAzureLibMod.java | 2 - .../MultiFluidNavigationElement.java | 40 -- .../MultiFluidSmoothGroundNavigation.java | 92 --- .../MultiFluidWalkNodeEvaluator.java | 115 ---- .../neoforge/platform/NeoForgeSBLForked.java | 72 -- .../resources/META-INF/accesstransformer.cfg | 29 - 118 files changed, 1 insertion(+), 13131 deletions(-) delete mode 100644 LICENSE_SBLForked delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/APIOnly.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/SBLConstants.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/SBLLoader.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/SmartBrainOwner.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/BrainActivityGroup.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrain.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrainProvider.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/AllApplicableBehaviours.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/DelayedBehaviour.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/ExtendedBehaviour.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/FirstApplicableBehaviour.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/GroupBehaviour.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/HeldBehaviour.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/OneRandomBehaviour.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/SequentialBehaviour.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableMeleeAttack.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableRangedAttack.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/BowAttack.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessAttack.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessHeldAttack.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtAttackTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/AvoidSun.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BlockWithShield.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreakBlock.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreedWithPartner.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomBehaviour.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomDelayedBehaviour.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomHeldBehaviour.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/HoldItem.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Idle.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/InvalidateMemory.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Panic.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/ReactToUnreachableTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/AvoidEntity.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/EscapeSun.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FleeTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FloatToSurfaceOfFluid.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowEntity.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowOwner.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowParent.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowTemptation.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/MoveToWalkTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StayWithinDistanceOfAttackTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StrafeTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/WalkOrRunToWalkTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SeekRandomNearbyPosition.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomFlyingTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomHoverTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomSwimTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomWalkTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToAttackTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToBlock.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/InvalidateAttackTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAdditionalAttackTargets.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAttackTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetPlayerLookTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRandomLookTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRetaliateTarget.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/TargetOrRetaliate.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/ExtendedNavigator.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothAmphibiousPathNavigation.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothFlyingPathNavigation.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothGroundNavigation.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWallClimberNavigation.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWaterBoundPathNavigation.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/schedule/SmartBrainSchedule.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/EntityFilteringSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/ExtendedSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/PredicateSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/GenericAttackTargetSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/IncomingProjectilesSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyBlocksSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyItemsSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/UnreachableTargetSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/AxolotlSpecificSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/FrogSpecificSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HoglinSpecificSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HurtBySensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/InWaterSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/ItemTemptingSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyAdultSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyBabySensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyGolemSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyHostileSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyLivingEntitySensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyPlayersSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestHomeSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestItemSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinBruteSpecificSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinSpecificSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/SecondaryPoiSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/WardenSpecificSensor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourConsumer.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourPredicate.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/object/ExtendedTargetingConditions.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/object/FixedNearestVisibleLivingEntities.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/object/FreePositionTracker.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/object/SBLShufflingList.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/object/SquareRadius.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/object/TriPredicate.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLMemoryTypes.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLSensors.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/util/BrainUtils.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/util/EntityRetrievalUtil.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/util/RandomUtil.java delete mode 100644 common/src/main/java/mod/azure/azurelib/sblforked/util/SensoryUtils.java delete mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricSBLForked.java delete mode 100644 neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidNavigationElement.java delete mode 100644 neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidSmoothGroundNavigation.java delete mode 100644 neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/nodeevaluator/MultiFluidWalkNodeEvaluator.java delete mode 100644 neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeSBLForked.java diff --git a/LICENSE_SBLForked b/LICENSE_SBLForked deleted file mode 100644 index a612ad981..000000000 --- a/LICENSE_SBLForked +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/changelog.md b/changelog.md index bbd9babd3..9ecc937a3 100644 --- a/changelog.md +++ b/changelog.md @@ -5,4 +5,5 @@ v3.0.0 - Render pipeline completely rewritten. - MORE WIP - Move to new Az Naming scheme from Geo +- No longer ship with a forked SBL, no longer being used in my mods moving forward. - MORE WIP \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/APIOnly.java b/common/src/main/java/mod/azure/azurelib/sblforked/APIOnly.java deleted file mode 100644 index 6ae164efa..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/APIOnly.java +++ /dev/null @@ -1,19 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Methods marked with this annotation should only be used internally, or by abstract-subclasses. This is usually done - * to avoid accidentally overriding methods handled in the super class. - */ -@Retention(RetentionPolicy.SOURCE) -@Target(ElementType.METHOD) -public @interface APIOnly {} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/SBLConstants.java b/common/src/main/java/mod/azure/azurelib/sblforked/SBLConstants.java deleted file mode 100644 index 5feec2788..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/SBLConstants.java +++ /dev/null @@ -1,13 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked; - -import java.util.ServiceLoader; - -public class SBLConstants { - - public static final SBLLoader SBL_LOADER = ServiceLoader.load(SBLLoader.class).findFirst().get(); -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/SBLLoader.java b/common/src/main/java/mod/azure/azurelib/sblforked/SBLLoader.java deleted file mode 100644 index ad51a4972..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/SBLLoader.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked; - -import com.mojang.serialization.Codec; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import org.jetbrains.annotations.ApiStatus; - -import java.util.Optional; -import java.util.function.Supplier; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; - -public interface SBLLoader { - - void init(Object eventBus); - - boolean isDevEnv(); - - @ApiStatus.Internal - Supplier> registerMemoryType(String id); - - @ApiStatus.Internal - Supplier> registerMemoryType(String id, Optional> codec); - - @ApiStatus.Internal - > Supplier> registerSensorType(String id, Supplier sensor); -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/SmartBrainOwner.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/SmartBrainOwner.java deleted file mode 100644 index 1a15e528e..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/SmartBrainOwner.java +++ /dev/null @@ -1,162 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api; - -import com.google.common.collect.ImmutableSet; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.schedule.Activity; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import mod.azure.azurelib.sblforked.APIOnly; -import mod.azure.azurelib.sblforked.api.core.BrainActivityGroup; -import mod.azure.azurelib.sblforked.api.core.SmartBrain; -import mod.azure.azurelib.sblforked.api.core.schedule.SmartBrainSchedule; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; - -/** - * Implement this class for any entity you want to use the SmartBrain system.
    - * This interface contains the helper and constructive methods for initialising your entity's brain. - * - * @param Your entity - */ -public interface SmartBrainOwner> { - - /** - * The list of {@link ExtendedSensor Sensors} that your entity will be using.
    - * Only supports ExtendedSensors. - * - * @return A {@link List} of {@link ExtendedSensor Sensors} that the entity will use to fill memories for tasks. - */ - List> getSensors(); - - /** - * Override this for tasks that ideally should always be running, regardless of anything else.
    - * Usually you'd use this for things like moving towards the current target, floating on water, looking at a certain - * target, etc.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category
    - *
    - * Tasks returned in this category take up the {@link Activity#CORE} activity category - * - * @return a {@link BrainActivityGroup} containing the core tasks your entity should run. - */ - default BrainActivityGroup getCoreTasks() { - return BrainActivityGroup.empty(); - } - - /** - * Override this for tasks that would normally run when your entity is doing nothing else.
    - * Usually you'd use this for things like random walking, setting targets, or just standing still and doing nothing - * at all.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category
    - *
    - * Tasks returned in this category take up the {@link Activity#IDLE} activity category - * - * @return a {@link BrainActivityGroup} containing the idle tasks your entity should run. - */ - default BrainActivityGroup getIdleTasks() { - return BrainActivityGroup.empty(); - } - - /** - * Override this to add the tasks that would normally run when your entity attacking something, or is otherwise in - * combat.
    - * Usually you'd use this for things melee attacking, invalidating attack targets, or setting walk targets based off - * the current attack target.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category
    - *
    - * Tasks returned in this category take up the {@link Activity#FIGHT} activity category - * - * @return a {@link BrainActivityGroup} containing the fight tasks your entity should run. - */ - default BrainActivityGroup getFightTasks() { - return BrainActivityGroup.empty(); - } - - /** - * Override this to add any additional tasks that don't fit into the categories already handled in the pre-defined - * activity task methods.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category - * - * @return a {@link Map} of Activities to BrainActivityGroups group containing the additional tasks your entity - * should run. - */ - default Map> getAdditionalTasks() { - return new Object2ObjectOpenHashMap<>(0); - } - - /** - * The activity categories that should always be running, regardless of any other conditions or situations.
    - * This is usually just left as {@link Activity#CORE}, but it can be modified as needed - * - * @return A {@link Set} of {@link Activity Activities} - */ - default Set getAlwaysRunningActivities() { - return ImmutableSet.of(Activity.CORE); - } - - /** - * The activity category that is used as a fallback, for when no other activity categories meet the conditions to - * run.
    - * This is almost always left as {@link Activity#IDLE}, but it can be modified as needed. - * - * @return The {@link Activity} to use as a fallback - */ - default Activity getDefaultActivity() { - return Activity.IDLE; - } - - /** - * Override this to return the order of activity categories the brain should attempt to run things in.
    - * The list is ordered in order of insertion - I.E. earlier elements have higher priority - * - * @return An ordered {@link List} of {@link Activity} categories - */ - default List getActivityPriorities() { - return ObjectArrayList.of(Activity.FIGHT, Activity.IDLE); - } - - /** - * Override this to do any additional work after the brain has been built and readied.
    - * By this stage, the brain has had all its memories, sensors, activities, and priorities set. - * - * @param brain The brain that the entity will be using. - */ - default void handleAdditionalBrainSetup(SmartBrain brain) {} - - /** - * Override this to return the {@link net.minecraft.world.entity.schedule.Schedule schedule} for your entity.
    - * This can be set at any time via {@link SmartBrain#setSchedule(SmartBrainSchedule)}, but it's recommended to do so - * statically if possible and provide it through this method - * - * @return The schedule for the brain, or null if no schedule - */ - @Nullable - default SmartBrainSchedule getSchedule() { - return null; - } - - /** - * SmartBrainOwners MUST call this from the entity's {@link LivingEntity#serverAiStep}, or - * {@link Mob#customServerAiStep} if extending Mob.
    - * Brains should only be ticked server side.
    - * This method does not need to be overridden. - * - * @param entity The brain owner - */ - @APIOnly - default void tickBrain(T entity) { - ((Brain) entity.getBrain()).tick((ServerLevel) entity.level(), entity); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/BrainActivityGroup.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/BrainActivityGroup.java deleted file mode 100644 index d17b4af60..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/BrainActivityGroup.java +++ /dev/null @@ -1,132 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core; - -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.Behavior; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.schedule.Activity; - -import java.util.List; -import java.util.Set; - -import mod.azure.azurelib.sblforked.api.SmartBrainOwner; - -public class BrainActivityGroup> { - - private final Activity activity; - - private int priorityStart = 0; - - private final List> behaviours = new ObjectArrayList<>(); - - private final Set, MemoryStatus>> activityStartMemoryConditions = - new ObjectOpenHashSet<>(); - - private Set> wipedMemoriesOnFinish = null; - - public BrainActivityGroup(Activity activity) { - this.activity = activity; - } - - public BrainActivityGroup priority(int priorityStart) { - this.priorityStart = priorityStart; - - return this; - } - - public BrainActivityGroup behaviours(Behavior... behaviours) { - this.behaviours.addAll(new ObjectArrayList<>(behaviours)); - - return this; - } - - public BrainActivityGroup onlyStartWithMemoryStatus(MemoryModuleType memory, MemoryStatus status) { - this.activityStartMemoryConditions.add(Pair.of(memory, status)); - - return this; - } - - public BrainActivityGroup wipeMemoriesWhenFinished(MemoryModuleType... memories) { - if (this.wipedMemoriesOnFinish == null) { - this.wipedMemoriesOnFinish = new ObjectOpenHashSet<>(memories); - } else { - this.wipedMemoriesOnFinish.addAll(new ObjectOpenHashSet<>(memories)); - } - - return this; - } - - public BrainActivityGroup requireAndWipeMemoriesOnUse(MemoryModuleType... memories) { - for (MemoryModuleType memory : memories) { - onlyStartWithMemoryStatus(memory, MemoryStatus.VALUE_PRESENT); - } - - wipeMemoriesWhenFinished(memories); - - return this; - } - - public Activity getActivity() { - return this.activity; - } - - public List> getBehaviours() { - return this.behaviours; - } - - public int getPriorityStart() { - return this.priorityStart; - } - - public Set, MemoryStatus>> getActivityStartMemoryConditions() { - return this.activityStartMemoryConditions; - } - - public Set> getWipedMemoriesOnFinish() { - return this.wipedMemoriesOnFinish != null ? this.wipedMemoriesOnFinish : Set.of(); - } - - public ImmutableList>> pairBehaviourPriorities() { - int priority = this.priorityStart; - ImmutableList.Builder>> pairedBehaviours = ImmutableList.builder(); - - for (Behavior behaviour : this.behaviours) { - pairedBehaviours.add(Pair.of(priority++, behaviour)); - } - - return pairedBehaviours.build(); - } - - public static > BrainActivityGroup empty() { - return new BrainActivityGroup(Activity.REST); - } - - public static > BrainActivityGroup coreTasks( - Behavior... behaviours - ) { - return new BrainActivityGroup(Activity.CORE).priority(0).behaviours(behaviours); - } - - public static > BrainActivityGroup idleTasks( - Behavior... behaviours - ) { - return new BrainActivityGroup(Activity.IDLE).priority(10).behaviours(behaviours); - } - - public static > BrainActivityGroup fightTasks( - Behavior... behaviours - ) { - return new BrainActivityGroup(Activity.FIGHT).priority(10) - .behaviours(behaviours) - .requireAndWipeMemoriesOnUse(MemoryModuleType.ATTACK_TARGET); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrain.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrain.java deleted file mode 100644 index e1b6cf16d..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrain.java +++ /dev/null @@ -1,527 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core; - -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Codec; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.behavior.Behavior; -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import net.minecraft.world.entity.ai.behavior.GateBehavior; -import net.minecraft.world.entity.ai.memory.ExpirableValue; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.sensing.Sensor; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.schedule.Activity; -import net.minecraft.world.entity.schedule.Schedule; -import org.apache.commons.lang3.mutable.MutableObject; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.Consumer; -import java.util.stream.Stream; - -import mod.azure.azurelib.sblforked.api.SmartBrainOwner; -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; -import mod.azure.azurelib.sblforked.api.core.schedule.SmartBrainSchedule; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.object.BrainBehaviourConsumer; -import mod.azure.azurelib.sblforked.object.BrainBehaviourPredicate; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Supercedes vanilla's {@link Brain}. One of the core components of the SBL library.
    - * Any entity that returns a {@link SmartBrainProvider} from {@link LivingEntity#brainProvider()} will have one of - * these. - * - * @param The entity - */ -public class SmartBrain> extends Brain { - - private final List> expirableMemories = new ObjectArrayList<>(); - - private final List> behaviours = new ObjectArrayList<>(); - - private final List>, ExtendedSensor>> sensors = - new ObjectArrayList<>(); - - private SmartBrainSchedule schedule = null; - - private boolean sortBehaviours = false; - - public SmartBrain( - List> memories, - List> sensors, - @Nullable List> taskList - ) { - super(memories, ImmutableList.of(), ImmutableList.of(), SmartBrain::emptyBrainCodec); - - for (ExtendedSensor sensor : sensors) { - this.sensors.add(Pair.of((SensorType) sensor.type(), sensor)); - } - - if (taskList != null) { - for (BrainActivityGroup group : taskList) { - addActivity(group); - } - } - } - - @Override - public void tick(ServerLevel level, E entity) { - entity.level().getProfiler().push("SmartBrain"); - - if (this.sortBehaviours) - this.behaviours.sort(Comparator.comparingInt(ActivityBehaviours::priority)); - - forgetOutdatedMemories(); - tickSensors(level, entity); - checkForNewBehaviours(level, entity); - tickRunningBehaviours(level, entity); - findAndSetActiveActivity(entity); - - entity.level().getProfiler().pop(); - - if (entity instanceof Mob mob) - mob.setAggressive(BrainUtils.hasMemory(mob, MemoryModuleType.ATTACK_TARGET)); - } - - private void findAndSetActiveActivity(E entity) { - if (this.schedule != null) { - Activity scheduledActivity = this.schedule.tick(entity); - - if ( - scheduledActivity != null && !getActiveActivities().contains(scheduledActivity) - && activityRequirementsAreMet(scheduledActivity) - ) { - setActiveActivity(scheduledActivity); - - return; - } - } - - setActiveActivityToFirstValid(entity.getActivityPriorities()); - } - - private void tickSensors(ServerLevel level, E entity) { - for (Pair>, ExtendedSensor> sensor : this.sensors) { - sensor.getSecond().tick(level, entity); - } - } - - private void checkForNewBehaviours(ServerLevel level, E entity) { - long gameTime = level.getGameTime(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - if (getActiveActivities().contains(pair.getFirst())) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.STOPPED) - behaviour.tryStart(level, entity, gameTime); - } - } - } - } - } - - private void tickRunningBehaviours(ServerLevel level, E entity) { - long gameTime = level.getGameTime(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.tickOrStop(level, entity, gameTime); - } - } - } - } - - @Override - public void forgetOutdatedMemories() { - Iterator> expirable = this.expirableMemories.iterator(); - - while (expirable.hasNext()) { - MemoryModuleType memoryType = expirable.next(); - Optional> memory = memories.get(memoryType); - - if (memory.isEmpty()) { - expirable.remove(); - } else { - ExpirableValue value = memory.get(); - - if (!value.canExpire()) { - expirable.remove(); - } else if (value.hasExpired()) { - expirable.remove(); - eraseMemory(memoryType); - } else { - value.tick(); - } - } - } - } - - @Override - public void stopAll(ServerLevel level, E entity) { - long gameTime = level.getGameTime(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.doStop(level, entity, gameTime); - } - } - } - } - - @Override - public Optional getMemory(MemoryModuleType type) { - return (Optional) this.memories.computeIfAbsent(type, key -> Optional.empty()).map(ExpirableValue::getValue); - } - - @Override - public void setMemoryInternal(MemoryModuleType memoryType, Optional> memory) { - if (memory.isPresent() && memory.get().getValue() instanceof Collection collection && collection.isEmpty()) - memory = Optional.empty(); - - this.memories.put(memoryType, memory); - - if (memory.isPresent() && memory.get().canExpire() && !this.expirableMemories.contains(memoryType)) - this.expirableMemories.add(memoryType); - } - - @Override - public boolean isMemoryValue(MemoryModuleType memoryType, U memory) { - Optional value = getMemory(memoryType); - - return value.isPresent() && value.get().equals(memory); - } - - private static > Codec> emptyBrainCodec() { - MutableObject>> brainCodec = new MutableObject<>(); - - brainCodec.setValue( - Codec.unit( - () -> new Brain<>(ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), brainCodec::getValue) - ) - ); - - return brainCodec.getValue(); - } - - private static > List>> convertSensorsToTypes( - List> sensors - ) { - List>> types = new ObjectArrayList<>(sensors.size()); - - for (ExtendedSensor sensor : sensors) { - types.add((SensorType) sensor.type()); - } - - return types; - } - - @Override - public Brain copyWithoutBehaviors() { - SmartBrain brain = new SmartBrain<>( - this.memories.keySet().stream().toList(), - this.sensors.stream().map(pair -> (ExtendedSensor) pair.getSecond()).toList(), - null - ); - - for (Map.Entry, Optional>> entry : this.memories.entrySet()) { - MemoryModuleType memoryType = entry.getKey(); - - if (entry.getValue().isPresent()) - brain.memories.put(memoryType, entry.getValue()); - } - - return brain; - } - - @Override - public List> getRunningBehaviors() { - List> runningBehaviours = new ObjectArrayList<>(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - runningBehaviours.add(behaviour); - } - } - } - - return runningBehaviours; - } - - /** - * Returns a stream of all {@link BehaviorControl Behaviours} registered to this brain - */ - public Stream> getBehaviours() { - return this.behaviours.stream() - .map(ActivityBehaviours::behaviours) - .flatMap(list -> list.stream().map(Pair::getSecond).flatMap(List::stream)); - } - - @Override - public void removeAllBehaviors() { - this.behaviours.clear(); - } - - @Override - public void addActivityAndRemoveMemoriesWhenStopped( - Activity activity, - ImmutableList>> tasks, - Set, MemoryStatus>> memorieStatuses, - Set> memoryTypes - ) { - this.activityRequirements.put(activity, memorieStatuses); - - if (!memoryTypes.isEmpty()) - this.activityMemoriesToEraseWhenStopped.put(activity, memoryTypes); - - for (Pair> pair : tasks) { - addBehaviour(pair.getFirst(), activity, pair.getSecond()); - } - } - - /** - * Adds a full {@link BrainActivityGroup} to the brain, inclusive of activities and conditions - */ - public void addActivity(BrainActivityGroup activityGroup) { - addActivityAndRemoveMemoriesWhenStopped( - activityGroup.getActivity(), - activityGroup.pairBehaviourPriorities(), - activityGroup.getActivityStartMemoryConditions(), - activityGroup.getWipedMemoriesOnFinish() - ); - } - - /** - * Add a behaviour to the behaviours list of this brain. - * - * @param priority The behaviour's priority value - * @param activity The behaviour's activity category - * @param behaviour The behaviour instance - */ - public void addBehaviour(int priority, Activity activity, BehaviorControl behaviour) { - for (ActivityBehaviours behaviourGroup : this.behaviours) { - if (behaviourGroup.priority == priority) { - for (Pair>> pair : behaviourGroup.behaviours) { - if (pair.getFirst() == activity) { - pair.getSecond().add(behaviour); - - return; - } - } - - behaviourGroup.behaviours.add(Pair.of(activity, ObjectArrayList.of(behaviour))); - - return; - } - } - - this.behaviours.add( - new ActivityBehaviours<>( - priority, - ObjectArrayList.of(Pair.of(activity, ObjectArrayList.>of(behaviour))) - ) - ); - this.sortBehaviours = true; - } - - /** - * Removes any behaviours matching the given predicate from the provided brain.
    - * Removed behaviours are stopped prior to removal - * - * @param entity The owner of the brain - * @param predicate The predicate checked for each (priority, activity, behaviour) - */ - public void removeBehaviour(E entity, BrainBehaviourPredicate predicate) { - for (ActivityBehaviours behaviourGroup : this.behaviours) { - int priority = behaviourGroup.priority; - - for (Pair>> pair : behaviourGroup.behaviours) { - Activity activity = pair.getFirst(); - - for (Iterator> iterator = pair.getSecond().iterator(); iterator.hasNext();) { - BehaviorControl behaviour = iterator.next(); - - checkBehaviour(priority, activity, behaviour, null, predicate, () -> { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.doStop((ServerLevel) entity.level(), entity, entity.level().getGameTime()); - - iterator.remove(); - }); - } - } - } - } - - /** - * Sets a {@link SmartBrainSchedule} for this brain, for scheduled functionality - * - * @param schedule The schedule to set for the brain - * @return this - */ - public SmartBrain setSchedule(SmartBrainSchedule schedule) { - this.schedule = schedule; - - return this; - } - - /** - * @return The {@link SmartBrainSchedule schedule} of this brain - */ - @Override - public SmartBrainSchedule getSchedule() { - return this.schedule; - } - - /** - * Cheekily (and conveniently) uses the {@link SmartBrainSchedule schedule} system to schedule a delayed runnable - * for this entity/brain. - * - * @param delay The delay (in ticks) before running the task - * @param task The task to run at the given tick - */ - public void scheduleTask(E brainOwner, int delay, Consumer task) { - if (this.schedule == null) - this.schedule = new SmartBrainSchedule(); - - this.schedule.scheduleTask(brainOwner, delay, (Consumer) task); - } - - private static void checkBehaviour( - int priority, - Activity activity, - BehaviorControl behaviour, - @Nullable BehaviorControl parentBehaviour, - BrainBehaviourPredicate predicate, - Runnable callback - ) { - if (predicate.isBehaviour(priority, activity, behaviour, parentBehaviour)) { - callback.run(); - } else if (behaviour instanceof GateBehavior groupBehaviour) { - for ( - Iterator> childBehaviourIterator = groupBehaviour.behaviors.iterator(); - childBehaviourIterator.hasNext(); - ) { - checkBehaviour( - priority, - activity, - childBehaviourIterator.next(), - groupBehaviour, - predicate, - childBehaviourIterator::remove - ); - } - - if (!groupBehaviour.behaviors.iterator().hasNext()) - callback.run(); - } else if (behaviour instanceof GroupBehaviour groupBehaviour) { - for ( - Iterator> childBehaviourIterator = groupBehaviour.getBehaviours(); - childBehaviourIterator.hasNext(); - ) { - checkBehaviour( - priority, - activity, - childBehaviourIterator.next(), - groupBehaviour, - predicate, - childBehaviourIterator::remove - ); - } - - if (!groupBehaviour.getBehaviours().hasNext()) - callback.run(); - } - } - - /** - * Loops over all {@link BehaviorControl Behaviours} registered to this brain, calling the consumer for each - * - * @param consumer The consumer called for each (priority, activity, behaviour) - */ - public void forEachBehaviour(BrainBehaviourConsumer consumer) { - for (ActivityBehaviours behavioursGroup : this.behaviours) { - int priority = behavioursGroup.priority(); - - for (Pair>> behaviourList : behavioursGroup.behaviours()) { - Activity activity = behaviourList.getFirst(); - - for (BehaviorControl behaviour : behaviourList.getSecond()) { - consumeBehaviour(priority, activity, behaviour, null, consumer); - } - } - } - } - - private static void consumeBehaviour( - int priority, - Activity activity, - BehaviorControl behaviour, - @Nullable BehaviorControl parentBehaviour, - BrainBehaviourConsumer consumer - ) { - consumer.consume(priority, activity, behaviour, parentBehaviour); - - if (behaviour instanceof GateBehavior groupBehaviour) { - groupBehaviour.behaviors.stream() - .forEach( - childBehaviour -> consumeBehaviour( - priority, - activity, - (BehaviorControl) childBehaviour, - groupBehaviour, - consumer - ) - ); - } else if (behaviour instanceof GroupBehaviour groupBehaviour) { - groupBehaviour.getBehaviours() - .forEachRemaining( - childBehaviour -> consumeBehaviour( - priority, - activity, - (BehaviorControl) childBehaviour, - groupBehaviour, - consumer - ) - ); - } - } - - /** - * Adds an {@link ExtendedSensor} to this brain - */ - public void addSensor(ExtendedSensor sensor) { - SensorType> sensorType = (SensorType) sensor.type(); - - this.sensors.add(Pair.of(sensorType, sensor)); - } - - /** - * Not supported, use {@link SmartBrain#setSchedule(SmartBrainSchedule)} instead - */ - @Deprecated(forRemoval = true) - @Override - public final void setSchedule(Schedule schedule) {} - - private record ActivityBehaviours>( - int priority, - List>>> behaviours - ) {} -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrainProvider.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrainProvider.java deleted file mode 100644 index 5dff12cc0..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrainProvider.java +++ /dev/null @@ -1,154 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core; - -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Dynamic; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.behavior.Behavior; -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import net.minecraft.world.entity.ai.behavior.GateBehavior; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.schedule.Activity; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import mod.azure.azurelib.sblforked.api.SmartBrainOwner; -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; - -/** - * The provider of {@link SmartBrain SmartBrains}. All entities intending to utilise this library should return a new - * instance of this in {@link LivingEntity#brainProvider()}
    - * All entities that use this provider use SmartBrains. - * - * @param The entity - */ -public class SmartBrainProvider> extends Brain.Provider { - - private static final Map, ImmutableList>> BRAIN_MEMORY_CACHE = - new Object2ObjectOpenHashMap<>(); - - private final E owner; - - private final boolean nonStaticMemories; - - /** - * @param owner The owner of the brain - */ - public SmartBrainProvider(E owner) { - this(owner, false); - } - - /** - * @param owner The owner of the brain - * @param nonStaticMemories Whether the entity has different behaviours or sensors depending on the entity instance - */ - public SmartBrainProvider(E owner, boolean nonStaticMemories) { - super(List.of(), List.of()); - - this.owner = owner; - this.nonStaticMemories = nonStaticMemories; - } - - @Override - public final SmartBrain makeBrain(Dynamic codecLoader) { - List> sensors = this.owner.getSensors(); - List> taskList = compileTasks(); - ImmutableList> memories; - - if (!this.nonStaticMemories && BRAIN_MEMORY_CACHE.containsKey(this.owner.getType())) { - memories = BRAIN_MEMORY_CACHE.get(this.owner.getType()); - } else { - memories = createMemoryList(taskList, sensors); - - if (!this.nonStaticMemories) - BRAIN_MEMORY_CACHE.put((EntityType) this.owner.getType(), memories); - } - - SmartBrain brain = new SmartBrain(memories, sensors, taskList); - - finaliseBrain(brain); - - return brain; - } - - private ImmutableList> createMemoryList( - List> taskList, - List> sensors - ) { - Set> memoryTypes = new ObjectOpenHashSet<>(); - - taskList.forEach( - activityGroup -> activityGroup.getBehaviours() - .forEach(behavior -> collectMemoriesFromTask(memoryTypes, behavior)) - ); - sensors.forEach(sensor -> memoryTypes.addAll(sensor.memoriesUsed())); - - return ImmutableList.copyOf(memoryTypes); - } - - private void collectMemoriesFromTask(Set> memories, BehaviorControl behaviour) { - if (behaviour instanceof GateBehavior gateBehaviour) { - gateBehaviour.behaviors.stream().forEach(subBehaviour -> collectMemoriesFromTask(memories, subBehaviour)); - } else if (behaviour instanceof GroupBehaviour groupBehaviour) { - groupBehaviour.getBehaviours() - .forEachRemaining(subBehaviour -> collectMemoriesFromTask(memories, subBehaviour)); - } else if (behaviour instanceof Behavior behaviour2) { - memories.addAll(behaviour2.entryCondition.keySet()); - } - } - - private List> compileTasks() { - List> tasks = new ObjectArrayList<>(); - BrainActivityGroup activityGroup; - - if (!(activityGroup = owner.getCoreTasks()).getBehaviours().isEmpty()) - tasks.add(activityGroup); - - if (!(activityGroup = owner.getIdleTasks()).getBehaviours().isEmpty()) - tasks.add(activityGroup); - - if (!(activityGroup = owner.getFightTasks()).getBehaviours().isEmpty()) - tasks.add(activityGroup); - - tasks.addAll(owner.getAdditionalTasks().values()); - - return tasks; - } - - private void finaliseBrain(SmartBrain brain) { - brain.setCoreActivities(this.owner.getAlwaysRunningActivities()); - brain.setDefaultActivity(this.owner.getDefaultActivity()); - brain.useDefaultActivity(); - brain.setSchedule(this.owner.getSchedule()); - this.owner.handleAdditionalBrainSetup(brain); - } - - /** - * Use one of the startup 'getTasks' methods if adding at startup, or else use - * {@link mod.azure.azurelib.sblforked.util.BrainUtils#addActivity(Brain, BrainActivityGroup)} - */ - @Deprecated(forRemoval = true) - protected void addActivity(SmartBrain brain, Activity activity, BrainActivityGroup activityGroup) { - brain.activityRequirements.put(activity, activityGroup.getActivityStartMemoryConditions()); - - if (!activityGroup.getWipedMemoriesOnFinish().isEmpty()) - brain.activityMemoriesToEraseWhenStopped.put(activity, activityGroup.getWipedMemoriesOnFinish()); - - for (Pair> pair : activityGroup.pairBehaviourPriorities()) { - brain.addBehaviour(pair.getFirst(), activity, pair.getSecond()); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/AllApplicableBehaviours.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/AllApplicableBehaviours.java deleted file mode 100644 index e80c1ccf7..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/AllApplicableBehaviours.java +++ /dev/null @@ -1,140 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import org.jetbrains.annotations.Nullable; - -import java.util.Set; -import java.util.stream.Collectors; - -import mod.azure.azurelib.sblforked.object.SBLShufflingList; - -/** - * Group behaviour that attempts to run all sub-behaviours in order, running any that apply.
    - * This allows for wrapping entire groups of behaviours in overarching conditions or nesting them in other groups.
    - * This will count this behaviour as running if any of the child behaviours are running. - * - * @param The entity - */ -public final class AllApplicableBehaviours extends GroupBehaviour { - - public AllApplicableBehaviours(Pair, Integer>... behaviours) { - super(behaviours); - } - - public AllApplicableBehaviours(ExtendedBehaviour... behaviours) { - super(behaviours); - } - - @Override - protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { - if ( - this.cooldownFinishedAt > gameTime || !hasRequiredMemories(entity) || !this.startCondition.test(entity) - || !checkExtraStartConditions(level, entity) - ) - return false; - - return (this.runningBehaviour = pickBehaviour(level, entity, gameTime, this.behaviours)) != null; - } - - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour( - ServerLevel level, - E entity, - long gameTime, - SBLShufflingList> extendedBehaviours - ) { - ExtendedBehaviour lastSuccessfulBehaviour = null; - - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (behaviour.tryStart(level, entity, gameTime)) - lastSuccessfulBehaviour = behaviour; - } - - return lastSuccessfulBehaviour; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - boolean stillOperational = false; - - for (ExtendedBehaviour behaviour : this.behaviours) { - stillOperational |= behaviour.getStatus() == Status.RUNNING && behaviour.canStillUse( - (ServerLevel) entity.level(), - entity, - entity.level().getGameTime() - ); - } - - return stillOperational; - } - - @Override - protected boolean timedOut(long gameTime) { - boolean timedOut = true; - - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING && !behaviour.timedOut(gameTime)) - timedOut = false; - } - - return timedOut; - } - - @Override - protected void tick(ServerLevel level, E owner, long gameTime) { - boolean stillRunning = false; - - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING) { - behaviour.tickOrStop(level, owner, gameTime); - - if (behaviour.getStatus() != Status.STOPPED) - stillRunning = true; - } - } - - if (!stillRunning) - doStop(level, owner, gameTime); - } - - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - this.cooldownFinishedAt = gameTime + cooldownProvider.apply(entity); - - this.taskStopCallback.accept(entity); - stop(entity); - - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING) - behaviour.doStop(level, entity, gameTime); - } - } - - @Override - public Status getStatus() { - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING) - return Status.RUNNING; - } - - return Status.STOPPED; - } - - @Override - public String toString() { - final Set> activeBehaviours = this.behaviours.stream() - .filter(behaviorControl -> behaviorControl.getStatus() == Status.RUNNING) - .collect(Collectors.toSet()); - - return "(" + getClass().getSimpleName() + "): " + activeBehaviours; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/DelayedBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/DelayedBehaviour.java deleted file mode 100644 index c4a79d1f9..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/DelayedBehaviour.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; - -import java.util.function.Consumer; - -/** - * An abstract behaviour used for tasks that should have a start, and then a followup delayed action.
    - * This is most useful for things like attacks that have associated animations, or action which require a charge up or - * prep time.
    - * - * @param The entity - */ -public abstract class DelayedBehaviour extends ExtendedBehaviour { - - protected final int delayTime; - - protected long delayFinishedAt = 0; - - protected Consumer delayedCallback = entity -> {}; - - public DelayedBehaviour(int delayTicks) { - this.delayTime = delayTicks; - - runFor(entity -> Math.max(delayTicks, 60)); - } - - /** - * A callback for when the delayed action is called. - * - * @param callback The callback - * @return this - */ - public final DelayedBehaviour whenActivating(Consumer callback) { - this.delayedCallback = callback; - - return this; - } - - @Override - protected final void start(ServerLevel level, E entity, long gameTime) { - if (this.delayTime > 0) { - this.delayFinishedAt = gameTime + this.delayTime; - - super.start(level, entity, gameTime); - } else { - super.start(level, entity, gameTime); - doDelayedAction(entity); - } - } - - @Override - protected final void stop(ServerLevel level, E entity, long gameTime) { - super.stop(level, entity, gameTime); - - this.delayFinishedAt = 0; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.delayFinishedAt >= entity.level().getGameTime(); - } - - @Override - protected final void tick(ServerLevel level, E entity, long gameTime) { - super.tick(level, entity, gameTime); - - if (this.delayFinishedAt <= gameTime) { - doDelayedAction(entity); - this.delayedCallback.accept(entity); - } - } - - /** - * The action to take once the delay period has elapsed. - * - * @param entity The owner of the brain - */ - protected void doDelayedAction(E entity) {} -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/ExtendedBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/ExtendedBehaviour.java deleted file mode 100644 index 4b05bc0ec..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/ExtendedBehaviour.java +++ /dev/null @@ -1,325 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.behavior.Behavior; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.APIOnly; - -/** - * An extension of the base Behavior class that is used for tasks in the brain system.
    - * This extension auto-handles some boilerplate and adds in some additional auto-handled functions:
    - *
      - *
    • Task start and stop callbacks for additional entity-interactions
    • - *
    • A functional implementation of a duration provider
    • - *
    • A functional implementation of a cooldown provider
    • - *
    - * Ideally, all custom behaviours should use at least this class as a base, instead of the core Behavior class - * - * @param Your entity - */ -public abstract class ExtendedBehaviour extends Behavior { - - protected Predicate startCondition = entity -> true; - - protected Predicate stopCondition = entity -> false; - - protected Consumer taskStartCallback = entity -> {}; - - protected Consumer taskStopCallback = entity -> {}; - - protected Function runtimeProvider = entity -> 60; - - protected Function cooldownProvider = entity -> 0; - - protected long cooldownFinishedAt = 0; - - public ExtendedBehaviour() { - super(new Object2ObjectOpenHashMap<>()); - - for (Pair, MemoryStatus> memoryReq : getMemoryRequirements()) { - this.entryCondition.put(memoryReq.getFirst(), memoryReq.getSecond()); - } - } - - /** - * A callback for when the task begins. Use this to trigger effects or handle things when the entity activates this - * task. - * - * @param callback The callback - * @return this - */ - public final ExtendedBehaviour whenStarting(Consumer callback) { - this.taskStartCallback = callback; - - return this; - } - - /** - * A callback for when the task stops. Use this to trigger effects or handle things when the entity ends this task. - *
    - * Note that the task stopping does not necessarily mean it was successful. - * - * @param callback The callback - * @return this - */ - public final ExtendedBehaviour whenStopping(Consumer callback) { - this.taskStopCallback = callback; - - return this; - } - - /** - * Set the length that the task should run for, once activated. The value used is in ticks. - * - * @param timeProvider A function for the tick value - * @return this - */ - public final ExtendedBehaviour runFor(Function timeProvider) { - this.runtimeProvider = timeProvider; - - return this; - } - - /** - * Set the length that the task should wait for between activations. This is the time between when the task stops, - * and it is able to start again. The value used is in ticks - * - * @param timeProvider A function for the tick value - * @return this - */ - public final ExtendedBehaviour cooldownFor(Function timeProvider) { - this.cooldownProvider = timeProvider; - - return this; - } - - /** - * Set an additional condition for the behaviour to be able to start. Useful for dynamically predicating - * behaviours.
    - * Prevents this behaviour starting unless this predicate returns true. - * - * @param predicate The predicate - * @return this - */ - public final ExtendedBehaviour startCondition(Predicate predicate) { - this.startCondition = predicate; - - return this; - } - - /** - * Set an automatic condition for the behavior to stop. Useful for dynamically stopping behaviours. Has no effect on - * one-shot behaviours that don't have a runtime.
    - * Stops the behaviour if it is active and this predicate returns true. - * - * @param predicate The predicate - * @return this - */ - public final ExtendedBehaviour stopIf(Predicate predicate) { - this.stopCondition = predicate; - - return this; - } - - /** - * Defines a maximum value timeout period for this behaviour. - *

    - * Functionally, this means that the behaviour will not timeout, and will rely on other factors to stop (such as - * memory conditions failing) - *

    - * - * @return this - */ - public final ExtendedBehaviour noTimeout() { - return runFor(entity -> Integer.MAX_VALUE); - } - - @Override - public final boolean tryStart(ServerLevel level, E entity, long gameTime) { - if (!doStartCheck(level, entity, gameTime)) - return false; - - this.status = Status.RUNNING; - this.endTimestamp = gameTime + this.runtimeProvider.apply(entity); - - start(level, entity, gameTime); - - return true; - } - - @APIOnly - protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { - return this.cooldownFinishedAt <= gameTime && hasRequiredMemories(entity) && this.startCondition.test(entity) - && checkExtraStartConditions(level, entity); - } - - /** - * Check any extra conditions required for this behaviour to start.
    - * By this stage, memory conditions from {@link ExtendedBehaviour#getMemoryRequirements()} have already been - * checked. - * - * @param level The level the entity is in - * @param entity The owner of the brain - * @return Whether the conditions have been met to start the behaviour - */ - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return true; - } - - /** - * The root stop method for when this behaviour stops. This method should only be overridden by other abstract - * subclasses.
    - * If overriding, ensure you either call {@code super} or manually call {@code stop(E)} yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - */ - @APIOnly - @Override - protected void start(ServerLevel level, E entity, long gameTime) { - this.taskStartCallback.accept(entity); - start(entity); - } - - /** - * Override this for custom behaviour implementations. This is a safe endpoint for behaviours so that all required - * auto-handling is safely contained without super calls.
    - * This is called when the behaviour is to start. Set up any instance variables needed or perform the required - * actions.
    - * By this stage any memory requirements set in {@link ExtendedBehaviour#getMemoryRequirements()} are true, so any - * memories paired with {@link MemoryStatus#VALUE_PRESENT} are safe to retrieve. - * - * @param entity The entity being handled (I.E. the owner of the brain) - */ - protected void start(E entity) {} - - /** - * The root stop method for when this behaviour stops. This method should only be overridden by other abstract - * subclasses.
    - * If overriding, ensure you either call {@code super} or manually call {@code stop(E)} yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - */ - @APIOnly - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - this.cooldownFinishedAt = gameTime + cooldownProvider.apply(entity); - - this.taskStopCallback.accept(entity); - stop(entity); - } - - /** - * Override this for custom behaviour implementations. This is a safe endpoint for behaviours so that all required - * auto-handling is safely contained without super calls.
    - * This is called when the behaviour is to stop. Close off any instanced variables and such here, ready for the next - * start. - * - * @param entity The entity being handled (I.E. the owner of the brain) - */ - protected void stop(E entity) {} - - /** - * The root method to check if this behaviour should continue running. This method should only be overridden by - * other abstract subclasses.
    - * If overriding, ensure you either call super or manually call the {@link ExtendedBehaviour#stopCondition} check - * yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - * @return Whether the behaviour should continue ticking - */ - @Override - protected boolean canStillUse(ServerLevel level, E entity, long gameTime) { - return shouldKeepRunning(entity) && !this.stopCondition.test(entity); - } - - /** - * Check whether the behaviour should continue running. This is checked before {@link ExtendedBehaviour#tick(E)}. - *
    - * Memories are not guaranteed to be in their required state here, so if you have required memories, it might be - * worth checking them here. - * - * @param entity The owner of the brain - * @return Whether the behaviour should continue ticking - */ - protected boolean shouldKeepRunning(E entity) { - return false; - } - - /** - * The root tick method for when this behaviour ticks. This method should only be overridden by other abstract - * subclasses.
    - * If overriding, ensure you either call {@code super} or manually call {@code tick(E)} yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - */ - @APIOnly - @Override - protected void tick(ServerLevel level, E entity, long gameTime) { - tick(entity); - } - - /** - * Override this for custom behaviour implementations. This is a safe endpoint for behaviours so that all required - * auto-handling is safely contained without super calls.
    - * This is called when the behaviour is ticked. Be aware this is called every tick, so use tick reduction if - * needed to minimise performance impacts of goals.
    - * NOTE: Memory requirements are not guaranteed at this stage. If you are retrieving brain memories, you'll - * need to check their presence before use. - * - * @param entity The entity being handled (I.E. the owner of the brain) - */ - protected void tick(E entity) {} - - @Override - protected boolean timedOut(long gameTime) { - return super.timedOut(gameTime); - } - - @APIOnly - @Override - public final boolean hasRequiredMemories(E entity) { - Brain brain = entity.getBrain(); - - for (Pair, MemoryStatus> memoryPair : getMemoryRequirements()) { - if (!brain.checkMemory(memoryPair.getFirst(), memoryPair.getSecond())) - return false; - } - - return true; - } - - /** - * The list of memory requirements this task has prior to starting. This outlines the approximate state the brain - * should be in, in order to allow this behaviour to run.
    - * Bonus points if it's a statically-initialised list. - * - * @return The {@link List} of {@link MemoryModuleType Memories} and their associated required {@link MemoryStatus - * status} - */ - protected abstract List, MemoryStatus>> getMemoryRequirements(); -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/FirstApplicableBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/FirstApplicableBehaviour.java deleted file mode 100644 index 031d3fec5..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/FirstApplicableBehaviour.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import org.jetbrains.annotations.Nullable; - -import mod.azure.azurelib.sblforked.object.SBLShufflingList; - -/** - * Group behaviour that attempts to run all sub-behaviours in order, until the first successful one. - * - * @param The entity - */ -public final class FirstApplicableBehaviour extends GroupBehaviour { - - public FirstApplicableBehaviour(Pair, Integer>... behaviours) { - super(behaviours); - } - - public FirstApplicableBehaviour(ExtendedBehaviour... behaviours) { - super(behaviours); - } - - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour( - ServerLevel level, - E entity, - long gameTime, - SBLShufflingList> extendedBehaviours - ) { - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (behaviour.tryStart(level, entity, gameTime)) - return behaviour; - } - - return null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/GroupBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/GroupBehaviour.java deleted file mode 100644 index d8003eb0b..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/GroupBehaviour.java +++ /dev/null @@ -1,121 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import org.jetbrains.annotations.Nullable; - -import java.util.Iterator; -import java.util.List; - -import mod.azure.azurelib.sblforked.object.SBLShufflingList; - -/** - * Functional replacement to {@link net.minecraft.world.entity.ai.behavior.GateBehavior} due to the very poor way it is - * implemented.
    - * In particular, this allows nesting of group behaviours without breaking behaviour flow entirely.
    - * It also allows for utilising the various callbacks and conditions that {@link ExtendedBehaviour} offers.
    - * NOTE: Only supports ExtendedBehaviour implementations as sub-behaviours. This is due to access-modifiers on the - * vanilla behaviours making this prohibitively annoying to work with. - */ -public abstract class GroupBehaviour extends ExtendedBehaviour { - - protected final SBLShufflingList> behaviours; - - @Nullable - protected ExtendedBehaviour runningBehaviour = null; - - public GroupBehaviour(Pair, Integer>... behaviours) { - this.behaviours = new SBLShufflingList<>(behaviours); - } - - public GroupBehaviour(ExtendedBehaviour... behaviours) { - this.behaviours = new SBLShufflingList<>(); - - for (ExtendedBehaviour behaviour : behaviours) { - this.behaviours.add(behaviour, 1); - } - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - public Iterator> getBehaviours() { - return this.behaviours.iterator(); - } - - @Nullable - protected abstract ExtendedBehaviour pickBehaviour( - ServerLevel level, - E entity, - long gameTime, - SBLShufflingList> behaviours - ); - - @Override - protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { - if (!super.doStartCheck(level, entity, gameTime)) - return false; - - return (this.runningBehaviour = pickBehaviour(level, entity, gameTime, this.behaviours)) != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.runningBehaviour != null && this.runningBehaviour.canStillUse( - (ServerLevel) entity.level(), - entity, - entity.level().getGameTime() - ); - } - - @Override - protected boolean timedOut(long gameTime) { - return this.runningBehaviour == null || this.runningBehaviour.timedOut(gameTime); - } - - @Override - protected void tick(ServerLevel level, E owner, long gameTime) { - this.runningBehaviour.tickOrStop(level, owner, gameTime); - - if (this.runningBehaviour.getStatus() == Status.STOPPED) { - this.runningBehaviour = null; - - doStop(level, owner, gameTime); - } - } - - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - super.stop(level, entity, gameTime); - - if (this.runningBehaviour != null) - this.runningBehaviour.stop(level, entity, gameTime); - - this.runningBehaviour = null; - } - - @Override - public Status getStatus() { - if (this.runningBehaviour == null) - return Status.STOPPED; - - return this.runningBehaviour.getStatus(); - } - - @Override - public String toString() { - return "(" + getClass().getSimpleName() + "): " + (this.runningBehaviour == null - ? this.runningBehaviour.getClass().getSimpleName() - : "{}"); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/HeldBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/HeldBehaviour.java deleted file mode 100644 index 16ef07b02..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/HeldBehaviour.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; - -import java.util.function.Function; - -/** - * An abstract behaviour used for tasks that should have an ongoing effect, optionally with an early finish.
    - * This is most useful for things like attacks with multi-tick effects such as beams or flamethrowers, or other - * prolonged actions. - * - * @param The entity - */ -public abstract class HeldBehaviour extends ExtendedBehaviour { - - protected Function tickConsumer = entity -> true; - - protected int runningTime = 0; - - public HeldBehaviour() { - runFor(entity -> Integer.MAX_VALUE); - } - - /** - * Set the per-tick handler for this held behaviour - * - * @param tickConsumer The consumer to handle the per-action tick. Return false to end the behaviour, or true to - * continue running - */ - public HeldBehaviour onTick(Function tickConsumer) { - this.tickConsumer = tickConsumer; - - return this; - } - - /** - * Gets the amount of ticks this behaviour has been held for - */ - public int getRunningTime() { - return this.runningTime; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return true; - } - - @Override - protected void start(ServerLevel level, E entity, long gameTime) { - super.start(level, entity, gameTime); - - this.runningTime = 0; - } - - @Override - protected void tick(ServerLevel level, E owner, long gameTime) { - super.tick(level, owner, gameTime); - - if (!this.tickConsumer.apply(owner)) - doStop(level, owner, gameTime); - - this.runningTime++; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/OneRandomBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/OneRandomBehaviour.java deleted file mode 100644 index f15482c8f..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/OneRandomBehaviour.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import org.jetbrains.annotations.Nullable; - -import mod.azure.azurelib.sblforked.object.SBLShufflingList; - -/** - * Group behaviour that attempts to run sub-behaviours in a - * - * @param The entity - */ -public final class OneRandomBehaviour extends GroupBehaviour { - - public OneRandomBehaviour(Pair, Integer>... behaviours) { - super(behaviours); - } - - public OneRandomBehaviour(ExtendedBehaviour... behaviours) { - super(behaviours); - } - - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour( - ServerLevel level, - E entity, - long gameTime, - SBLShufflingList> extendedBehaviours - ) { - extendedBehaviours.shuffle(); - - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (behaviour.tryStart(level, entity, gameTime)) - return behaviour; - } - - return null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/SequentialBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/SequentialBehaviour.java deleted file mode 100644 index c7fabf3fc..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/SequentialBehaviour.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.object.SBLShufflingList; - -/** - * Group behaviour that runs all child behaviours in order, one after another.
    - * Restarts from the first behaviour upon reaching the end of the list - * - * @param The entity - */ -public final class SequentialBehaviour extends GroupBehaviour { - - private Predicate> earlyResetPredicate = behaviour -> false; - - private ExtendedBehaviour lastRun = null; - - public SequentialBehaviour(Pair, Integer>... behaviours) { - super(behaviours); - } - - public SequentialBehaviour(ExtendedBehaviour... behaviours) { - super(behaviours); - } - - /** - * Adds an early short-circuit predicate to reset back to the start of the child behaviours at any time - */ - public SequentialBehaviour resetIf(Predicate> predicate) { - this.earlyResetPredicate = predicate; - - return this; - } - - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour( - ServerLevel level, - E entity, - long gameTime, - SBLShufflingList> extendedBehaviours - ) { - boolean pickNext = this.lastRun == null; - - if (this.lastRun != null && this.earlyResetPredicate.test(this.lastRun)) { - pickNext = true; - this.lastRun = null; - } - - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (pickNext) { - if (behaviour.tryStart(level, entity, gameTime)) { - this.lastRun = behaviour; - - return behaviour; - } - - return null; - } - - if (behaviour == this.lastRun) - pickNext = true; - } - - this.lastRun = null; - - return null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableMeleeAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableMeleeAttack.java deleted file mode 100644 index ecc824a50..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableMeleeAttack.java +++ /dev/null @@ -1,102 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.Function; - -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Extended behaviour for melee attacking. Natively supports animation hit delays or other delays.
    - * Defaults: - *
      - *
    • 20 tick attack interval
    • - *
    - * - * @param The entity - */ -public class AnimatableMeleeAttack extends DelayedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), - Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT) - ); - - protected Function attackIntervalSupplier = entity -> 20; - - @Nullable - protected LivingEntity target = null; - - public AnimatableMeleeAttack(int delayTicks) { - super(delayTicks); - } - - /** - * Set the time between attacks. - * - * @param supplier The tick value provider - * @return this - */ - public AnimatableMeleeAttack attackInterval(Function supplier) { - this.attackIntervalSupplier = supplier; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.target = BrainUtils.getTargetOfEntity(entity); - - return entity.getSensing().hasLineOfSight(this.target) && entity.isWithinMeleeAttackRange(this.target); - } - - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); - BehaviorUtils.lookAtEntity(entity, this.target); - } - - @Override - protected void stop(E entity) { - this.target = null; - } - - @Override - protected void doDelayedAction(E entity) { - BrainUtils.setForgettableMemory( - entity, - MemoryModuleType.ATTACK_COOLING_DOWN, - true, - this.attackIntervalSupplier.apply(entity) - ); - - if (this.target == null) - return; - - if (!entity.getSensing().hasLineOfSight(this.target) || !entity.isWithinMeleeAttackRange(this.target)) - return; - - entity.doHurtTarget(this.target); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableRangedAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableRangedAttack.java deleted file mode 100644 index 340a5ac28..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableRangedAttack.java +++ /dev/null @@ -1,120 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Difficulty; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.monster.RangedAttackMob; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.Function; - -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Extended behaviour for ranged attacking. Natively supports animation hit delays or other delays. Defaults: - *
      - *
    • 40-tick firing interval, decreased to 20 ticks when on {@link Difficulty Hard Difficulty}
    • - *
    • 16-block firing radius
    • - *
    - * - * @param - */ -public class AnimatableRangedAttack extends DelayedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), - Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT) - ); - - protected Function attackIntervalSupplier = entity -> entity.level().getDifficulty() == Difficulty.HARD - ? 20 - : 40; - - protected float attackRadius; - - @Nullable - protected LivingEntity target = null; - - public AnimatableRangedAttack(int delayTicks) { - super(delayTicks); - - attackRadius(16); - } - - /** - * Set the time between attacks. - * - * @param supplier The tick value provider - * @return this - */ - public AnimatableRangedAttack attackInterval(Function supplier) { - this.attackIntervalSupplier = supplier; - - return this; - } - - /** - * Set the radius in blocks that the entity should be able to fire on targets. - * - * @param radius The radius, in blocks - * @return this - */ - public AnimatableRangedAttack attackRadius(float radius) { - this.attackRadius = radius * radius; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.target = BrainUtils.getTargetOfEntity(entity); - - return BrainUtils.canSee(entity, this.target) && entity.distanceToSqr(this.target) <= this.attackRadius; - } - - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); - BehaviorUtils.lookAtEntity(entity, this.target); - } - - @Override - protected void stop(E entity) { - this.target = null; - } - - @Override - protected void doDelayedAction(E entity) { - if (this.target == null) - return; - - if (!BrainUtils.canSee(entity, this.target) || entity.distanceToSqr(this.target) > this.attackRadius) - return; - - entity.performRangedAttack(this.target, 1); - BrainUtils.setForgettableMemory( - entity, - MemoryModuleType.ATTACK_COOLING_DOWN, - true, - this.attackIntervalSupplier.apply(entity) - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/BowAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/BowAttack.java deleted file mode 100644 index 9aec7a803..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/BowAttack.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; - -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.monster.RangedAttackMob; -import net.minecraft.world.entity.projectile.ProjectileUtil; -import net.minecraft.world.item.BowItem; -import net.minecraft.world.item.Items; - -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Extended behaviour for charging and firing a {@link BowItem bow}. - * - * @param - */ -public class BowAttack extends AnimatableRangedAttack { - - public BowAttack(int delayTicks) { - super(delayTicks); - } - - @Override - protected void start(E entity) { - BehaviorUtils.lookAtEntity(entity, this.target); - entity.startUsingItem(ProjectileUtil.getWeaponHoldingHand(entity, Items.BOW)); - } - - @Override - protected void doDelayedAction(E entity) { - if (this.target == null) - return; - - if (!BrainUtils.canSee(entity, this.target) || entity.distanceToSqr(this.target) > this.attackRadius) - return; - - entity.performRangedAttack(this.target, BowItem.getPowerForTime(entity.getTicksUsingItem())); - entity.stopUsingItem(); - BrainUtils.setForgettableMemory( - entity, - MemoryModuleType.ATTACK_COOLING_DOWN, - true, - this.attackIntervalSupplier.apply(entity) - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessAttack.java deleted file mode 100644 index e24c395f8..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessAttack.java +++ /dev/null @@ -1,124 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Attack behaviour that doesn't require line of sight or proximity to target, or to even have a target at all. This is - * useful for special attacks.
    - * Set the actual condition for activation via {@link ExtendedBehaviour#startCondition(Predicate)} - * - * @param The entity - */ -public class ConditionlessAttack extends DelayedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT) - ); - - protected Function attackIntervalSupplier = entity -> 20; - - protected boolean requireTarget = false; - - protected Consumer effect = entity -> {}; - - @Nullable - protected LivingEntity target = null; - - public ConditionlessAttack(int delayTicks) { - super(delayTicks); - } - - /** - * Set the time between attacks. - * - * @param supplier The tick value provider - * @return this - */ - public ConditionlessAttack attackInterval(Function supplier) { - this.attackIntervalSupplier = supplier; - - return this; - } - - /** - * Set that the attack requires that the entity have an attack target set to activate. - * - * @return this - */ - public ConditionlessAttack requiresTarget() { - this.requireTarget = true; - - return this; - } - - /** - * Set the callback for the actual attack when the delay time has elapsed - * - * @param consumer The callback - * @return this - */ - public ConditionlessAttack attack(Consumer consumer) { - this.effect = consumer; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!this.requireTarget) - return true; - - this.target = BrainUtils.getTargetOfEntity(entity); - - return this.target != null; - } - - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); - - if (this.requireTarget) - BehaviorUtils.lookAtEntity(entity, this.target); - } - - @Override - protected void doDelayedAction(E entity) { - if (this.requireTarget && this.target == null) - return; - - this.effect.accept(entity); - BrainUtils.setForgettableMemory( - entity, - MemoryModuleType.ATTACK_COOLING_DOWN, - true, - this.attackIntervalSupplier.apply(entity) - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessHeldAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessHeldAttack.java deleted file mode 100644 index e091eeec8..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessHeldAttack.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.behaviour.HeldBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Attack behaviour for held attacks that doesn't require line of sight or proximity to target, or to even have a target - * at all. This is useful for special attacks.
    - * Set the actual condition for activation via - * {@link mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour#startCondition - * ExtendedBehaviour.startCondition} - * - * @param The entity - */ -public class ConditionlessHeldAttack extends HeldBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT) - ); - - protected boolean requireTarget = false; - - @Nullable - protected LivingEntity target = null; - - /** - * Set that the attack requires that the entity have an attack target set to activate. - * - * @return this - */ - public ConditionlessHeldAttack requiresTarget() { - this.requireTarget = true; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!this.requireTarget) - return true; - - this.target = BrainUtils.getTargetOfEntity(entity); - - return this.target != null; - } - - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); - - if (this.requireTarget) - BehaviorUtils.lookAtEntity(entity, this.target); - } - - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - super.stop(level, entity, gameTime); - - this.target = null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtAttackTarget.java deleted file mode 100644 index 0f67ce298..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtAttackTarget.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.look; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Set the {@link MemoryModuleType#LOOK_TARGET} of the brain owner to the current - * {@link MemoryModuleType#ATTACK_TARGET}, replacing the existing look target.
    - * This is mostly superceded by - * {@link mod.azure.azurelib.sblforked.api.core.behaviour.custom.path.SetWalkTargetToAttackTarget - * SetWalkTargetToAttackTarget}, but can be useful if you want the brain owner to look at the target without pathing to - * it - * - * @param The entity - */ -public class LookAtAttackTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), - Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED) - ); - - private LivingEntity target = null; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.target = BrainUtils.getTargetOfEntity(entity); - - return !(BrainUtils.getMemory(entity, MemoryModuleType.LOOK_TARGET) instanceof EntityTracker entityTracker) - || entityTracker.getEntity() != this.target; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(this.target, true)); - } - - @Override - protected void stop(E entity) { - this.target = null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtTarget.java deleted file mode 100644 index 23b9e90c3..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtTarget.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.look; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Look at the look target for as long as it is present - * - * @param The entity - */ -public class LookAtTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_PRESENT) - ); - - public LookAtTarget() { - noTimeout(); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.LOOK_TARGET); - } - - @Override - protected void tick(E entity) { - BrainUtils.withMemory( - entity, - MemoryModuleType.LOOK_TARGET, - target -> entity.getLookControl().setLookAt(target.currentPosition()) - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/AvoidSun.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/AvoidSun.java deleted file mode 100644 index 4be6e7ff3..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/AvoidSun.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -/** - * Avoid the sun if not wearing a hat - * - * @param The entity - */ -public class AvoidSun extends ExtendedBehaviour { - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return level.isDay() && entity.getItemBySlot(EquipmentSlot.HEAD).isEmpty() && entity - .getNavigation() instanceof GroundPathNavigation; - } - - @Override - protected void start(E entity) { - ((GroundPathNavigation) entity.getNavigation()).setAvoidSun(true); - } - - @Override - protected void stop(E entity) { - if (entity.getNavigation() instanceof GroundPathNavigation groundNavigation) - groundNavigation.setAvoidSun(true); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BlockWithShield.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BlockWithShield.java deleted file mode 100644 index cdb4b3ef2..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BlockWithShield.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.item.UseAnim; - -import java.util.List; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -/** - * Makes the entity use (block) using a shield if it's currently in the entity's hands - */ -public class BlockWithShield extends ExtendedBehaviour { - - protected InteractionHand hand = InteractionHand.MAIN_HAND; - - protected Predicate stopCondition = entity -> false; - - /** - * Sets the condition for when the entity should stop blocking.
    - * Deprecated, use {@link ExtendedBehaviour#stopIf} - * - * @param predicate The predicate - * @return this - */ - @Deprecated(forRemoval = true) - public BlockWithShield stopWhen(Predicate predicate) { - this.stopCondition = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (entity.getMainHandItem().getUseAnimation() == UseAnim.BLOCK) { - this.hand = InteractionHand.MAIN_HAND; - - return true; - } else if (entity.getOffhandItem().getUseAnimation() == UseAnim.BLOCK) { - this.hand = InteractionHand.OFF_HAND; - - return true; - } - - return false; - } - - @Override - protected void start(E entity) { - entity.startUsingItem(this.hand); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - if (!entity.isUsingItem()) - return false; - - if (!(entity.getUseItem().getUseAnimation() == UseAnim.BLOCK)) - return false; - - return !this.stopCondition.test(entity); - } - - @Override - protected void stop(E entity) { - if (entity.getUseItem().getUseAnimation() == UseAnim.BLOCK) - entity.stopUsingItem(); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreakBlock.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreakBlock.java deleted file mode 100644 index 1776c6218..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreakBlock.java +++ /dev/null @@ -1,165 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.LevelEvent; -import net.minecraft.world.level.block.state.BlockState; -import org.apache.commons.lang3.function.TriFunction; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.TriPredicate; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Gradually breaks then destroys a block.
    - * Finds blocks based on the {@link SBLMemoryTypes#NEARBY_BLOCKS} memory module.
    - * Defaults: - *
      - *
    • Breaks doors
    • - *
    • Takes 240 ticks to break the block
    • - *
    - */ -public class BreakBlock extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(SBLMemoryTypes.NEARBY_BLOCKS.get(), MemoryStatus.VALUE_PRESENT) - ); - - protected TriPredicate targetBlockPredicate = (entity, pos, state) -> state.is( - BlockTags.DOORS - ); - - protected TriPredicate stopPredicate = (entity, pos, state) -> false; - - protected TriFunction digTimePredicate = (entity, pos, state) -> 240; - - protected BlockPos pos = null; - - protected BlockState state = null; - - protected int timeToBreak = 0; - - protected int breakTime = 0; - - protected int breakProgress = -1; - - /** - * Set the condition for when the entity should stop breaking the block. - * - * @param predicate The predicate - * @return this - */ - public BreakBlock stopBreakingIf(TriPredicate predicate) { - this.stopPredicate = predicate; - - return this; - } - - /** - * Sets the predicate for valid blocks to break. - * - * @param predicate The predicate - * @return this - */ - public BreakBlock forBlocks(TriPredicate predicate) { - this.targetBlockPredicate = predicate; - - return this; - } - - /** - * Determines the amount of time (in ticks) it takes to break the given block. - * - * @param function The function - * @return this - */ - public BreakBlock timeToBreak(TriFunction function) { - this.digTimePredicate = function; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean timedOut(long gameTime) { - return this.breakProgress < 0 && super.timedOut(gameTime); - } - - @Override - protected void stop(E entity) { - entity.level().destroyBlockProgress(entity.getId(), this.pos, -1); - - this.state = null; - this.pos = null; - this.timeToBreak = 0; - this.breakTime = 0; - this.breakProgress = -1; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - for (Pair pair : BrainUtils.getMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get())) { - if (this.targetBlockPredicate.test(entity, pair.getFirst(), pair.getSecond())) { - this.pos = pair.getFirst(); - this.state = pair.getSecond(); - this.timeToBreak = this.digTimePredicate.apply(entity, this.pos, this.state); - - return true; - } - } - - return false; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.breakTime <= this.timeToBreak && this.targetBlockPredicate.test( - entity, - this.pos, - entity.level().getBlockState(this.pos) - ) && !this.stopPredicate.test(entity, this.pos, this.state); - } - - @Override - protected void tick(E entity) { - this.breakTime++; - int progress = (int) (this.breakTime / (float) this.timeToBreak * 10); - - if (progress != this.breakProgress) { - entity.level().destroyBlockProgress(entity.getId(), this.pos, progress); - - this.breakProgress = progress; - } - - if (this.breakTime >= this.timeToBreak) { - entity.level().removeBlock(this.pos, false); - entity.level() - .levelEvent( - LevelEvent.PARTICLES_DESTROY_BLOCK, - this.pos, - Block.getId(entity.level().getBlockState(this.pos)) - ); - - doStop((ServerLevel) entity.level(), entity, entity.level().getGameTime()); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreedWithPartner.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreedWithPartner.java deleted file mode 100644 index dd0920e6c..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreedWithPartner.java +++ /dev/null @@ -1,169 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.animal.Animal; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.ToIntBiFunction; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Functional replacement for vanilla's {@link net.minecraft.world.entity.ai.behavior.AnimalMakeLove AnimalMakeLove}. - *

    - * Makes the entity find, move to, and breed with its target mate, producing offspring. - *

    - * Defaults: - *
      - *
    • 1x walk speed modifier when moving to its breeding partner
    • - *
    • Spend between 3 and 5.5 seconds to create the offspring
    • - *
    - */ -public class BreedWithPartner extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.BREED_TARGET, MemoryStatus.VALUE_ABSENT), - Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT) - ); - - protected BiFunction speedMod = (entity, partner) -> 1f; - - protected ToIntBiFunction closeEnoughDist = (entity, partner) -> 2; - - protected BiFunction breedTime = (entity, partner) -> entity.getRandom().nextInt(60, 110); - - protected BiPredicate partnerPredicate = (entity, partner) -> entity.getType() == partner.getType() - && entity.canMate(partner); - - protected int childBreedTick = -1; - - protected Animal partner = null; - - public BreedWithPartner() { - runFor(entity -> Integer.MAX_VALUE); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the movespeed modifier for the entity when moving to their partner. - * - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public BreedWithPartner speedMod(final BiFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Sets the amount (in blocks) that the animal can be considered 'close enough' to their partner that they can stop - * pathfinding - * - * @param closeEnoughDist The distance function - * @return this - */ - public BreedWithPartner closeEnoughDist(final ToIntBiFunction closeEnoughDist) { - this.closeEnoughDist = closeEnoughDist; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!entity.isInLove()) - return false; - - this.partner = findPartner(entity); - - return this.partner != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.partner != null && this.partner.isAlive() && entity.tickCount <= this.childBreedTick - && BehaviorUtils.entityIsVisible(entity.getBrain(), this.partner) && this.partnerPredicate.test( - entity, - this.partner - ); - } - - @Override - protected void start(E entity) { - this.childBreedTick = entity.tickCount + this.breedTime.apply(entity, this.partner); - - BrainUtils.setMemory(entity, MemoryModuleType.BREED_TARGET, this.partner); - BrainUtils.setMemory(this.partner, MemoryModuleType.BREED_TARGET, entity); - BehaviorUtils.lockGazeAndWalkToEachOther( - entity, - this.partner, - this.speedMod.apply(entity, this.partner), - this.closeEnoughDist.applyAsInt(entity, this.partner) - ); - } - - @Override - protected void tick(E entity) { - BehaviorUtils.lockGazeAndWalkToEachOther( - entity, - this.partner, - this.speedMod.apply(entity, this.partner), - this.closeEnoughDist.applyAsInt(entity, this.partner) - ); - - if (entity.closerThan(this.partner, 3) && entity.tickCount == this.childBreedTick) { - entity.spawnChildFromBreeding((ServerLevel) entity.level(), this.partner); - BrainUtils.clearMemory(entity, MemoryModuleType.BREED_TARGET); - BrainUtils.clearMemory(this.partner, MemoryModuleType.BREED_TARGET); - } - } - - @Override - protected void stop(E entity) { - BrainUtils.clearMemories( - entity, - MemoryModuleType.BREED_TARGET, - MemoryModuleType.LOOK_TARGET, - MemoryModuleType.WALK_TARGET - ); - - if (this.partner != null) - BrainUtils.clearMemories( - this.partner, - MemoryModuleType.BREED_TARGET, - MemoryModuleType.LOOK_TARGET, - MemoryModuleType.WALK_TARGET - ); - - this.childBreedTick = -1; - this.partner = null; - } - - @Nullable - protected Animal findPartner(E entity) { - return BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES) - .findClosest(entity2 -> entity2 instanceof Animal partner && this.partnerPredicate.test(entity, partner)) - .map(Animal.class::cast) - .orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomBehaviour.java deleted file mode 100644 index 163ff75f4..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomBehaviour.java +++ /dev/null @@ -1,53 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -/** - * A behaviour module that invokes a callback.
    - * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth - * implementing into a full behaviour.
    - * Set the condition for running via {@link ExtendedBehaviour#startCondition(Predicate)} - */ -public final class CustomBehaviour extends ExtendedBehaviour { - - private Consumer callback; - - public CustomBehaviour(Consumer callback) { - this.callback = callback; - } - - /** - * Replace the callback function - * - * @return this - */ - public CustomBehaviour callback(Consumer callback) { - this.callback = callback; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected void start(E entity) { - this.callback.accept(entity); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomDelayedBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomDelayedBehaviour.java deleted file mode 100644 index 9e4313394..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomDelayedBehaviour.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -/** - * A behaviour module that acts as a default implementation of {@link DelayedBehaviour}.
    - * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth - * implementing into a full behaviour.
    - * Set the condition for running via {@link ExtendedBehaviour#startCondition(Predicate)} - */ -public final class CustomDelayedBehaviour extends DelayedBehaviour { - - public CustomDelayedBehaviour(int delayTicks) { - super(delayTicks); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomHeldBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomHeldBehaviour.java deleted file mode 100644 index ec506a28c..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomHeldBehaviour.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.api.core.behaviour.HeldBehaviour; - -/** - * A behaviour module that invokes a callback every tick until stopped.
    - * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth - * implementing into a full behaviour.
    - * Set the condition for running via {@link ExtendedBehaviour#startCondition(Predicate)}
    - * Set the condition for stopping via {@link ExtendedBehaviour#stopIf(Predicate)} - */ -public final class CustomHeldBehaviour extends HeldBehaviour { - - private Consumer callback; - - public CustomHeldBehaviour(Consumer callback) { - this.callback = callback; - } - - /** - * Replace the callback function - * - * @return this - */ - public CustomHeldBehaviour callback(Consumer callback) { - this.callback = callback; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected void tick(E entity) { - this.callback.accept(entity); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/HoldItem.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/HoldItem.java deleted file mode 100644 index 0d1fca49f..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/HoldItem.java +++ /dev/null @@ -1,99 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.item.ItemStack; - -import java.util.List; -import java.util.function.BiPredicate; -import java.util.function.Function; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -/** - * Equips the entity with an item in its {@link InteractionHand hand}.
    - * Can be set to an {@link ItemStack#EMPTY empty ItemStack} to act as unequipping.
    - * Defaults: - *
      - *
    • Equips to the main hand
    • - *
    • Deletes the item it was holding prior to equipping the new item
    • - *
    - */ -public class HoldItem extends ExtendedBehaviour { - - protected Function stackFunction = entity -> ItemStack.EMPTY; - - protected Function handDecider = entity -> InteractionHand.MAIN_HAND; - - protected BiPredicate dropItemOnUnequip = (entity, stack) -> false; - - /** - * Sets the function to determine which hand to equip the item in. - * - * @param function The function - * @return this - */ - public HoldItem toHand(Function function) { - this.handDecider = function; - - return this; - } - - /** - * Sets the function to determine the item to equip. - * - * @param function The itemstack function - * @return this - */ - public HoldItem withStack(Function function) { - this.stackFunction = function; - - return this; - } - - /** - * Sets the behaviour to drop the previously equipped item when equipping the new item. - * - * @return this - */ - public HoldItem dropItemOnUnequip() { - return dropItemOnUnequip((entity, stack) -> true); - } - - /** - * Sets the predicate to determine whether the entity should drop the previously equipped item when equipping the - * new item. - * - * @param dropPredicate The predicate - * @return this - */ - public HoldItem dropItemOnUnequip(BiPredicate dropPredicate) { - this.dropItemOnUnequip = dropPredicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected void start(E entity) { - InteractionHand hand = this.handDecider.apply(entity); - ItemStack previousStack = entity.getItemInHand(hand); - - if (this.dropItemOnUnequip.test(entity, previousStack)) - entity.spawnAtLocation(previousStack); - - entity.setItemInHand(hand, this.stackFunction.apply(entity)); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Idle.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Idle.java deleted file mode 100644 index 588bc338c..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Idle.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -/** - * Do nothing at all. - * - * @param The entity - */ -public class Idle extends ExtendedBehaviour { - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return true; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/InvalidateMemory.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/InvalidateMemory.java deleted file mode 100644 index 8f0ae1ed4..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/InvalidateMemory.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Custom behaviour for conditionally invalidating/resetting existing memories.
    - * This allows for custom handling of stored memories, and clearing them at will.
    - *
    - * Invalidates the memory unconditionally once the behaviour runs. Use {@link InvalidateMemory#invalidateIf} and - * {@link ExtendedBehaviour#startCondition} to quantify its operating conditions - * - * @param The brain owner - * @param The data type of the memory - */ -public class InvalidateMemory extends ExtendedBehaviour { - - private List, MemoryStatus>> memoryRequirements; - - protected BiPredicate customPredicate = (entity, target) -> true; - - protected MemoryModuleType memory; - - public InvalidateMemory(MemoryModuleType memory) { - super(); - - this.memory = memory; - this.memoryRequirements = List.of(Pair.of(this.memory, MemoryStatus.VALUE_PRESENT)); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return this.memoryRequirements == null ? List.of() : this.memoryRequirements; - } - - /** - * Sets the {@link MemoryModuleType memory} to check and invalidate. - */ - public InvalidateMemory forMemory(MemoryModuleType memory) { - this.memory = memory; - this.memoryRequirements = List.of(Pair.of(this.memory, MemoryStatus.VALUE_PRESENT)); - - return this; - } - - /** - * Sets a custom predicate to invalidate the memory if none of the previous checks invalidate it first. - */ - public InvalidateMemory invalidateIf(BiPredicate predicate) { - this.customPredicate = predicate; - - return this; - } - - @Override - protected void start(E entity) { - M memory = BrainUtils.getMemory(entity, this.memory); - - if (memory != null && this.customPredicate.test(entity, memory)) - BrainUtils.clearMemory(entity, this.memory); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Panic.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Panic.java deleted file mode 100644 index 398c11925..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Panic.java +++ /dev/null @@ -1,229 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.Object2FloatFunction; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.FluidTags; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Functional equivalent of the goal system's {@link net.minecraft.world.entity.ai.goal.PanicGoal panic goal}.
    - * Rapidly sets a runaway position based on its last damage.
    - * Defaults: - *
      - *
    • 1.25x Speed modifier when panicking
    • - *
    • Panics if freezing, on fire, or was recently hurt by a living entity
    • - *
    • Runs to a nearby location within 5x4 blocks radius
    • - *
    • Panics for a minimum of 5-6 seconds
    • - *
    - * - * @param The entity - */ -public class Panic extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.HURT_BY, MemoryStatus.VALUE_PRESENT), - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.IS_PANICKING, MemoryStatus.REGISTERED) - ); - - protected BiPredicate shouldPanicPredicate = (entity, damageSource) -> entity.isFreezing() - || entity.isOnFire() || damageSource.getEntity() instanceof LivingEntity; - - protected Object2FloatFunction speedMod = entity -> 1.25f; - - protected SquareRadius radius = new SquareRadius(5, 4); - - protected BiFunction panicFor = (entity, damageSource) -> entity.getRandom() - .nextInt(100, 120); - - protected Vec3 targetPos = null; - - protected int panicEndTime = 0; - - public Panic() { - noTimeout(); - } - - /** - * Set a custom predicate for if the entity should panic based on its current conditions. - * - * @param predicate The predicate - * @return this - */ - public Panic panicIf(final BiPredicate predicate) { - this.shouldPanicPredicate = predicate; - - return this; - } - - /** - * Determine the length of time (in ticks) that the entity should panic for once starting - * - * @param function The predicate - * @return this - */ - public Panic panicFor(final BiFunction function) { - this.panicFor = function; - - return this; - } - - /** - * Set the movespeed modifier for the entity when panicking. - * - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public Panic speedMod(final Object2FloatFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Set the radius in which to look for walk positions. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public Panic setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for walk positions. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public Panic setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!this.shouldPanicPredicate.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY))) - return false; - - setPanicTarget(entity); - - return this.targetPos != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return entity.tickCount < this.panicEndTime; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory( - entity, - MemoryModuleType.WALK_TARGET, - new WalkTarget(this.targetPos, this.speedMod.apply(entity), 0) - ); - BrainUtils.setMemory(entity, MemoryModuleType.IS_PANICKING, true); - - this.panicEndTime = entity.tickCount + this.panicFor.apply( - entity, - BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY) - ); - } - - @Override - protected void tick(E entity) { - if (entity.getNavigation().isDone()) { - this.targetPos = null; - setPanicTarget(entity); - - if (this.targetPos != null) { - BrainUtils.clearMemory(entity, MemoryModuleType.PATH); - BrainUtils.setMemory( - entity, - MemoryModuleType.WALK_TARGET, - new WalkTarget(this.targetPos, this.speedMod.apply(entity), 1) - ); - } - } - } - - @Override - protected void stop(E entity) { - this.targetPos = null; - this.panicEndTime = 0; - - BrainUtils.setMemory(entity, MemoryModuleType.IS_PANICKING, false); - } - - @Nullable - protected Vec3 findNearbyWater(E entity) { - final BlockPos pos = entity.blockPosition(); - final Level level = entity.level(); - - return !level.getBlockState(pos).getCollisionShape(level, pos).isEmpty() - ? null - : BlockPos.findClosestMatch( - entity.blockPosition(), - (int) this.radius.xzRadius(), - (int) this.radius.yRadius(), - checkPos -> level.getFluidState(checkPos).is(FluidTags.WATER) - ).map(Vec3::atBottomCenterOf).orElse(null); - } - - protected void setPanicTarget(E entity) { - if (entity.isOnFire()) - this.targetPos = findNearbyWater(entity); - - if (this.targetPos == null) { - final DamageSource lastDamage = BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY); - - if (lastDamage != null && lastDamage.getEntity() instanceof LivingEntity attacker) - this.targetPos = DefaultRandomPos.getPosAway( - entity, - (int) this.radius.xzRadius(), - (int) this.radius.yRadius(), - attacker.position() - ); - - if (this.targetPos == null) - this.targetPos = DefaultRandomPos.getPos( - entity, - (int) this.radius.xzRadius(), - (int) this.radius.yRadius() - ); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/ReactToUnreachableTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/ReactToUnreachableTarget.java deleted file mode 100644 index 2ea8e411e..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/ReactToUnreachableTarget.java +++ /dev/null @@ -1,94 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; -import java.util.function.BiConsumer; -import java.util.function.Function; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Calls a callback when the entity has been obstructed for a given period of time. - * - * @param The entity - */ -public class ReactToUnreachableTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.VALUE_PRESENT), - Pair.of(SBLMemoryTypes.TARGET_UNREACHABLE.get(), MemoryStatus.VALUE_PRESENT) - ); - - protected Function ticksToReact = entity -> 100; - - protected BiConsumer callback = (entity, towering) -> {}; - - protected long reactAtTime = 0; - - /** - * Set the amount of ticks that the target should be unreachable before reacting. - * - * @param ticksToReact The function to provide the time to wait before reacting - * @return this - */ - public ReactToUnreachableTarget timeBeforeReacting(Function ticksToReact) { - this.ticksToReact = ticksToReact; - - return this; - } - - /** - * Set the function to run when the given time has elapsed and the target is still unreachable. - * - * @param callback The function to run - * @return this - */ - public ReactToUnreachableTarget reaction(BiConsumer callback) { - this.callback = callback; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean timedOut(long gameTime) { - return this.reactAtTime == 0 || this.reactAtTime < gameTime; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return hasRequiredMemories(entity); - } - - @Override - protected void start(E entity) { - this.reactAtTime = entity.level().getGameTime() + this.ticksToReact.apply(entity); - } - - @Override - protected void stop(E entity) { - this.reactAtTime = 0; - } - - @Override - protected void tick(E entity) { - if (entity.level().getGameTime() == this.reactAtTime) - this.callback.accept(entity, BrainUtils.getMemory(entity, SBLMemoryTypes.TARGET_UNREACHABLE.get())); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/AvoidEntity.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/AvoidEntity.java deleted file mode 100644 index 99384a7e1..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/AvoidEntity.java +++ /dev/null @@ -1,148 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.phys.Vec3; - -import java.util.List; -import java.util.Optional; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Try to move away from certain entities when they get too close.
    - * Defaults: - *
      - *
    • 3 block minimum distance
    • - *
    • 7 block maximum distance
    • - *
    • 1x move speed modifier
    • - *
    - */ -public class AvoidEntity extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT) - ); - - protected Predicate avoidingPredicate = target -> false; - - protected float noCloserThanSqr = 9f; - - protected float stopAvoidingAfterSqr = 49f; - - protected float speedModifier = 1; - - private Path runPath = null; - - public AvoidEntity() { - noTimeout(); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the minimum distance the target entity should be allowed to come before the entity starts retreating. - * - * @param blocks The distance, in blocks - * @return this - */ - public AvoidEntity noCloserThan(float blocks) { - this.noCloserThanSqr = blocks * blocks; - - return this; - } - - /** - * Set the maximum distance the target entity should be before the entity stops retreating. - * - * @param blocks The distance, in blocks - * @return this - */ - public AvoidEntity stopCaringAfter(float blocks) { - this.stopAvoidingAfterSqr = blocks * blocks; - - return this; - } - - /** - * Sets the predicate for entities to avoid. - * - * @param predicate The predicate - * @return this - */ - public AvoidEntity avoiding(Predicate predicate) { - this.avoidingPredicate = predicate; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is running away. - * - * @param mod The speed multiplier modifier - * @return this - */ - public AvoidEntity speedModifier(float mod) { - this.speedModifier = mod; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - Optional target = BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES) - .findClosest(this.avoidingPredicate); - - if (target.isEmpty()) - return false; - - LivingEntity avoidingEntity = target.get(); - double distToTarget = avoidingEntity.distanceToSqr(entity); - - if (distToTarget > this.noCloserThanSqr) - return false; - - Vec3 runPos = DefaultRandomPos.getPosAway(entity, 16, 7, avoidingEntity.position()); - - if (runPos == null || avoidingEntity.distanceToSqr(runPos.x, runPos.y, runPos.z) < distToTarget) - return false; - - this.runPath = entity.getNavigation().createPath(runPos.x, runPos.y, runPos.z, 0); - - return this.runPath != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return !this.runPath.isDone(); - } - - @Override - protected void start(E entity) { - entity.getNavigation().moveTo(this.runPath, this.speedModifier); - } - - @Override - protected void stop(E entity) { - this.runPath = null; - - entity.getNavigation().setSpeedModifier(1); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/EscapeSun.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/EscapeSun.java deleted file mode 100644 index 71c1f8855..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/EscapeSun.java +++ /dev/null @@ -1,124 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Sets the {@link MemoryModuleType#WALK_TARGET walk target} to a safe position if caught in the sun.
    - * Defaults: - *
      - *
    • Only if not currently fighting something
    • - *
    • Only if already burning from the sun
    • - *
    - * - * @param The entity - */ -public class EscapeSun extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED) - ); - - protected float speedModifier = 1; - - protected Vec3 hidePos = null; - - public EscapeSun() { - noTimeout(); - } - - /** - * Set the movespeed modifier for when the entity tries to escape the sun - * - * @param speedMod The speed modifier - * @return this - */ - public EscapeSun speedModifier(float speedMod) { - this.speedModifier = speedMod; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!level.isDay() || !entity.isOnFire() || !level.canSeeSky(entity.blockPosition())) - return false; - - if (!entity.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) - return false; - - this.hidePos = getHidePos(entity); - - return this.hidePos != null; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.hidePos, this.speedModifier, 0)); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - if (this.hidePos == null) - return false; - - WalkTarget walkTarget = BrainUtils.getMemory(entity, MemoryModuleType.WALK_TARGET); - - if (walkTarget == null) - return false; - - return walkTarget.getTarget().currentBlockPosition().equals(BlockPos.containing(this.hidePos)) && !entity - .getNavigation() - .isDone(); - } - - @Override - protected void stop(E entity) { - this.hidePos = null; - } - - @Nullable - protected Vec3 getHidePos(E entity) { - RandomSource randomsource = entity.getRandom(); - BlockPos entityPos = entity.blockPosition(); - - for (int i = 0; i < 10; ++i) { - BlockPos hidePos = entityPos.offset( - randomsource.nextInt(20) - 10, - randomsource.nextInt(6) - 3, - randomsource.nextInt(20) - 10 - ); - - if (!entity.level().canSeeSky(hidePos) && entity.getWalkTargetValue(hidePos) < 0.0F) - return Vec3.atBottomCenterOf(hidePos); - } - - return null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FleeTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FleeTarget.java deleted file mode 100644 index cbe9b707a..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FleeTarget.java +++ /dev/null @@ -1,111 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.phys.Vec3; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Flee the current attack target.
    - * Defaults: - *
      - *
    • 20 block flee distance
    • - *
    • 1x move speed modifier
    • - *
    - * - * @param The entity - */ -public class FleeTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT) - ); - - protected int fleeDistance = 20; - - protected float speedModifier = 1; - - protected Path runPath = null; - - public FleeTarget() { - noTimeout(); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the maximum distance the entity should try to flee to - * - * @param blocks The distance, in blocks - * @return this - */ - public FleeTarget fleeDistance(int blocks) { - this.fleeDistance = blocks; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is running away. - * - * @param mod The speed multiplier modifier - * @return this - */ - public FleeTarget speedModifier(float mod) { - this.speedModifier = mod; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - double distToTarget = entity.distanceToSqr(target); - Vec3 runPos = DefaultRandomPos.getPosAway(entity, this.fleeDistance, 10, target.position()); - - if (runPos == null || target.distanceToSqr(runPos.x, runPos.y, runPos.z) < distToTarget) - return false; - - this.runPath = entity.getNavigation().createPath(runPos.x, runPos.y, runPos.z, 0); - - return this.runPath != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return entity.getNavigation().getPath() == this.runPath && !entity.getNavigation().isDone(); - } - - @Override - protected void start(E entity) { - entity.getNavigation().moveTo(this.runPath, this.speedModifier); - BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } - - @Override - protected void stop(E entity) { - if (entity.getNavigation().getPath() == this.runPath) - entity.getNavigation().setSpeedModifier(1); - - this.runPath = null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FloatToSurfaceOfFluid.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FloatToSurfaceOfFluid.java deleted file mode 100644 index c5e9fbb2a..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FloatToSurfaceOfFluid.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.FluidTags; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -/** - * Replacement for {@link net.minecraft.world.entity.ai.goal.FloatGoal} or - * {@link net.minecraft.world.entity.ai.behavior.Swim}.
    - * Causes the entity to rise to the surface of water and float at the surface. Defaults: - *
      - *
    • 80% chance per tick to jump
    • - *
    • Applies to water
    • - *
    - */ -public class FloatToSurfaceOfFluid extends ExtendedBehaviour { - - protected float riseChance = 0.8f; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - /** - * Set the chance per tick that the entity will 'jump' in water, rising up towards the surface. - * - * @param chance The chance, between 0 and 1 (inclusive) - * @return this - */ - public FloatToSurfaceOfFluid riseChance(float chance) { - this.riseChance = chance; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return entity.isInWater() && entity.getFluidHeight(FluidTags.WATER) > entity.getFluidJumpThreshold() || entity - .isInLava(); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return checkExtraStartConditions((ServerLevel) entity.level(), entity); - } - - @Override - protected void tick(E entity) { - if (entity.getRandom().nextFloat() < this.riseChance) - entity.getJumpControl().jump(); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowEntity.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowEntity.java deleted file mode 100644 index d069595d2..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowEntity.java +++ /dev/null @@ -1,246 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.PathType; -import net.minecraft.world.level.pathfinder.PathfindingContext; -import net.minecraft.world.phys.Vec3; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.Function; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.RandomUtil; - -/** - * A movement behaviour for automatically following a given entity.
    - * Defaults: - *
      - *
    • Will stop attempting to move closer than 2 blocks from the target
    • - *
    • Won't attempt to follow until the target is more than 10 blocks away
    • - *
    • Won't teleport to the target if it gets too far away
    • - *
    • 1x movespeed modifier for following
    • - *
    - * - * @param The owner of the brain - * @param The minimum common class of the entity expected to be following - */ -public class FollowEntity extends ExtendedBehaviour { - - protected Function followingEntityProvider = entity -> null; - - protected BiFunction teleportDistance = (entity, target) -> Double.MAX_VALUE; - - protected BiFunction followDistMin = (entity, target) -> 4d; - - protected BiFunction speedMod = (entity, target) -> 1f; - - protected float oldWaterPathMalus = 0; - - protected float oldLavaPathMalus = 0; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - /** - * Determines the entity that the brain owner should follow. - * - * @param following The function that provides the entity to follow - * @return this - */ - public FollowEntity following(Function following) { - this.followingEntityProvider = following; - - return this; - } - - /** - * Determines the distance (in blocks) after which the entity should just attempt to teleport closer to the target - * entity - * - * @param distance The function to provide the distance to teleport after - * @return this - */ - public FollowEntity teleportToTargetAfter(double distance) { - return teleportToTargetAfter((entity, target) -> distance); - } - - /** - * Determines the distance (in blocks) after which the entity should just attempt to teleport closer to the target - * entity - * - * @param distanceProvider The function to provide the distance to teleport after - * @return this - */ - public FollowEntity teleportToTargetAfter(BiFunction distanceProvider) { - this.teleportDistance = distanceProvider; - - return this; - } - - /** - * Determines the distance (in blocks) within which the entity will stop pathing and will do other activities - * - * @param distance The distance to stop following within - * @return this - */ - public FollowEntity stopFollowingWithin(double distance) { - return stopFollowingWithin((entity, target) -> distance); - } - - /** - * Determines the distance (in blocks) within which the entity will stop pathing and will do other activities - * - * @param distanceProvider The function to provide the distance to stop following within - * @return this - */ - public FollowEntity stopFollowingWithin(BiFunction distanceProvider) { - this.followDistMin = distanceProvider; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * - * @param modifier The multiplier for movement speed - * @return this - */ - public FollowEntity speedMod(float modifier) { - return speedMod((entity, target) -> modifier); - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * - * @param modifier The multiplier function for movement speed - * @return this - */ - public FollowEntity speedMod(BiFunction modifier) { - this.speedMod = modifier; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - T target = this.followingEntityProvider.apply(entity); - - if (target == null || target.isSpectator()) - return false; - - double minDist = this.followDistMin.apply(entity, target); - - return entity.distanceToSqr(target) > minDist * minDist; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - T target = this.followingEntityProvider.apply(entity); - - if (target == null) - return false; - - double dist = entity.distanceToSqr(target); - double minDist = this.followDistMin.apply(entity, target); - - return dist > minDist * minDist; - } - - @Override - protected void start(E entity) { - T target = this.followingEntityProvider.apply(entity); - double minDist = this.followDistMin.apply(entity, target); - float speedMod = this.speedMod.apply(entity, target); - this.oldWaterPathMalus = entity.getPathfindingMalus(PathType.WATER); - - if (entity.fireImmune()) { - this.oldLavaPathMalus = entity.getPathfindingMalus(PathType.LAVA); - - entity.setPathfindingMalus(PathType.LAVA, 0); - } - - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(target, speedMod, (int) minDist)); - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); - entity.setPathfindingMalus(PathType.WATER, 0); - } - - @Override - protected void stop(E entity) { - entity.setPathfindingMalus(PathType.WATER, this.oldWaterPathMalus); - - if (entity.fireImmune()) - entity.setPathfindingMalus(PathType.LAVA, this.oldLavaPathMalus); - - entity.getNavigation().stop(); - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - - @Override - protected void tick(E entity) { - T target = this.followingEntityProvider.apply(entity); - double teleportDist = this.teleportDistance.apply(entity, target); - - if (entity.distanceToSqr(target) >= teleportDist * teleportDist) - teleportToTarget(entity, target); - } - - protected void teleportToTarget(E entity, T target) { - Level level = entity.level(); - BlockPos entityPos = target.blockPosition(); - - BlockPos pos = RandomUtil.getRandomPositionWithinRange( - entityPos, - 5, - 5, - 5, - 1, - 1, - 1, - true, - level, - 10, - (state, statePos) -> { - PathType pathTypes = entity.getNavigation() - .getNodeEvaluator() - .getPathType( - new PathfindingContext(level, entity), - statePos.getX(), - statePos.getY(), - statePos.getZ() - ); - - if (pathTypes != PathType.WALKABLE) - return false; - - return level.noCollision( - entity, - entity.getBoundingBox().move(Vec3.atBottomCenterOf(statePos).subtract(entity.position())) - ); - } - ); - - if (pos != entityPos) { - entity.moveTo(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, entity.getYRot(), entity.getXRot()); - entity.getNavigation().stop(); - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowOwner.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowOwner.java deleted file mode 100644 index 660308c86..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowOwner.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.TamableAnimal; - -/** - * A movement behaviour for automatically following the owner of a {@link TamableAnimal TameableAnimal}.
    - * - * @param The owner of the brain - */ -public class FollowOwner extends FollowEntity { - - protected LivingEntity owner = null; - - public FollowOwner() { - following(this::getOwner); - teleportToTargetAfter(12); - } - - protected LivingEntity getOwner(E entity) { - if (this.owner == null) - this.owner = entity.getOwner(); - - if (this.owner != null && this.owner.isRemoved()) - this.owner = null; - - return this.owner; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowParent.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowParent.java deleted file mode 100644 index c2f6dbd9c..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowParent.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.AgeableMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A movement behaviour for automatically following the parent of an {@link AgeableMob AgeableMob}. - *

    - * Note that because vanilla animals do not store a reference to their parent or child, by default this behaviour just - * grabs the nearest animal of the same class and presumes it is the parent. - *

    - */ -public class FollowParent extends FollowEntity { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT) - ); - - private BiPredicate parentPredicate = (entity, other) -> entity.getClass() == other.getClass() - && other.getAge() >= 0; - - public FollowParent() { - following(this::getParent); - stopFollowingWithin(2); - } - - /** - * Set the predicate that determines whether a given entity is a suitable 'parent' to follow - */ - public FollowParent parentPredicate(BiPredicate predicate) { - this.parentPredicate = predicate; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return entity.getAge() < 0 && super.checkExtraStartConditions(level, entity); - } - - @Override - public List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Nullable - protected AgeableMob getParent(E entity) { - return BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES) - .findClosest( - other -> other instanceof AgeableMob ageableMob && this.parentPredicate.test(entity, ageableMob) - ) - .map(AgeableMob.class::cast) - .orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowTemptation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowTemptation.java deleted file mode 100644 index c72936619..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowTemptation.java +++ /dev/null @@ -1,176 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.Object2IntFunction; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.entity.animal.Animal; -import net.minecraft.world.entity.player.Player; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * {@link ExtendedBehaviour ExtendedBehaviour} equivalent of vanilla's - * {@link net.minecraft.world.entity.ai.behavior.FollowTemptation FollowTemptation}.
    - * Has the entity follow a relevant temptation target (I.E. a player holding a tempting item).
    - * Will continue running for as long as the entity is being tempted.
    - * Defaults: - *
      - *
    • Follows the temptation target indefinitely
    • - *
    • Will stop following if panicked or if it has an active breed target
    • - *
    • Will not follow a temptation target again for 5 seconds after stopping
    • - *
    • Considers 2.5 blocks 'close enough' for the purposes of following temptation
    • - *
    • 1x speed modifier while following
    • - *
    - */ -public class FollowTemptation extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryStatus.VALUE_ABSENT), - Pair.of(MemoryModuleType.IS_TEMPTED, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.TEMPTING_PLAYER, MemoryStatus.VALUE_PRESENT), - Pair.of(MemoryModuleType.IS_PANICKING, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.BREED_TARGET, MemoryStatus.REGISTERED) - ); - - protected BiFunction speedMod = (entity, temptingPlayer) -> 1f; - - protected BiPredicate shouldFollow = (entity, temptingPlayer) -> (!(entity instanceof Animal animal) - || animal.getAge() == 0) && !BrainUtils.memoryOrDefault(entity, MemoryModuleType.IS_PANICKING, () -> false); - - protected BiFunction closeEnoughWhen = (owner, temptingPlayer) -> 2.5f; - - protected Object2IntFunction temptationCooldown = entity -> 100; - - public FollowTemptation() { - super(); - - this.runFor(entity -> Integer.MAX_VALUE); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the movespeed modifier for the entity when following the tempting player. - * - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public FollowTemptation speedMod(final BiFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Determine whether the entity should follow the tempting player or not - * - * @param predicate The temptation predicate - * @return this - */ - public FollowTemptation followIf(final BiPredicate predicate) { - this.shouldFollow = predicate; - - return this; - } - - /** - * Sets the amount (in blocks) that the mob can be considered 'close enough' to their temptation that they can stop - * pathfinding - * - * @param closeEnoughMod The distance modifier - * @return this - */ - public FollowTemptation closeEnoughDist(final BiFunction closeEnoughMod) { - this.closeEnoughWhen = closeEnoughMod; - - return this; - } - - /** - * Sets the length of time (in ticks) the entity should ignore temptation after having previously been tempted.
    - * NOTE: This could be ignored if the {@link FollowTemptation#followIf} predicate has been overriden - * - * @param cooldownFunction The cooldown function - * @return this - */ - public FollowTemptation temptationCooldown(final Object2IntFunction cooldownFunction) { - this.temptationCooldown = cooldownFunction; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return this.shouldFollow.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER)); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.TEMPTING_PLAYER) && - !BrainUtils.hasMemory(entity, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS) && - !BrainUtils.hasMemory(entity, MemoryModuleType.BREED_TARGET) && - this.shouldFollow.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER)); - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.IS_TEMPTED, true); - } - - @Override - protected void tick(E entity) { - final Player temptingPlayer = BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER); - final float closeEnough = this.closeEnoughWhen.apply(entity, temptingPlayer); - - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(temptingPlayer, true)); - - if (entity.distanceToSqr(temptingPlayer) < closeEnough * closeEnough) { - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } else { - BrainUtils.setMemory( - entity, - MemoryModuleType.WALK_TARGET, - new WalkTarget( - new EntityTracker(temptingPlayer, false), - this.speedMod.apply(entity, temptingPlayer), - (int) closeEnough - ) - ); - } - } - - @Override - protected void stop(E entity) { - final int cooldownTicks = this.temptationCooldown.apply(entity); - - BrainUtils.setForgettableMemory( - entity, - MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, - cooldownTicks, - cooldownTicks - ); - BrainUtils.setMemory(entity, MemoryModuleType.IS_TEMPTED, false); - BrainUtils.clearMemories(entity, MemoryModuleType.WALK_TARGET, MemoryModuleType.LOOK_TARGET); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/MoveToWalkTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/MoveToWalkTarget.java deleted file mode 100644 index 954948eeb..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/MoveToWalkTarget.java +++ /dev/null @@ -1,174 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -public class MoveToWalkTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.PATH, MemoryStatus.VALUE_ABSENT), - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_PRESENT) - ); - - @Nullable - protected Path path; - - @Nullable - protected BlockPos lastTargetPos; - - protected float speedModifier; - - public MoveToWalkTarget() { - runFor(entity -> entity.getRandom().nextInt(100) + 150); - cooldownFor(entity -> entity.getRandom().nextInt(40)); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - WalkTarget walkTarget = BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET); - - if (!hasReachedTarget(entity, walkTarget) && attemptNewPath(entity, walkTarget, false)) { - this.lastTargetPos = walkTarget.getTarget().currentBlockPosition(); - - return true; - } - - BrainUtils.clearMemory(brain, MemoryModuleType.WALK_TARGET); - BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - return false; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - if (this.path == null || this.lastTargetPos == null) - return false; - - if (entity.getNavigation().isDone()) - return false; - - WalkTarget walkTarget = BrainUtils.getMemory(entity, MemoryModuleType.WALK_TARGET); - - return walkTarget != null && !hasReachedTarget(entity, walkTarget); - } - - @Override - protected void start(E entity) { - startOnNewPath(entity); - } - - @Override - protected void tick(E entity) { - Path path = entity.getNavigation().getPath(); - Brain brain = entity.getBrain(); - - if (this.path != path) { - this.path = path; - - BrainUtils.setMemory(brain, MemoryModuleType.PATH, path); - } - - if (path != null && this.lastTargetPos != null) { - WalkTarget walkTarget = BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET); - - if ( - walkTarget.getTarget().currentBlockPosition().distSqr(this.lastTargetPos) > 4 && attemptNewPath( - entity, - walkTarget, - hasReachedTarget(entity, walkTarget) - ) - ) { - this.lastTargetPos = walkTarget.getTarget().currentBlockPosition(); - - startOnNewPath(entity); - } - } - } - - @Override - protected void stop(E entity) { - Brain brain = entity.getBrain(); - - if ( - !entity.getNavigation().isStuck() || !BrainUtils.hasMemory(brain, MemoryModuleType.WALK_TARGET) - || hasReachedTarget(entity, BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET)) - ) - this.cooldownFinishedAt = 0; - - entity.getNavigation().stop(); - BrainUtils.clearMemories(brain, MemoryModuleType.WALK_TARGET, MemoryModuleType.PATH); - - this.path = null; - } - - protected boolean attemptNewPath(E entity, WalkTarget walkTarget, boolean reachedCurrentTarget) { - Brain brain = entity.getBrain(); - BlockPos pos = walkTarget.getTarget().currentBlockPosition(); - this.path = entity.getNavigation().createPath(pos, 0); - this.speedModifier = walkTarget.getSpeedModifier(); - - if (reachedCurrentTarget) { - BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - return false; - } - - if (this.path != null && this.path.canReach()) { - BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - } else { - BrainUtils.setMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, entity.level().getGameTime()); - } - - if (this.path != null) - return true; - - Vec3 newTargetPos = DefaultRandomPos.getPosTowards(entity, 10, 7, Vec3.atBottomCenterOf(pos), Mth.HALF_PI); - - if (newTargetPos != null) { - this.path = entity.getNavigation().createPath(newTargetPos.x(), newTargetPos.y(), newTargetPos.z(), 0); - - return this.path != null; - } - - return false; - } - - protected boolean hasReachedTarget(E entity, WalkTarget target) { - return target.getTarget().currentBlockPosition().distManhattan(entity.blockPosition()) <= target - .getCloseEnoughDist(); - } - - protected void startOnNewPath(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.PATH, this.path); - entity.getNavigation().moveTo(this.path, this.speedModifier); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StayWithinDistanceOfAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StayWithinDistanceOfAttackTarget.java deleted file mode 100644 index 67574a566..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StayWithinDistanceOfAttackTarget.java +++ /dev/null @@ -1,176 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; -import net.minecraft.world.entity.ai.navigation.PathNavigation; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.phys.Vec3; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Movement behaviour to handle proximal strafing. Will run away if too close, or run towards if too far.
    - * Useful for ranged attackers.
    - * Defaults: - *
      - *
    • Continues strafing until the target is no longer in memory
    • - *
    • Stays between 5 and 20 blocks of the target
    • - *
    • Normal strafing speed
    • - *
    • 30% speed boost to repositioning
    • - *
    - * - * @param The entity - */ -public class StayWithinDistanceOfAttackTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) - ); - - protected BiFunction distMax = (entity, target) -> 20f; - - protected BiFunction distMin = (entity, target) -> 5f; - - protected Predicate stopWhen = entity -> false; - - protected float speedMod = 1; - - protected float repositionSpeedMod = 1.3f; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set how far the entity should attempt to stay away from the target at a minimum. - * - * @param distance The distance, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget minDistance(float distance) { - return minDistance((entity, target) -> distance); - } - - /** - * Set how far the entity should attempt to stay away from the target at a minimum. - * - * @param distance The distance function, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget minDistance(BiFunction distance) { - this.distMin = distance; - - return this; - } - - /** - * Set how far the entity should attempt to stay away from the target at most. - * - * @param distance The distance, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget maxDistance(float distance) { - return maxDistance((entity, target) -> distance); - } - - /** - * Set how far the entity should attempt to stay away from the target at most. - * - * @param distance The distance function, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget maxDistance(BiFunction distance) { - this.distMax = distance; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * - * @param modifier The multiplier for movement speed - * @return this - */ - public StayWithinDistanceOfAttackTarget speedMod(float modifier) { - this.speedMod = modifier; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is repositioning due to being too close or too far. - * - * @param modifier The multiplier for movement speed - * @return this - */ - public StayWithinDistanceOfAttackTarget repositionSpeedMod(float modifier) { - this.speedMod = modifier; - - return this; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.ATTACK_TARGET) && !this.stopWhen.test(entity); - } - - @Override - protected void tick(E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - double distanceToTarget = target.distanceToSqr(entity); - float maxDist = this.distMax.apply(entity, target); - double maxDistSq = Math.pow(maxDist, 2); - double minDistSq = Math.pow(this.distMin.apply(entity, target), 2); - PathNavigation navigation = entity.getNavigation(); - - if (distanceToTarget > maxDistSq || !entity.hasLineOfSight(target)) { - if (navigation.isDone()) - navigation.moveTo(target, this.repositionSpeedMod); - - return; - } - - if (distanceToTarget < minDistSq) { - if (navigation.isDone()) { - Vec3 runPos = DefaultRandomPos.getPosAway(entity, (int) maxDist, 5, target.position()); - - if (runPos != null) - navigation.moveTo(navigation.createPath(BlockPos.containing(runPos), 1), this.repositionSpeedMod); - } - - return; - } - - if (navigation instanceof GroundPathNavigation) - navigation.stop(); - - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); - - if (distanceToTarget > maxDistSq * 0.5f) { - entity.lookAt(target, 30, 30); - entity.getMoveControl().strafe(0.5f * this.speedMod, 0); - } else if (distanceToTarget < minDistSq * 3f) { - entity.lookAt(target, 30, 30); - entity.getMoveControl().strafe(-0.5f * this.speedMod, 0); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StrafeTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StrafeTarget.java deleted file mode 100644 index ced37a23b..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StrafeTarget.java +++ /dev/null @@ -1,129 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Movement behaviour to handle strafing.
    - * Defaults: - *
      - *
    • Continues strafing until the target is no longer in memory
    • - *
    - * - * @param The entity - */ -public class StrafeTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) - ); - - protected boolean strafingLaterally = false; - - protected boolean strafingBack = false; - - protected int strafeCounter = -1; - - protected float strafeDistanceSqr = 244; - - protected Predicate stopStrafingWhen = entity -> false; - - protected float speedMod = 1; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set a custom condition for when the strafing should end. - * - * @param predicate The predicate - * @return this - */ - public StrafeTarget stopStrafingWhen(Predicate predicate) { - this.stopStrafingWhen = predicate; - - return this; - } - - /** - * Set how far the entity should attempt to stay away from the target whilst strafing. - * - * @param distance The distance, in blocks - * @return this - */ - public StrafeTarget strafeDistance(float distance) { - this.strafeDistanceSqr = distance * distance; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * - * @param modifier The multiplier for movement speed - * @return this - */ - public StrafeTarget speedMod(float modifier) { - this.speedMod = modifier; - - return this; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.ATTACK_TARGET) && !this.stopStrafingWhen.test(entity); - } - - @Override - protected void tick(E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - double distanceToTarget = target.distanceToSqr(entity); - - if (distanceToTarget <= this.strafeDistanceSqr) { - entity.getNavigation().stop(); - this.strafeCounter++; - } else { - entity.getNavigation().moveTo(target, this.speedMod); - this.strafeCounter = -1; - } - - if (this.strafeCounter >= 20) { - if (entity.getRandom().nextFloat() < 0.3) - this.strafingLaterally = !this.strafingLaterally; - - if (entity.getRandom().nextFloat() < 0.3) - this.strafingBack = !this.strafingBack; - - this.strafeCounter = 0; - } - - if (this.strafeCounter > -1) { - if (distanceToTarget > this.strafeDistanceSqr * 0.75f) { - this.strafingBack = false; - } else if (distanceToTarget < this.strafeDistanceSqr * 0.25f) { - this.strafingBack = true; - } - - entity.lookAt(target, 30, 30); - entity.getMoveControl().strafe(this.strafingBack ? -0.5f : 0.5f, this.strafingLaterally ? 0.5f : -0.5f); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/WalkOrRunToWalkTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/WalkOrRunToWalkTarget.java deleted file mode 100644 index acd8fdf33..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/WalkOrRunToWalkTarget.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; - -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Extension of MoveToWalkTarget, but auto-marking the sprinting flag depending on the movespeed. This can be useful for - * using sprint animations on the client. - * - * @param - */ -public class WalkOrRunToWalkTarget extends MoveToWalkTarget { - - @Override - protected void startOnNewPath(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.PATH, this.path); - - if (entity.getNavigation().moveTo(this.path, this.speedModifier)) - entity.setSharedFlag(3, this.speedModifier > 1); - } - - @Override - protected void stop(E entity) { - super.stop(entity); - - entity.setSharedFlag(3, false); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SeekRandomNearbyPosition.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SeekRandomNearbyPosition.java deleted file mode 100644 index 78f6a7c8c..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SeekRandomNearbyPosition.java +++ /dev/null @@ -1,177 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.Function; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.RandomUtil; - -/** - * Walk target class that finds a random position nearby and sets it as the walk target if applicable.
    - * Useful for finding quick alternate paths for specific purposes.
    - * Defaults: - *
      - *
    • 10x6 block search radius
    • - *
    • 1x Movespeed modifier
    • - *
    • 10 Attempts at finding a position before giving up
    • - *
    - * - * @param The entity - */ -public class SeekRandomNearbyPosition extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORIES = ObjectArrayList.of( - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) - ); - - protected BiPredicate validPosition = (entity, state) -> false; - - protected BiFunction speedModifier = (entity, targetPos) -> 1f; - - protected SquareRadius radius = new SquareRadius(10, 6); - - protected Function tries = entity -> 10; - - protected Vec3 targetPos = null; - - /** - * Set the radius in which to look for walk positions. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public SeekRandomNearbyPosition setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for walk positions. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SeekRandomNearbyPosition setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - /** - * Set the movespeed modifier for the path when chosen. - * - * @param modifier The movespeed modifier/multiplier - * @return this - */ - public SeekRandomNearbyPosition speedModifier(float modifier) { - return speedModifier((entity, targetPos) -> modifier); - } - - /** - * Set the movespeed modifier for the path when chosen. - * - * @param function The movespeed modifier/multiplier function - * @return this - */ - public SeekRandomNearbyPosition speedModifier(BiFunction function) { - this.speedModifier = function; - - return this; - } - - /** - * Sets the number of positions to check before giving up on finding a valid target. - * - * @param attempts The number of attempts - * @return this - */ - public SeekRandomNearbyPosition attempts(int attempts) { - return attempts(entity -> attempts); - } - - /** - * Sets the number of positions to check before giving up on finding a valid target. - * - * @param function The attempts function - * @return this - */ - public SeekRandomNearbyPosition attempts(Function function) { - this.tries = function; - - return this; - } - - /** - * Set the predicate that determines the validity of positions when searching - * - * @param predicate The predicate - * @return this - */ - public SeekRandomNearbyPosition validPositions(BiPredicate predicate) { - this.validPosition = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORIES; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.targetPos = getTargetPos(entity); - - return this.targetPos != null; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory( - entity, - MemoryModuleType.WALK_TARGET, - new WalkTarget(this.targetPos, this.speedModifier.apply(entity, this.targetPos), 0) - ); - } - - @Nullable - protected Vec3 getTargetPos(E entity) { - BlockPos entityPos = entity.blockPosition(); - BlockPos targetPos = RandomUtil.getRandomPositionWithinRange( - entityPos, - (int) this.radius.xzRadius(), - (int) this.radius.yRadius(), - (int) this.radius.xzRadius(), - 0, - 0, - 0, - false, - entity.level(), - 10, - (state, pos) -> this.validPosition.test(entity, state) - ); - - return targetPos == entityPos ? null : Vec3.atBottomCenterOf(targetPos); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomFlyingTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomFlyingTarget.java deleted file mode 100644 index 316146806..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomFlyingTarget.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import net.minecraft.util.Mth; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.util.AirAndWaterRandomPos; -import net.minecraft.world.entity.ai.util.HoverRandomPos; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -import java.util.function.ToIntFunction; - -/** - * Extension of {@link SetRandomHoverTarget}, with a configurable weight to allow for more 'flying'-like movement - *

    - * Additionally expands the vertical path search radius to 10, over the default of 7 - *

    - */ -public class SetRandomFlyingTarget extends SetRandomHoverTarget { - - protected ToIntFunction verticalWeight = entity -> -2; - - public SetRandomFlyingTarget() { - setRadius(10, 10); - } - - /** - * Sets the function that determines a vertical position offset for target positions.
    - * Flight patterns will tend towards this direction, with bigger values pulling more strongly - * - * @param function The function - * @return this - */ - public SetRandomFlyingTarget verticalWeight(ToIntFunction function) { - this.verticalWeight = function; - - return this; - } - - @Nullable - @Override - protected Vec3 getTargetPos(E entity) { - Vec3 entityFacing = entity.getViewVector(0); - Vec3 hoverPos = HoverRandomPos.getPos( - entity, - (int) (Math.ceil(this.radius.xzRadius())), - (int) Math.ceil(this.radius.yRadius()), - entityFacing.x, - entityFacing.z, - Mth.HALF_PI, - 3, - 1 - ); - - if (hoverPos != null) - return hoverPos; - - return AirAndWaterRandomPos.getPos( - entity, - (int) (Math.ceil(this.radius.xzRadius())), - (int) Math.ceil(this.radius.yRadius()), - this.verticalWeight.applyAsInt(entity), - entityFacing.x, - entityFacing.z, - Mth.HALF_PI - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomHoverTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomHoverTarget.java deleted file mode 100644 index 9893c87e4..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomHoverTarget.java +++ /dev/null @@ -1,159 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.entity.ai.util.AirAndWaterRandomPos; -import net.minecraft.world.entity.ai.util.HoverRandomPos; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Set a random position to fly to, taking into account the entity's current heading.
    - * Keeps the entity roughly near ground level, encouraging hover-flight rather than floating off into the sky.
    - * Defaults: - *
      - *
    • 1x movespeed modifier
    • - *
    • 10-block lateral radius
    • - *
    • 7-block vertical radius
    • - *
    - * - * @param - */ -public class SetRandomHoverTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) - ); - - protected BiFunction speedModifier = (entity, targetPos) -> 1f; - - protected SquareRadius radius = new SquareRadius(10, 7); - - protected BiPredicate positionPredicate = (entity, pos) -> true; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the radius in which to look for flight positions. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public SetRandomHoverTarget setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for flight positions. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SetRandomHoverTarget setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - /** - * Set the movespeed modifier for the path when chosen. - * - * @param modifier The movespeed modifier/multiplier - * @return this - */ - public SetRandomHoverTarget speedModifier(float modifier) { - return speedModifier((entity, targetPos) -> modifier); - } - - /** - * Set the movespeed modifier for the path when chosen. - * - * @param function The movespeed modifier/multiplier function - * @return this - */ - public SetRandomHoverTarget speedModifier(BiFunction function) { - this.speedModifier = function; - - return this; - } - - /** - * Sets a predicate to check whether the target movement position is valid or not - * - * @param predicate The predicate - * @return this - */ - public SetRandomHoverTarget flightTargetPredicate(BiPredicate predicate) { - this.positionPredicate = predicate; - - return this; - } - - @Override - protected void start(E entity) { - Vec3 targetPos = getTargetPos(entity); - - if (!this.positionPredicate.test(entity, targetPos)) - targetPos = null; - - if (targetPos == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } else { - BrainUtils.setMemory( - entity, - MemoryModuleType.WALK_TARGET, - new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0) - ); - } - } - - @Nullable - protected Vec3 getTargetPos(E entity) { - Vec3 entityFacing = entity.getViewVector(0); - Vec3 hoverPos = HoverRandomPos.getPos( - entity, - (int) (Math.ceil(this.radius.xzRadius())), - (int) Math.ceil(this.radius.yRadius()), - entityFacing.x, - entityFacing.z, - Mth.HALF_PI, - 3, - 1 - ); - - if (hoverPos != null) - return hoverPos; - - return AirAndWaterRandomPos.getPos( - entity, - (int) (Math.ceil(this.radius.xzRadius())), - (int) Math.ceil(this.radius.yRadius()), - -2, - entityFacing.x, - entityFacing.z, - Mth.HALF_PI - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomSwimTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomSwimTarget.java deleted file mode 100644 index e579e9ce2..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomSwimTarget.java +++ /dev/null @@ -1,133 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Set a random position to swim to.
    - * Defaults: - *
      - *
    • 1x movespeed modifier
    • - *
    • 10-block lateral radius
    • - *
    • 10-block vertical radius
    • - *
    - * - * @param - */ -public class SetRandomSwimTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) - ); - - protected BiFunction speedModifier = (entity, targetPos) -> 1f; - - protected SquareRadius radius = new SquareRadius(10, 7); - - protected BiPredicate positionPredicate = (entity, pos) -> true; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the radius in which to look for swim positions. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public SetRandomSwimTarget setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for swim positions. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SetRandomSwimTarget setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - /** - * Set the movespeed modifier for the path when chosen. - * - * @param modifier The movespeed modifier/multiplier - * @return this - */ - public SetRandomSwimTarget speedModifier(float modifier) { - return speedModifier((entity, targetPos) -> modifier); - } - - /** - * Set the movespeed modifier for the path when chosen. - * - * @param function The movespeed modifier/multiplier function - * @return this - */ - public SetRandomSwimTarget speedModifier(BiFunction function) { - this.speedModifier = function; - - return this; - } - - /** - * Sets a predicate to check whether the target movement position is valid or not - * - * @param predicate The predicate - * @return this - */ - public SetRandomSwimTarget swimTargetPredicate(BiPredicate predicate) { - this.positionPredicate = predicate; - - return this; - } - - @Override - protected void start(E entity) { - Vec3 targetPos = getTargetPos(entity); - - if (!this.positionPredicate.test(entity, targetPos)) - targetPos = null; - - if (targetPos == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } else { - BrainUtils.setMemory( - entity, - MemoryModuleType.WALK_TARGET, - new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0) - ); - } - } - - @Nullable - protected Vec3 getTargetPos(E entity) { - return BehaviorUtils.getRandomSwimmablePos(entity, (int) this.radius.xzRadius(), (int) this.radius.yRadius()); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomWalkTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomWalkTarget.java deleted file mode 100644 index 561844bdd..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomWalkTarget.java +++ /dev/null @@ -1,164 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.entity.ai.util.LandRandomPos; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Set a random position to walk to.
    - * Defaults: - *
      - *
    • 1x movespeed modifier
    • - *
    • 10-block lateral radius
    • - *
    • 7-block vertical radius
    • - *
    • Avoids walk targets with fluid
    • - *
    - * - * @param - */ -public class SetRandomWalkTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT) - ); - - protected BiFunction speedModifier = (entity, targetPos) -> 1f; - - protected Predicate avoidWaterPredicate = entity -> true; - - protected SquareRadius radius = new SquareRadius(10, 7); - - protected BiPredicate positionPredicate = (entity, pos) -> true; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the radius in which to look for walk positions. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public SetRandomWalkTarget setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for walk positions. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SetRandomWalkTarget setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - /** - * Set the movespeed modifier for the path when chosen. - * - * @param modifier The movespeed modifier/multiplier - * @return this - */ - public SetRandomWalkTarget speedModifier(float modifier) { - return speedModifier((entity, targetPos) -> modifier); - } - - /** - * Set the movespeed modifier for the path when chosen. - * - * @param function The movespeed modifier/multiplier function - * @return this - */ - public SetRandomWalkTarget speedModifier(BiFunction function) { - this.speedModifier = function; - - return this; - } - - /** - * Sets a predicate to check whether the target movement position is valid or not - * - * @param predicate The predicate - * @return this - */ - public SetRandomWalkTarget walkTargetPredicate(BiPredicate predicate) { - this.positionPredicate = predicate; - - return this; - } - - /** - * Sets the behaviour to allow finding of positions that might be in water.
    - * Useful for hybrid or water-based entities. - * - * @return this - */ - public SetRandomWalkTarget dontAvoidWater() { - return avoidWaterWhen(entity -> false); - } - - /** - * Set the predicate to determine when the entity should avoid water walk targets; - * - * @param predicate The predicate - * @return this - */ - public SetRandomWalkTarget avoidWaterWhen(Predicate predicate) { - this.avoidWaterPredicate = predicate; - - return this; - } - - @Override - protected void start(E entity) { - Vec3 targetPos = getTargetPos(entity); - - if (!this.positionPredicate.test(entity, targetPos)) - targetPos = null; - - if (targetPos == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } else { - BrainUtils.setMemory( - entity, - MemoryModuleType.WALK_TARGET, - new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0) - ); - } - } - - @Nullable - protected Vec3 getTargetPos(E entity) { - if (this.avoidWaterPredicate.test(entity)) { - return LandRandomPos.getPos(entity, (int) this.radius.xzRadius(), (int) this.radius.yRadius()); - } else { - return DefaultRandomPos.getPos(entity, (int) this.radius.xzRadius(), (int) this.radius.yRadius()); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToAttackTarget.java deleted file mode 100644 index 52f402ab9..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToAttackTarget.java +++ /dev/null @@ -1,107 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.ToIntBiFunction; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Set the walk target of the entity to its current attack target. - * - * @param The entity - */ -public class SetWalkTargetToAttackTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT) - ); - - @Deprecated(forRemoval = true) - protected float speedModifier = 1; - - protected BiFunction speedMod = (owner, target) -> 1f; - - protected ToIntBiFunction closeEnoughWhen = (owner, target) -> 0; - - /** - * Set the movespeed modifier for the entity when moving to the target. - * - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - @Deprecated(forRemoval = true) - public SetWalkTargetToAttackTarget speedMod(float speedModifier) { - return speedMod((owner, target) -> speedModifier); - } - - /** - * Set the movespeed modifier for the entity when moving to the target. - * - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public SetWalkTargetToAttackTarget speedMod(BiFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Sets the amount (in blocks) that the mob can be considered 'close enough' to their target that they can stop - * pathfinding - * - * @param closeEnoughMod The distance modifier - * @return this - */ - public SetWalkTargetToAttackTarget closeEnoughDist(ToIntBiFunction closeEnoughMod) { - this.closeEnoughWhen = closeEnoughMod; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected void start(E entity) { - Brain brain = entity.getBrain(); - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - - if (entity.getSensing().hasLineOfSight(target) && BehaviorUtils.isWithinAttackRange(entity, target, 1)) { - BrainUtils.clearMemory(brain, MemoryModuleType.WALK_TARGET); - } else { - BrainUtils.setMemory(brain, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); - BrainUtils.setMemory( - brain, - MemoryModuleType.WALK_TARGET, - new WalkTarget( - new EntityTracker(target, false), - this.speedMod.apply(entity, target), - this.closeEnoughWhen.applyAsInt(entity, target) - ) - ); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToBlock.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToBlock.java deleted file mode 100644 index fac1f01ec..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToBlock.java +++ /dev/null @@ -1,118 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.behavior.BlockPosTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Path setting behaviour for walking to/near a block position. - * - * @param The entity - */ -public class SetWalkTargetToBlock extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(SBLMemoryTypes.NEARBY_BLOCKS.get(), MemoryStatus.VALUE_PRESENT) - ); - - protected BiPredicate> predicate = (entity, block) -> true; - - protected BiFunction, Float> speedMod = (owner, pos) -> 1f; - - protected BiFunction, Integer> closeEnoughDist = (entity, pos) -> 2; - - protected Pair target = null; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the predicate to determine whether a given position/state should be the target path - * - * @param predicate The predicate - * @return this - */ - public SetWalkTargetToBlock predicate(final BiPredicate> predicate) { - this.predicate = predicate; - - return this; - } - - /** - * Set the movespeed modifier for the entity when moving to the target. - * - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public SetWalkTargetToBlock speedMod(BiFunction, Float> speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Set the distance (in blocks) that is 'close enough' for the entity to be considered at the target position - * - * @param function The function - * @return this - */ - public SetWalkTargetToBlock closeEnoughWhen(final BiFunction, Integer> function) { - this.closeEnoughDist = function; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - for (Pair position : BrainUtils.getMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get())) { - if (this.predicate.test(entity, position)) { - this.target = position; - - break; - } - } - - return this.target != null; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory( - entity, - MemoryModuleType.WALK_TARGET, - new WalkTarget( - this.target.getFirst(), - this.speedMod.apply(entity, this.target), - this.closeEnoughDist.apply(entity, this.target) - ) - ); - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new BlockPosTracker(this.target.getFirst())); - } - - @Override - protected void stop(E entity) { - this.target = null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/InvalidateAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/InvalidateAttackTarget.java deleted file mode 100644 index bf7192cbc..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/InvalidateAttackTarget.java +++ /dev/null @@ -1,106 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.player.Player; - -import java.util.List; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Invalidates the current {@link MemoryModuleType#ATTACK_TARGET attack target} if the given conditions are met.
    - * Defaults: - *
      - *
    • Will give up trying to path to the target if it hasn't been able to reach it in 200 ticks
    • - *
    • Invalidates the target if it's a creative or spectator mode player
    • - *
    - */ -public class InvalidateAttackTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), - Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.REGISTERED) - ); - - protected BiPredicate customPredicate = (entity, target) -> target instanceof Player pl && (pl - .isCreative() || pl.isSpectator()); - - protected long pathfindingAttentionSpan = 200; - - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Sets a custom predicate to invalidate the attack target if none of the previous checks invalidate it first.
    - * Overrides the default player gamemode check - */ - public InvalidateAttackTarget invalidateIf(BiPredicate predicate) { - this.customPredicate = predicate; - - return this; - } - - /** - * Skips the check to see if the entity has been unable to path to its target for a while - */ - public InvalidateAttackTarget ignoreFailedPathfinding() { - return stopTryingToPathAfter(0); - } - - /** - * Sets the attention span for the brain owner's pathfinding. If the entity has been unable to find a good path to - * the target after this time, it will invalidate the target. - */ - public InvalidateAttackTarget stopTryingToPathAfter(long ticks) { - this.pathfindingAttentionSpan = ticks; - - return this; - } - - @Override - protected void start(E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - - if (target == null) - return; - - if ( - isTargetInvalid(entity, target) || !canAttack(entity, target) || - isTiredOfPathing(entity) || this.customPredicate.test(entity, target) - ) { - BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } - } - - protected boolean isTargetInvalid(E entity, LivingEntity target) { - if (entity.level() != target.level()) - return true; - - return target.isDeadOrDying() || target.isRemoved(); - } - - protected boolean canAttack(E entity, LivingEntity target) { - return entity.canAttack(target); - } - - protected boolean isTiredOfPathing(E entity) { - if (this.pathfindingAttentionSpan <= 0) - return false; - - Long time = BrainUtils.getMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - return time != null && entity.level().getGameTime() - time > this.pathfindingAttentionSpan; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAdditionalAttackTargets.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAdditionalAttackTargets.java deleted file mode 100644 index 11eec504e..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAdditionalAttackTargets.java +++ /dev/null @@ -1,166 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.player.Player; -import org.apache.logging.log4j.util.TriConsumer; - -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.TriPredicate; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Special-case behaviour for setting secondary, tertiary, etc attack targets.
    - * This is useful for entities that concurrently target multiple entities, and use additional memory modules to store - * the additional targets.
    - * Uses {@link MemoryModuleType#NEAREST_PLAYERS} and {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} for its - * retrieval of additional targets.
    - * This behaviour will skip the usual pathing and alerting functionality as it is assumed they will be handled under the - * primary target.
    - *
    - * Defaults:
    - *
      - *
    • Will target any not-invulnerable player
    • - *
    • Avoids setting memories if a previous memory in the list is already set to the same target, and including - * {@link MemoryModuleType#ATTACK_TARGET}
    • - *
    - */ -public class SetAdditionalAttackTargets extends ExtendedBehaviour { - - private final List> targetingMemories = new ObjectArrayList<>(); - - protected TriPredicate, LivingEntity> canAttackPredicate = ( - owner, - memory, - target - ) -> target.isAlive() && target instanceof Player player && !player.getAbilities().invulnerable; - - protected TriConsumer, LivingEntity> targetCallback = ( - owner, - memory, - target - ) -> {}; - - protected boolean avoidDuplicateTargets = true; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - /** - * Set the predicate to determine whether a given entity should be targeted or not. - * - * @param predicate The predicate - * @return this - */ - public SetAdditionalAttackTargets attackablePredicate( - TriPredicate, LivingEntity> predicate - ) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Sets the callback for when a target is being successfully set to a memory. - */ - public SetAdditionalAttackTargets whenTargeting( - TriConsumer, LivingEntity> callback - ) { - this.targetCallback = callback; - - return this; - } - - /** - * Add {@link MemoryModuleType memories} to the list of tertiary memories to set targets for.
    - * This appends to any existing memories already added to this behaviour, and the functionality of this behaviour is - * order-dependent. - */ - public SetAdditionalAttackTargets withMemories(MemoryModuleType... targetMemories) { - this.targetingMemories.addAll(List.of(targetMemories)); - - return this; - } - - /** - * Allow for the tertiary target memories to be set to the same as the previous modules if no new target is - * available - */ - public SetAdditionalAttackTargets allowDuplicateTargeting() { - this.avoidDuplicateTargets = false; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - - for (MemoryModuleType memory : this.targetingMemories) { - if (!BrainUtils.hasMemory(brain, memory)) - return true; - } - - return BrainUtils.hasMemory(brain, MemoryModuleType.NEAREST_PLAYERS) || BrainUtils.hasMemory( - brain, - MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES - ); - } - - @Override - protected void start(E entity) { - Brain brain = entity.getBrain(); - Set targetPool = new ObjectOpenHashSet<>(); - - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_PLAYERS, targetPool::addAll); - BrainUtils.withMemory( - brain, - MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, - memory -> memory.findAll(target -> true).forEach(targetPool::add) - ); - - if (targetPool.isEmpty()) - return; - - for (MemoryModuleType memory : this.targetingMemories) { - LivingEntity target = BrainUtils.getMemory(brain, memory); - - if (target == null) { - LivingEntity newTarget = null; - - for (Iterator iterator = targetPool.iterator(); iterator.hasNext(); newTarget = null) { - newTarget = iterator.next(); - - if (this.canAttackPredicate.test(entity, memory, newTarget)) { - BrainUtils.setMemory(brain, (MemoryModuleType) memory, newTarget); - this.targetCallback.accept(entity, memory, newTarget); - iterator.remove(); - - break; - } - } - - if (newTarget != null && !this.avoidDuplicateTargets) - targetPool.add(newTarget); - } - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAttackTarget.java deleted file mode 100644 index ec9f29572..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAttackTarget.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; -import java.util.function.Function; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Sets the attack target of the entity if one is available.
    - * Defaults: - *
      - *
    • Will target anything set as the {@link MemoryModuleType#NEAREST_ATTACKABLE} memory
    • - *
    - * - * @see net.minecraft.world.entity.ai.behavior.StartAttacking - */ -public class SetAttackTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), - Pair.of(MemoryModuleType.NEAREST_ATTACKABLE, MemoryStatus.VALUE_PRESENT) - ); - - private static final List, MemoryStatus>> CUSTOM_TARGETING_REQUIREMENTS = ObjectArrayList - .of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected final boolean usingNearestAttackable; - - protected Predicate canAttackPredicate = entity -> true; - - protected Function targetFinder = entity -> BrainUtils.getMemory( - entity, - MemoryModuleType.NEAREST_ATTACKABLE - ); - - public SetAttackTarget() { - this(true); - } - - public SetAttackTarget(boolean usingNearestAttackable) { - this.usingNearestAttackable = usingNearestAttackable; - } - - /** - * Set the predicate to determine whether the entity is ready to attack or not. - * - * @param predicate The predicate - * @return this - */ - public SetAttackTarget attackPredicate(Predicate predicate) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Set the target finding function. If replacing the {@link MemoryModuleType#NEAREST_ATTACKABLE} memory retrieval, - * set false in the constructor of the behaviour. - * - * @param targetFindingFunction The function - * @return this - */ - public SetAttackTarget targetFinder(Function targetFindingFunction) { - this.targetFinder = targetFindingFunction; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return this.usingNearestAttackable ? MEMORY_REQUIREMENTS : CUSTOM_TARGETING_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return this.canAttackPredicate.test(entity); - } - - @Override - protected void start(E entity) { - LivingEntity target = this.targetFinder.apply(entity); - - if (target == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } else { - BrainUtils.setMemory(entity, MemoryModuleType.ATTACK_TARGET, target); - BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetPlayerLookTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetPlayerLookTarget.java deleted file mode 100644 index 59348cb7c..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetPlayerLookTarget.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.player.Player; - -import java.util.List; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Set the {@link MemoryModuleType#LOOK_TARGET} of the brain owner from {@link MemoryModuleType#NEAREST_PLAYERS} - * - * @param The entity - */ -public class SetPlayerLookTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT), - Pair.of(MemoryModuleType.NEAREST_PLAYERS, MemoryStatus.VALUE_PRESENT) - ); - - protected Predicate predicate = pl -> true; - - protected Player target = null; - - /** - * Set the predicate for the player to look at. - * - * @param predicate The predicate - * @return this - */ - public SetPlayerLookTarget predicate(Predicate predicate) { - this.predicate = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - for (Player player : BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_PLAYERS)) { - if (this.predicate.test(player)) { - this.target = player; - - break; - } - } - - return this.target != null; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(this.target, true)); - } - - @Override - protected void stop(E entity) { - this.target = null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRandomLookTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRandomLookTarget.java deleted file mode 100644 index 652997b99..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRandomLookTarget.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.Mth; -import net.minecraft.util.valueproviders.ConstantFloat; -import net.minecraft.util.valueproviders.FloatProvider; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; - -import java.util.List; -import java.util.function.Function; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.FreePositionTracker; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Set the look target to a random nearby position - * - * @param The entity - */ -public class SetRandomLookTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORIES = ObjectArrayList.of( - Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT) - ); - - protected FloatProvider runChance = ConstantFloat.of(0.02f); - - protected Function lookTime = entity -> entity.getRandom().nextInt(20) + 20; - - /** - * Set the value provider for the chance of the look target being set. - * - * @param chance The float provider - * @return this - */ - public SetRandomLookTarget lookChance(FloatProvider chance) { - this.runChance = chance; - - return this; - } - - /** - * Set the value provider for how long the entity's look target should be set for - * - * @param function The tick providing function - * @return this - */ - public SetRandomLookTarget lookTime(Function function) { - this.lookTime = function; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return entity.getRandom().nextFloat() < this.runChance.sample(entity.getRandom()); - } - - @Override - protected void start(E entity) { - double angle = Mth.TWO_PI * entity.getRandom().nextDouble(); - - BrainUtils.setForgettableMemory( - entity, - MemoryModuleType.LOOK_TARGET, - new FreePositionTracker(entity.getEyePosition().add(Math.cos(angle), 0, Math.sin(angle))), - this.lookTime.apply(entity) - ); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORIES; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRetaliateTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRetaliateTarget.java deleted file mode 100644 index 5205980fd..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRetaliateTarget.java +++ /dev/null @@ -1,140 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.TamableAnimal; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.player.Player; - -import java.util.List; -import java.util.function.BiPredicate; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -/** - * Sets the attack target of the entity based on the last entity to hurt it if a target isn't already set.
    - * Defaults: - *
      - *
    • Targets any live entity, as long as it's not a creative mode player
    • - *
    • Does not alert nearby allies when retaliating
    • - *
    • If enabled, only alerts allies of the same class, if they don't already have a target themselves
    • - *
    - * - * @param The entity - */ -public class SetRetaliateTarget extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.HURT_BY_ENTITY, MemoryStatus.VALUE_PRESENT), - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT) - ); - - protected Predicate canAttackPredicate = entity -> entity.isAlive() - && (!(entity instanceof Player player) || !player.isCreative()); - - protected LivingEntity toTarget = null; - - protected BiPredicate alertAlliesPredicate = (owner, attacker) -> false; - - protected BiPredicate allyPredicate = (owner, ally) -> owner.getClass() - .isAssignableFrom(ally.getClass()) && BrainUtils.getTargetOfEntity(ally) == null - && (!(owner instanceof TamableAnimal pet) || pet.getOwner() == ((TamableAnimal) ally).getOwner()) && !ally - .isAlliedTo(BrainUtils.getMemory(owner, MemoryModuleType.HURT_BY_ENTITY)); - - /** - * Set the predicate to determine whether a given entity should be targeted or not. - * - * @param predicate The predicate - * @return this - */ - public SetRetaliateTarget attackablePredicate(Predicate predicate) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Set the predicate to determine whether the brain owner should alert nearby allies of the same entity type when - * retaliating - * - * @param predicate The predicate - * @return this - */ - public SetRetaliateTarget alertAlliesWhen(BiPredicate predicate) { - this.alertAlliesPredicate = predicate; - - return this; - } - - /** - * Set the predicate to determine whether a given entity should be alerted to the target as an ally of the brain - * owner.
    - * Overriding replaces the default predicate, so be sure to include any portions of the default predicate in your - * own if applicable - * - * @param predicate The predicate - * @return this - */ - public SetRetaliateTarget isAllyIf(BiPredicate predicate) { - this.allyPredicate = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E owner) { - this.toTarget = BrainUtils.getMemory(owner, MemoryModuleType.HURT_BY_ENTITY); - - if (this.toTarget.isAlive() && this.toTarget.level() == level && this.canAttackPredicate.test(this.toTarget)) { - if (this.alertAlliesPredicate.test(owner, this.toTarget)) - alertAllies(level, owner); - - return true; - } - - return false; - } - - @Override - protected void start(E entity) { - BrainUtils.setTargetOfEntity(entity, this.toTarget); - BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - this.toTarget = null; - } - - protected void alertAllies(ServerLevel level, E owner) { - double followRange = owner.getAttributeValue(Attributes.FOLLOW_RANGE); - - for ( - LivingEntity ally : EntityRetrievalUtil.getEntities( - level, - owner.getBoundingBox().inflate(followRange, 10, followRange), - entity -> entity != owner && entity instanceof LivingEntity livingEntity && this.allyPredicate.test( - owner, - livingEntity - ) - ) - ) { - BrainUtils.setTargetOfEntity(ally, this.toTarget); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/TargetOrRetaliate.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/TargetOrRetaliate.java deleted file mode 100644 index 3148ee11e..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/TargetOrRetaliate.java +++ /dev/null @@ -1,185 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.*; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.player.Player; - -import java.util.List; -import java.util.function.BiPredicate; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -/** - * Sets the attack target of the entity, utilising a few sources of targets.
    - * In order: - *
      - *
    1. The {@link MemoryModuleType#NEAREST_ATTACKABLE} memory value
    2. - *
    3. The {@link MemoryModuleType#HURT_BY_ENTITY} memory value
    4. - *
    5. The closest applicable entity from the {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory value
    6. - *
    - * Defaults: - *
      - *
    • Targets any live entity, as long as it's not a creative-mode player
    • - *
    • Does not alert nearby allies when retaliating
    • - *
    • If enabled, only alerts allies of the same class, if they don't already have a target themselves
    • - *
    - * - * @param The entity - */ -public class TargetOrRetaliate extends ExtendedBehaviour { - - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of( - Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), - Pair.of(MemoryModuleType.HURT_BY, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.NEAREST_ATTACKABLE, MemoryStatus.REGISTERED), - Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.REGISTERED) - ); - - protected Predicate canAttackPredicate = entity -> entity.isAlive() - && (!(entity instanceof Player player) || !player.isCreative()); - - protected BiPredicate alertAlliesPredicate = (owner, attacker) -> false; - - protected BiPredicate allyPredicate = (owner, ally) -> { - if (!owner.getClass().isAssignableFrom(ally.getClass()) || BrainUtils.getTargetOfEntity(ally) != null) - return false; - - if (owner instanceof OwnableEntity pet && pet.getOwner() != ((OwnableEntity) ally).getOwner()) - return false; - - Entity lastHurtBy = BrainUtils.getMemory(ally, MemoryModuleType.HURT_BY_ENTITY); - - return lastHurtBy == null || !ally.isAlliedTo(lastHurtBy); - }; - - protected LivingEntity toTarget = null; - - protected MemoryModuleType priorityTargetMemory = MemoryModuleType.NEAREST_ATTACKABLE; - - /** - * Set the predicate to determine whether a given entity should be targeted or not. - * - * @param predicate The predicate - * @return this - */ - public TargetOrRetaliate attackablePredicate(Predicate predicate) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Set the memory type that is checked first to target an entity. Useful for switching to player-only targeting - * - * @return this - */ - public TargetOrRetaliate useMemory(MemoryModuleType memory) { - this.priorityTargetMemory = memory; - - return this; - } - - /** - * Set the predicate to determine whether the brain owner should alert nearby allies of the same entity type when - * retaliating - * - * @param predicate The predicate - * @return this - */ - public TargetOrRetaliate alertAlliesWhen(BiPredicate predicate) { - this.alertAlliesPredicate = predicate; - - return this; - } - - /** - * Set the predicate to determine whether a given entity should be alerted to the target as an ally of the brain - * owner.
    - * Overriding replaces the default predicate, so be sure to include any portions of the default predicate in your - * own if applicable - * - * @param predicate The predicate - * @return this - */ - public TargetOrRetaliate isAllyIf(BiPredicate predicate) { - this.allyPredicate = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E owner) { - Brain brain = owner.getBrain(); - this.toTarget = BrainUtils.getMemory(brain, this.priorityTargetMemory); - - if (this.toTarget == null) { - this.toTarget = BrainUtils.getMemory(brain, MemoryModuleType.HURT_BY_ENTITY); - - if (this.toTarget == null) { - NearestVisibleLivingEntities nearbyEntities = BrainUtils.getMemory( - brain, - MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES - ); - - if (nearbyEntities != null) - this.toTarget = nearbyEntities.findClosest(this.canAttackPredicate).orElse(null); - - if (this.alertAlliesPredicate.test(owner, this.toTarget)) - alertAllies(level, owner); - - if (this.toTarget == null) - return false; - } - } - - if (this.alertAlliesPredicate.test(owner, this.toTarget)) - alertAllies(level, owner); - - return this.canAttackPredicate.test(this.toTarget); - } - - @Override - protected void start(E entity) { - BrainUtils.setTargetOfEntity(entity, this.toTarget); - BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - this.toTarget = null; - } - - protected void alertAllies(ServerLevel level, E owner) { - double followRange = owner.getAttributeValue(Attributes.FOLLOW_RANGE); - - for ( - LivingEntity ally : EntityRetrievalUtil.getEntities( - level, - owner.getBoundingBox().inflate(followRange, 10, followRange), - entity -> entity != owner && entity instanceof LivingEntity livingEntity && this.allyPredicate.test( - owner, - livingEntity - ) - ) - ) { - BrainUtils.setTargetOfEntity(ally, this.toTarget); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/ExtendedNavigator.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/ExtendedNavigator.java deleted file mode 100644 index 637ccc170..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/ExtendedNavigator.java +++ /dev/null @@ -1,345 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.PathNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.PathNavigationRegion; -import net.minecraft.world.level.chunk.BulkSectionAccess; -import net.minecraft.world.level.pathfinder.*; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -import java.util.Set; - -/** - * Extracted interface to act as a helper utility for cleaner navigator implementations - *

    - * This expands on Vanilla's navigator functionality, fixing some issues, optimising it, and splitting it out to be - * properly extensible - */ -public interface ExtendedNavigator { - - /** - * Minimum threshold representing a rounding error for the purposes of bounds collision - */ - float EPSILON = 1.0E-8F; - - /** - * Helper overload getter for retrieving the entity from {@link PathNavigation#mob} - */ - Mob getMob(); - - /** - * Helper overload getter for retrieving the path from {@link PathNavigation#path} - */ - Path getPath(); - - /** - * @return Whether the given path type can be pathed onto, or otherwise be considered a pathable surface - */ - default boolean canPathOnto(PathType pathType) { - return switch (pathType) { - case WATER, LAVA, OPEN -> false; - default -> true; - }; - } - - /** - * @return Whether the given path type should be considered safe to path into, or is otherwise a pathable free space - */ - default boolean canPathInto(PathType pathType) { - return switch (pathType) { - case DAMAGE_FIRE, DANGER_FIRE, DAMAGE_OTHER -> true; - default -> false; - }; - } - - /** - * Determine whether the entity should be considered close enough to the next node to be counted as having reached - * it - * - * @param distance The distance threshold which counts as 'close enough' to the next node - * @return Whether the entity is within reach of the next node in the path - * @see PathNavigation#getMaxDistanceToWaypoint() - */ - default boolean isCloseToNextNode(float distance) { - final Mob mob = getMob(); - final Path path = getPath(); - final Vec3 nextNodePos = getEntityPosAtNode(path.getNextNodeIndex()); - - return Math.abs(mob.getX() - nextNodePos.x) < distance && - Math.abs(mob.getZ() - nextNodePos.z) < distance && - Math.abs(mob.getY() - nextNodePos.y) < 1; - } - - /** - * @return Whether the path the mob is following is about to cause a change in elevation (either up or down), - * accounting for potentially skippable nodes based on the entity's stride size - */ - default boolean isAboutToTraverseVertically() { - final Mob mob = getMob(); - final Path path = getPath(); - final int fromNode = path.getNextNodeIndex(); - final int fromNodeHeight = path.getNode(fromNode).y; - final int toNode = Math.min(path.getNodeCount(), fromNode + Mth.ceil(mob.getBbWidth() * 0.5d) + 1); - - for (int i = fromNode + 1; i < toNode; i++) { - if (path.getNode(i).y != fromNodeHeight) - return true; - } - - return false; - } - - /** - * Wrap a Path instance in a new instance, patching out the {@link Path#getEntityPosAtNode(Entity, int)} - * implementation for smoother pathing - * - * @return A new Path instance, or null if the input Path was null - */ - @Nullable - default Path patchPath(@Nullable Path path) { - return path == null ? null : new Path(path.nodes, path.getTarget(), path.canReach()) { - - @Override - public Vec3 getEntityPosAtNode(Entity entity, int nodeIndex) { - return ExtendedNavigator.this.getEntityPosAtNode(nodeIndex); - } - }; - } - - /** - * Create a PathFinder instance patching out the {@link Path#getEntityPosAtNode(Entity, int)} implementation for - * smoother pathing - */ - default PathFinder createSmoothPathFinder(NodeEvaluator nodeEvaluator, int maxVisitedNodes) { - return new PathFinder(nodeEvaluator, maxVisitedNodes) { - - @Nullable - @Override - public Path findPath( - PathNavigationRegion navigationRegion, - Mob mob, - Set targetPositions, - float maxRange, - int accuracy, - float searchDepthMultiplier - ) { - return patchPath( - super.findPath(navigationRegion, mob, targetPositions, maxRange, accuracy, searchDepthMultiplier) - ); - } - }; - } - - /** - * Attempt to skip to the target node, bypassing the intermediate notes depending on bounds collision for the - * intervening distance - *

    - * Typically, the target node should already have been checked for proximal relevance, as otherwise this could cause - * node skips to act strangely - * - * @param targetNode The target node index to shortcut to - * @param safeSurfacePos The baseline position of where the mob should traverse to (usually the nearest ground pos - * or surface of the fluid it's submerged in) - * @return Whether the shortcut was successful or not - */ - default boolean attemptShortcut(int targetNode, Vec3 safeSurfacePos) { - final Mob mob = getMob(); - final Path path = getPath(); - final Vec3 position = mob.position(); - final Vec3 minBounds = safeSurfacePos.add(-mob.getBbWidth() * 0.5d, 0, -mob.getBbWidth() * 0.5d); - final Vec3 maxBounds = minBounds.add(mob.getBbWidth(), mob.getBbHeight(), mob.getBbWidth()); - - for (int nodeIndex = targetNode - 1; nodeIndex > path.getNextNodeIndex(); nodeIndex--) { - final Vec3 nodeDelta = getEntityPosAtNode(nodeIndex).subtract(position); - - if (isCollisionFreeTraversal(nodeDelta, minBounds, maxBounds)) { - path.setNextNodeIndex(nodeIndex); - - return true; - } - } - - return false; - } - - /** - * Get the entity's predicted position at the time they reach the given node - *

    - * Functionally replaces {@link Path#getEntityPosAtNode} to better handle the double rounding - * - * @param nodeIndex The index of the node to check - * @return The approximate position of the entity for the given node - */ - default Vec3 getEntityPosAtNode(int nodeIndex) { - final Mob mob = getMob(); - final Path path = getPath(); - final double lateralOffset = Mth.floor(mob.getBbWidth() + 1d) / 2d; - - return Vec3.atLowerCornerOf(path.getNodePos(nodeIndex)).add(lateralOffset, 0, lateralOffset); - } - - /** - * Recursively sweep the edges of a given area, identifying collisions for colliding faces of a pseudo-bounds - * determined by ray-casts projected from the bounds leading edge, then cross-checking interceptions for the - * relevant face. - *

    - * Each array represent [x, y, z] vector coordinates - * - * @param minPos The minimum-pos coordinate for the given axis - * @param leadingEdgeBound The maximum-pos axis-aligned coordinate for the given axis - * @param trailingEdgeBound The mimimum-pos axis-aligned coordinate for the given axis - * @param absStep -1 or 1 value representing which direction to step for each axis - * @param axisSteps How many lengths of the given axis required to traverse the full distance - * @param rayTargetLength How long the ray should be to account for traversal - * @param axisLengthNormalised Fraction of the full distance the given length of this axis represents - */ - record VoxelRayDetails( - float[] minPos, - int[] leadingEdgeBound, - int[] trailingEdgeBound, - int[] absStep, - float[] axisSteps, - float[] rayTargetLength, - float[] axisLengthNormalised - ) { - - public VoxelRayDetails() { - this(new float[3], new int[3], new int[3], new int[3], new float[3], new float[3], new float[3]); - } - } - - /** - * @return The vector length for the given axis - */ - default float lengthForAxis(Vec3 vector, Direction.Axis axis) { - return (float) axis.choose(vector.x, vector.y, vector.z); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothAmphibiousPathNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothAmphibiousPathNavigation.java deleted file mode 100644 index a0a766b43..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothAmphibiousPathNavigation.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.AmphibiousPathNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.AmphibiousNodeEvaluator; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; -import org.jetbrains.annotations.Nullable; - -/** - * Extension of the vanilla {@link AmphibiousPathNavigation} with some tweaks for smoother pathfinding: - *

      - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Extensible {@link #prefersShallowSwimming()} implementation for ease-of-use
    • - *
    - *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based - * walking entity - */ -public class SmoothAmphibiousPathNavigation extends AmphibiousPathNavigation implements ExtendedNavigator { - - public SmoothAmphibiousPathNavigation(Mob mob, Level level) { - super(mob, level); - } - - /** - * Determine whether the navigator should prefer shallow swimming patterns - *

    - * Adjusts path node penalty when determining paths - */ - public boolean prefersShallowSwimming() { - return false; - } - - @Override - public Mob getMob() { - return this.mob; - } - - @Nullable - @Override - public Path getPath() { - return super.getPath(); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new AmphibiousNodeEvaluator(prefersShallowSwimming()); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothFlyingPathNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothFlyingPathNavigation.java deleted file mode 100644 index b0f51773f..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothFlyingPathNavigation.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.FlyNodeEvaluator; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; -import org.jetbrains.annotations.Nullable; - -/** - * Extension of the vanilla {@link FlyingPathNavigation} with some tweaks for smoother pathfinding: - *

      - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    - *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based - * walking entity - */ -public class SmoothFlyingPathNavigation extends FlyingPathNavigation implements ExtendedNavigator { - - public SmoothFlyingPathNavigation(Mob mob, Level level) { - super(mob, level); - } - - @Override - public Mob getMob() { - return this.mob; - } - - @Nullable - @Override - public Path getPath() { - return super.getPath(); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new FlyNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothGroundNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothGroundNavigation.java deleted file mode 100644 index f414c2b0f..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothGroundNavigation.java +++ /dev/null @@ -1,114 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; -import net.minecraft.world.entity.ai.navigation.PathNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; -import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -/** - * Extension of the vanilla {@link GroundPathNavigation} with some tweaks for smoother pathfinding: - *

      - *
    • Smoothed unit rounding to better accommodate edge-cases
    • - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Skip to vertical traversal first before continuing path nodes if appropriate
    • - *
    • Accessible {@link GroundPathNavigation#getSurfaceY()} override for extensibility
    • - *
    - *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based - * walking entity - * - * @see ExtendedNavigator#canPathOnto - * @see ExtendedNavigator#canPathInto - */ -public class SmoothGroundNavigation extends GroundPathNavigation implements ExtendedNavigator { - - public SmoothGroundNavigation(Mob mob, Level level) { - super(mob, level); - } - - @Override - public Mob getMob() { - return this.mob; - } - - @Nullable - @Override - public Path getPath() { - return super.getPath(); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new WalkNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } - - @Override - protected void followThePath() { - final Vec3 safeSurfacePos = getTempMobPos(); - final int shortcutNode = getClosestVerticalTraversal(Mth.floor(safeSurfacePos.y)); - this.maxDistanceToWaypoint = this.mob.getBbWidth() > 0.75f - ? this.mob.getBbWidth() / 2f - : 0.75f - this.mob.getBbWidth() / 2f; - - if (!attemptShortcut(shortcutNode, safeSurfacePos)) { - if ( - isCloseToNextNode(0.5f) || isAboutToTraverseVertically() && isCloseToNextNode( - getMaxDistanceToWaypoint() - ) - ) - this.path.advance(); - } - - doStuckDetection(safeSurfacePos); - } - - /** - * Helper override to allow end-users to modify the fluids an entity can swim in - *

    - * If using this to modify swimmable fluids, ensure you also override {@link PathNavigation#canUpdatePath()} as well - * - * @return The nearest safe surface height for the entity - */ - @Override - public int getSurfaceY() { - return super.getSurfaceY(); - } - - /** - * Find the nearest node in the path that accounts for a vertical traversal (either up or down) - *

    - * This can then be used to test if a collision-free traversal can be made, skipping the intermediate nodes as - * appropriate - * - * @param safeSurfaceHeight The baseline floored y-pos of where the mob should traverse to (usually the nearest - * ground pos or surface of the fluid it's submerged in) - * @return The node index for the nearest node representing a vertical traversal - */ - protected int getClosestVerticalTraversal(int safeSurfaceHeight) { - final int nodesLength = this.path.getNodeCount(); - - for (int nodeIndex = this.path.getNextNodeIndex(); nodeIndex < nodesLength; nodeIndex++) { - if (this.path.getNode(nodeIndex).y != safeSurfaceHeight) - return nodeIndex; - } - - return nodesLength; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWallClimberNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWallClimberNavigation.java deleted file mode 100644 index cf1cfe5be..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWallClimberNavigation.java +++ /dev/null @@ -1,67 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; -import net.minecraft.world.entity.ai.navigation.PathNavigation; -import net.minecraft.world.entity.ai.navigation.WallClimberNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; -import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; -import org.jetbrains.annotations.Nullable; - -/** - * Extension of the vanilla {@link WallClimberNavigation} with some tweaks for smoother pathfinding: - *

      - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Accessible {@link GroundPathNavigation#getSurfaceY()} override for extensibility
    • - *
    - *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based - * walking entity - */ -public class SmoothWallClimberNavigation extends WallClimberNavigation implements ExtendedNavigator { - - public SmoothWallClimberNavigation(Mob mob, Level level) { - super(mob, level); - } - - @Override - public Mob getMob() { - return this.mob; - } - - @Nullable - @Override - public Path getPath() { - return super.getPath(); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new WalkNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } - - /** - * Helper override to allow end-users to modify the fluids an entity can swim in - *

    - * If using this to modify swimmable fluids, ensure you also override {@link PathNavigation#canUpdatePath()} as well - * - * @return The nearest safe surface height for the entity - */ - @Override - public int getSurfaceY() { - return super.getSurfaceY(); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWaterBoundPathNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWaterBoundPathNavigation.java deleted file mode 100644 index 188984954..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWaterBoundPathNavigation.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.WaterBoundPathNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; -import net.minecraft.world.level.pathfinder.SwimNodeEvaluator; -import org.jetbrains.annotations.Nullable; - -/** - * Extension of the vanilla {@link WaterBoundPathNavigation} navigator with some tweaks for smoother pathfinding: - *

      - *
    • Smoothed unit rounding to better accommodate edge-cases
    • - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Extensible {@link #canBreach()} implementation for ease-of-use
    • - *
    - *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a water-based - * swimming entity - */ -public class SmoothWaterBoundPathNavigation extends WaterBoundPathNavigation implements ExtendedNavigator { - - public SmoothWaterBoundPathNavigation(Mob mob, Level level) { - super(mob, level); - } - - /** - * Determine whether the entity can breach the surface as part of its pathing - *

    - * Defaults to false for non-dolphins - */ - public boolean canBreach() { - return this.mob.getType() == EntityType.DOLPHIN; - } - - @Override - public Mob getMob() { - return this.mob; - } - - @Nullable - @Override - public Path getPath() { - return super.getPath(); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new SwimNodeEvaluator(this.allowBreaching = canBreach()); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/schedule/SmartBrainSchedule.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/schedule/SmartBrainSchedule.java deleted file mode 100644 index 95fa9dd0e..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/schedule/SmartBrainSchedule.java +++ /dev/null @@ -1,211 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.schedule; - -import com.google.common.collect.ListMultimap; -import com.google.common.collect.MultimapBuilder; -import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.schedule.Activity; -import net.minecraft.world.entity.schedule.Schedule; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.function.Consumer; -import java.util.function.ToIntBiFunction; -import java.util.function.ToIntFunction; - -import mod.azure.azurelib.sblforked.api.SmartBrainOwner; - -/** - * SBL-implementation of the vanilla {@link net.minecraft.world.entity.schedule.Schedule Schedule}.
    - * It extends the vanilla {@link Schedule} purely for compatibility reasons, but does not utilise any of its - * functionality.
    - *
    - * This segment of the Brain system is used to timeline activities, allowing you to run activity groups and tasks on a - * tick-based schedule.
    - *
    - * Activities scheduled using this system will override the activity priorities from - * {@link SmartBrainOwner#getActivityPriorities()} at tick time - */ -public class SmartBrainSchedule extends Schedule { - - private final Type type; - - private final Int2ObjectArrayMap timeline = new Int2ObjectArrayMap<>(0); - - private final ListMultimap> callbacks = MultimapBuilder.hashKeys(0) - .arrayListValues() - .build(); - - private boolean sortedTimeline = true; - - public SmartBrainSchedule() { - this(Type.DAYTIME); - } - - public SmartBrainSchedule(Type type) { - this.type = type; - } - - /** - * Set the active {@link Activity} for the brain at the given tick/time - * - * @param tick The tick/time to activate the activity - * @param activity The activity to set as active at the given time - * @return this - */ - public SmartBrainSchedule activityAt(int tick, Activity activity) { - this.timeline.put(tick, activity); - - this.sortedTimeline = false; - - return this; - } - - /** - * Add a callback to run at the given tick - * - * @param tick The tick/time to run the callback at - * @param callback The callback to run at the given time - * @return this - */ - public SmartBrainSchedule doAt(int tick, Consumer callback) { - this.callbacks.put(tick, callback); - - return this; - } - - /** - * Adds a dynamically-scheduled task for a given tick-time in the future - * - * @param brainOwner The owner of the brain - * @param delay The delay time (in ticks) before the task should be called - * @param task The task to run after the given delay - */ - public void scheduleTask(LivingEntity brainOwner, int delay, Consumer task) { - this.callbacks.put(this.type.resolveDelay(brainOwner, delay), entity -> task.accept(brainOwner)); - } - - /** - * Remove all entries from the schedule, clearing it out - */ - public void clearSchedule() { - this.callbacks.clear(); - this.timeline.clear(); - } - - /** - * Tick the schedule and return the activity to switch the entity to, if applicable - * - * @param brainOwner The owner of the brain that contains this schedule - * @return The activity to set as active based on the current tick, or null if none to set - */ - @Nullable - public Activity tick(LivingEntity brainOwner) { - int tick = this.type.resolve(brainOwner); - - if (!this.callbacks.isEmpty()) { - this.callbacks.get(tick).forEach(consumer -> consumer.accept(brainOwner)); - - if (this.type == Type.AGE) - this.callbacks.removeAll(tick); - } - - if (!this.timeline.isEmpty()) { - if (!this.sortedTimeline) - sortTimeline(); - - int index = -1; - Activity activity = null; - - for (Int2ObjectMap.Entry entry : this.timeline.int2ObjectEntrySet()) { - index++; - - if (entry.getIntKey() >= tick) { - if (entry.getIntKey() == tick) - activity = entry.getValue(); - - break; - } - - activity = entry.getValue(); - } - - if (this.type == Type.AGE && index + 1 >= this.timeline.size()) - this.timeline.clear(); - - return activity; - } - - return null; - } - - private void sortTimeline() { - Int2ObjectArrayMap copy = new Int2ObjectArrayMap<>(this.timeline); - int[] keys = copy.keySet().toArray(new int[0]); - - Arrays.sort(keys); - this.timeline.clear(); - - for (int key : keys) { - this.timeline.put(key, copy.get(key)); - } - - this.sortedTimeline = true; - } - - @Override - public final Activity getActivityAt(int tick) { - if (this.type == Type.AGE) - return Activity.IDLE; - - Activity activity = Activity.IDLE; - - for (Int2ObjectMap.Entry entry : this.timeline.int2ObjectEntrySet()) { - if (entry.getIntKey() >= tick) - return activity; - - activity = entry.getValue(); - } - - return activity; - } - - /** - * The type of scheduling this scheduler is using (I.E. how it determines the input tick) - */ - public enum Type { - - /** - * Time of day (0-24000 ticks) - */ - DAYTIME(e -> (int) (e.level().getDayTime() % 24000L), (e, t) -> (int) ((e.level().getDayTime() + t) % 24000L)), - /** - * Age of the brain owner (0+).
    - * This makes the schedule a 'run-once' per entity - */ - AGE(e -> e.tickCount, (e, t) -> e.tickCount + t); - - final ToIntFunction tickResolver; - - final ToIntBiFunction delayResolver; - - Type(ToIntFunction tickResolver, ToIntBiFunction delayResolver) { - this.tickResolver = tickResolver; - this.delayResolver = delayResolver; - } - - public int resolve(LivingEntity entity) { - return this.tickResolver.applyAsInt(entity); - } - - public int resolveDelay(LivingEntity entity, int delay) { - return this.delayResolver.applyAsInt(entity, delay); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/EntityFilteringSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/EntityFilteringSensor.java deleted file mode 100644 index 8f9c4e714..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/EntityFilteringSensor.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor; - -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * An abstract class that is used to pick out certain entities from the existing - * {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory.
    - * This requires that another sensor has pre-filled that memory. - * - * @see net.minecraft.world.entity.ai.sensing.NearestVisibleLivingEntitySensor - * @param

    The target entity - * @param The entity - */ -public abstract class EntityFilteringSensor extends PredicateSensor { - - /** - * Which memory the sensor should set if an entity meets the given criteria. - * - * @return The memory type to use - */ - protected abstract MemoryModuleType

    getMemory(); - - @Override - protected abstract BiPredicate predicate(); - - @Override - public List> memoriesUsed() { - return List.of(getMemory()); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.setMemory(entity, getMemory(), testForEntity(entity)); - } - - protected P testForEntity(E entity) { - NearestVisibleLivingEntities matcher = BrainUtils.getMemory( - entity, - MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES - ); - - if (matcher == null) - return null; - - return findMatches(entity, matcher); - } - - /** - * Find and return matches based on the provided list of entities.
    - * The returned value is saved as the memory for this sensor. - * - * @param entity The entity - * @param matcher The nearby entities list retrieved from the - * {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory - * @return The match(es) to save in memory - */ - @Nullable - protected abstract P findMatches(E entity, NearestVisibleLivingEntities matcher); -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/ExtendedSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/ExtendedSensor.java deleted file mode 100644 index b231ae8d5..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/ExtendedSensor.java +++ /dev/null @@ -1,107 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor; - -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.Sensor; -import net.minecraft.world.entity.ai.sensing.SensorType; - -import java.util.List; -import java.util.Set; -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * An extension of the base Sensor. This adds some minor additional functionality and swaps the memory to a list for - * easier usage and faster iteration.
    - * All custom sensor implementations should use this superclass. - * - * @param The entity - */ -public abstract class ExtendedSensor extends Sensor { - - protected Function scanRate = entity -> 20; - - protected Consumer scanCallback = entity -> {}; - - protected long nextTickTime = 0; - - public ExtendedSensor() { - super(); - } - - /** - * Set the scan rate provider for this sensor.
    - * The provider will be sampled every time the sensor does a scan. - * - * @param function The function to provide the tick rate - * @return this - */ - public ExtendedSensor setScanRate(Function function) { - this.scanRate = function; - - return this; - } - - /** - * Set a callback function for when the sensor completes a scan. - */ - public ExtendedSensor afterScanning(Consumer callback) { - this.scanCallback = callback; - - return this; - } - - @Override - public final void tick(ServerLevel level, E entity) { - if (nextTickTime < level.getGameTime()) { - nextTickTime = level.getGameTime() + scanRate.apply(entity); - - doTick(level, entity); - this.scanCallback.accept(entity); - } - } - - /** - * Handle the Sensor's actual function here. Be wary of performance implications of computation-heavy checks here. - * - * @param level The level the entity is in - * @param entity The owner of the brain - */ - @Override - protected void doTick(ServerLevel level, E entity) {} - - /** - * The list of memory types this sensor saves to. This should contain any memory the sensor sets a value for in the - * brain
    - * Bonus points if it's a statically-initialised list. - * - * @return The list of memory types saves by this sensor - */ - public abstract List> memoriesUsed(); - - /** - * The {@link SensorType} of the sensor, used for reverse lookups. - * - * @return The sensor type - */ - public abstract SensorType> type(); - - /** - * Vanilla's implementation of the required memory collection. Functionally replaced by - * {@link ExtendedSensor#memoriesUsed()}.
    - * Left in place for compatibility reasons. - * - * @return A set view of the list returned by {@code memoriesUsed()} - */ - @Override - public final Set> requires() { - return new ObjectOpenHashSet<>(memoriesUsed()); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/PredicateSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/PredicateSensor.java deleted file mode 100644 index 8d7b92140..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/PredicateSensor.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor; - -import net.minecraft.world.entity.LivingEntity; - -import java.util.function.BiPredicate; - -/** - * An abstract sensor class used for sensors that utilise some form of predication in their function. This allows for - * instance-based SmartBrainLib of the predicate and the sensor. - * - * @param

    The predicate, used for whatever the sensor might need - * @param The entity - */ -public abstract class PredicateSensor extends ExtendedSensor { - - private BiPredicate predicate; - - public PredicateSensor() { - this((obj, entity) -> true); - } - - public PredicateSensor(BiPredicate predicate) { - this.predicate = predicate; - } - - /** - * Set the predicate for the sensor. The subclass of this class determines its usage. - * - * @param predicate The predicate - * @return this - */ - public PredicateSensor setPredicate(BiPredicate predicate) { - this.predicate = predicate; - - return this; - } - - /** - * Retrieve the predicate this sensor is using. - * - * @return The predicate - */ - protected BiPredicate predicate() { - return this.predicate; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/GenericAttackTargetSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/GenericAttackTargetSensor.java deleted file mode 100644 index 7082c97b5..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/GenericAttackTargetSensor.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.custom; - -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.SensorType; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; - -/** - * Sets the {@link MemoryModuleType#NEAREST_ATTACKABLE} memory based on visible nearby entities.
    - * Defaults: - *

      - *
    • Only targets that - * {@link net.minecraft.world.entity.ai.sensing.Sensor#isEntityAttackable(LivingEntity, LivingEntity)} passes.
    • - *
    - * - * @param - */ -public class GenericAttackTargetSensor extends EntityFilteringSensor { - - @Override - protected MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_ATTACKABLE; - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> isEntityAttackable(entity, target); - } - - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } - - @Override - public SensorType> type() { - return SBLSensors.GENERIC_ATTACK_TARGET.get(); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/IncomingProjectilesSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/IncomingProjectilesSensor.java deleted file mode 100644 index 70805fcaf..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/IncomingProjectilesSensor.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.custom; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.projectile.Projectile; - -import java.util.Comparator; -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -/** - * Custom sensor that detects incoming projectiles. Defaults: - *
      - *
    • 3-tick scan rate
    • - *
    • Only projectiles that are still in flight
    • - *
    • Only projectiles that will hit the entity before the next scan
    • - *
    - * - * @param - */ -public class IncomingProjectilesSensor extends PredicateSensor { - - private static final List> MEMORIES = ObjectArrayList.of( - SBLMemoryTypes.INCOMING_PROJECTILES.get() - ); - - public IncomingProjectilesSensor() { - setScanRate(entity -> 3); - setPredicate((projectile, entity) -> { - if (projectile.onGround() || projectile.horizontalCollision || projectile.verticalCollision) - return false; - - return entity.getBoundingBox() - .clip(projectile.position(), projectile.position().add(projectile.getDeltaMovement().multiply(3, 3, 3))) - .isPresent(); - }); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.INCOMING_PROJECTILES.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - List projectiles = EntityRetrievalUtil.getEntities( - level, - entity.getBoundingBox().inflate(7), - target -> target instanceof Projectile projectile && predicate().test(projectile, entity) - ); - - if (!projectiles.isEmpty()) { - projectiles.sort(Comparator.comparingDouble(entity::distanceToSqr)); - BrainUtils.setMemory(entity, SBLMemoryTypes.INCOMING_PROJECTILES.get(), projectiles); - } else { - BrainUtils.clearMemory(entity, SBLMemoryTypes.INCOMING_PROJECTILES.get()); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyBlocksSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyBlocksSensor.java deleted file mode 100644 index f0fb96400..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyBlocksSensor.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.custom; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Sensor for identifying and memorising nearby blocks using the {@link SBLMemoryTypes#NEARBY_BLOCKS} memory module. - *
    - * Defaults: - *
      - *
    • 1-block radius
    • - *
    • Ignores air blocks
    • - *
    - */ -public class NearbyBlocksSensor extends PredicateSensor { - - private static final List> MEMORIES = ObjectArrayList.of(SBLMemoryTypes.NEARBY_BLOCKS.get()); - - protected SquareRadius radius = new SquareRadius(1, 1); - - public NearbyBlocksSensor() { - setPredicate((state, entity) -> !state.isAir()); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_BLOCKS.get(); - } - - /** - * Set the radius for the sensor to scan - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyBlocksSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyBlocksSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - protected void doTick(ServerLevel level, E entity) { - List> blocks = new ObjectArrayList<>(); - - for ( - BlockPos pos : BlockPos.betweenClosed( - entity.blockPosition().subtract(this.radius.toVec3i()), - entity.blockPosition().offset(this.radius.toVec3i()) - ) - ) { - BlockState state = level.getBlockState(pos); - - if (this.predicate().test(state, entity)) - blocks.add(Pair.of(pos.immutable(), state)); - } - - if (blocks.isEmpty()) { - BrainUtils.clearMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get()); - } else { - BrainUtils.setMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get(), blocks); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyItemsSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyItemsSensor.java deleted file mode 100644 index 30ff6198f..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyItemsSensor.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.custom; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -/** - * A sensor that looks for nearby {@link ItemEntity items} in the surrounding area.
    - * Defaults: - *
      - *
    • 32x16x32 radius
    • - *
    • Only items that return true for {@link Mob#wantsToPickUp(ItemStack)}
    • - *
    • Only items that return true for {@link net.minecraft.world.entity.LivingEntity#hasLineOfSight(Entity)}
    • - *
    - * - * @param The entity - */ -public class NearbyItemsSensor extends PredicateSensor { - - private static final List> MEMORIES = ObjectArrayList.of(SBLMemoryTypes.NEARBY_ITEMS.get()); - - protected SquareRadius radius = new SquareRadius(32, 16); - - public NearbyItemsSensor() { - super((item, entity) -> entity.wantsToPickUp(item.getItem()) && entity.hasLineOfSight(item)); - } - - /** - * Set the radius for the item sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyItemsSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the item sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyItemsSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_ITEMS.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.setMemory( - entity, - SBLMemoryTypes.NEARBY_ITEMS.get(), - EntityRetrievalUtil.getEntities( - level, - this.radius.inflateAABB(entity.getBoundingBox()), - obj -> obj instanceof ItemEntity item && predicate().test(item, entity) - ) - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/UnreachableTargetSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/UnreachableTargetSensor.java deleted file mode 100644 index b7bcd64af..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/UnreachableTargetSensor.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.custom; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A sensor to attempt to track whether the entity's target is currently obstructed either by blocks or a wall/tower of - * blocks.
    - * This is differentiated from {@link MemoryModuleType#CANT_REACH_WALK_TARGET_SINCE} in that it only stores state if the - * entity is actively blocked, and not just completing a previous path that may have been blocked.
    - * The contract of the memory (when this sensor is used) is as follows:
    - *
      - *
    • If not present: entity is not blocked
    • - *
    • If false: entity is blocked at a similar or lower y-coordinate (wall-blocked)
    • - *
    • If true: entity is blocked at a higher y-coordinate (target has towered up, or is on cliff)
    • - *
    - * - * @param The entity - */ -public class UnreachableTargetSensor extends ExtendedSensor { - - private static final List> MEMORIES = ObjectArrayList.of( - MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, - MemoryModuleType.ATTACK_TARGET, - SBLMemoryTypes.TARGET_UNREACHABLE.get() - ); - - protected long lastUnpathableTime = 0; - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.UNREACHABLE_TARGET.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - - if (target == null) { - resetState(brain); - - return; - } - - Long unpathableTime = BrainUtils.getMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - if (unpathableTime == null) { - resetState(brain); - - return; - } - - if (this.lastUnpathableTime == 0) { - this.lastUnpathableTime = unpathableTime; - } else if (this.lastUnpathableTime == unpathableTime) { - BrainUtils.clearMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get()); - } else if (this.lastUnpathableTime < unpathableTime) { - this.lastUnpathableTime = unpathableTime; - - BrainUtils.setMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get(), target.getY() > entity.getEyeY()); - } - } - - private void resetState(Brain brain) { - if (this.lastUnpathableTime > 0) - BrainUtils.clearMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get()); - - this.lastUnpathableTime = 0; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/AxolotlSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/AxolotlSpecificSensor.java deleted file mode 100644 index c774ee19e..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/AxolotlSpecificSensor.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import net.minecraft.tags.EntityTypeTags; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.Sensor; -import net.minecraft.world.entity.ai.sensing.SensorType; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.AxolotlAttackablesSensor}. Not really useful, - * but included for completeness' sake and legibility.
    - * Handles the Axolotl's hostility and targets - * - * @param The entity - */ -public class AxolotlSpecificSensor extends EntityFilteringSensor { - - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_ATTACKABLE; - } - - @Override - public List> memoriesUsed() { - return List.of(getMemory(), MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); - } - - @Override - public SensorType> type() { - return SBLSensors.AXOLOTL_SPECIFIC.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> { - if (target.distanceToSqr(entity) > 64) - return false; - - if (!target.isInWaterOrBubble()) - return false; - - if ( - !target.getType().is(EntityTypeTags.AXOLOTL_ALWAYS_HOSTILES) && (BrainUtils.hasMemory( - target, - MemoryModuleType.HAS_HUNTING_COOLDOWN - ) || !target.getType().is(EntityTypeTags.AXOLOTL_HUNT_TARGETS)) - ) - return false; - - return Sensor.isEntityAttackable(entity, target); - }; - } - - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/FrogSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/FrogSpecificSensor.java deleted file mode 100644 index b5f453e78..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/FrogSpecificSensor.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.Sensor; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.animal.frog.Frog; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.UUID; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.FrogAttackablesSensor}. Not really useful, - * but included for completeness' sake and legibility.
    - * Handles the Frog's tongue target. - * - * @param The entity - */ -public class FrogSpecificSensor extends EntityFilteringSensor { - - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_ATTACKABLE; - } - - @Override - public SensorType> type() { - return SBLSensors.FROG_SPECIFIC.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> { - if (BrainUtils.hasMemory(entity, MemoryModuleType.HAS_HUNTING_COOLDOWN)) - return false; - - if (!Sensor.isEntityAttackable(entity, target)) - return false; - - if (!Frog.canEat(target)) - return false; - - if (!target.closerThan(entity, 10)) - return false; - - List unreachableTargets = BrainUtils.getMemory(entity, MemoryModuleType.UNREACHABLE_TONGUE_TARGETS); - - return unreachableTargets == null || !unreachableTargets.contains(target.getUUID()); - }; - } - - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HoglinSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HoglinSpecificSensor.java deleted file mode 100644 index 81639f3b9..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HoglinSpecificSensor.java +++ /dev/null @@ -1,88 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.monster.hoglin.Hoglin; -import net.minecraft.world.entity.monster.piglin.Piglin; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.HoglinSpecificSensor}. Not really useful, but - * included for completeness' sake and legibility.
    - * Handles most of Hoglin's memories at once - * - * @param The entity - */ -public class HoglinSpecificSensor extends ExtendedSensor { - - private static final List> MEMORIES = ObjectArrayList.of( - MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, - MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, - MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, - MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, - MemoryModuleType.NEAREST_REPELLENT - ); - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.HOGLIN_SPECIFIC.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, entities -> { - int piglinCount = 0; - Piglin nearestPiglin = null; - List hoglins = new ObjectArrayList<>(); - - for (LivingEntity target : entities.findAll(mob -> !mob.isBaby())) { - if (target instanceof Piglin piglin) { - piglinCount++; - - if (nearestPiglin == null) - nearestPiglin = piglin; - } else if (target instanceof Hoglin hoglin) { - hoglins.add(hoglin); - } - } - - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, nearestPiglin); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, hoglins); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, piglinCount); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, hoglins.size()); - BrainUtils.setMemory( - brain, - MemoryModuleType.NEAREST_REPELLENT, - BlockPos.findClosestMatch( - entity.blockPosition(), - 8, - 4, - pos -> level.getBlockState(pos).is(BlockTags.HOGLIN_REPELLENTS) - ).orElse(null) - ); - }); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HurtBySensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HurtBySensor.java deleted file mode 100644 index efeb9b1c3..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HurtBySensor.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A sensor that sets the memory state for the last damage source and attacker. - * - * @param The entity - */ -public class HurtBySensor extends PredicateSensor { - - private static final List> MEMORIES = ObjectArrayList.of( - MemoryModuleType.HURT_BY, - MemoryModuleType.HURT_BY_ENTITY - ); - - public HurtBySensor() { - super((damageSource, entity) -> true); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.HURT_BY.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - DamageSource damageSource = entity.getLastDamageSource(); - - if (damageSource == null) { - BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY); - BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY_ENTITY); - } else if (predicate().test(damageSource, entity)) { - BrainUtils.setMemory(brain, MemoryModuleType.HURT_BY, damageSource); - - if ( - damageSource.getEntity() instanceof LivingEntity attacker && attacker.isAlive() && attacker - .level() == entity.level() - ) - BrainUtils.setMemory(brain, MemoryModuleType.HURT_BY_ENTITY, attacker); - } else { - BrainUtils.withMemory(brain, MemoryModuleType.HURT_BY_ENTITY, attacker -> { - if (!attacker.isAlive() || attacker.level() != entity.level()) - BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY_ENTITY); - }); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/InWaterSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/InWaterSensor.java deleted file mode 100644 index 00f29ab24..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/InWaterSensor.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.Unit; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A sensor that sets or clears the {@link MemoryModuleType#IS_IN_WATER} memory depending on certain criteria.
    - * Defaults: - *
      - *
    • {@link LivingEntity#isInWater()}
    • - *
    - * - * @param The entity - */ -public class InWaterSensor extends PredicateSensor { - - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.IS_IN_WATER); - - public InWaterSensor() { - super((entity2, entity) -> entity.isInWater()); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.IN_WATER.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - if (predicate().test(entity, entity)) { - BrainUtils.setMemory(entity, MemoryModuleType.IS_IN_WATER, Unit.INSTANCE); - } else { - BrainUtils.clearMemory(entity, MemoryModuleType.IS_IN_WATER); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/ItemTemptingSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/ItemTemptingSensor.java deleted file mode 100644 index bece8b489..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/ItemTemptingSensor.java +++ /dev/null @@ -1,141 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; - -import java.util.Comparator; -import java.util.List; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -/** - * Find the nearest player that is holding out a tempting item for the entity. Defaults: - *
      - *
    • 10x10x10 Radius
    • - *
    • No spectators
    • - *
    - * - * @see net.minecraft.world.entity.ai.sensing.TemptingSensor - * @param The entity - */ -public class ItemTemptingSensor extends PredicateSensor { - - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.TEMPTING_PLAYER); - - protected BiPredicate temptPredicate = (entity, stack) -> false; - - protected SquareRadius radius = new SquareRadius(10, 10); - - public ItemTemptingSensor() { - setPredicate((target, entity) -> { - if (target.isSpectator() || !target.isAlive()) - return false; - - return this.temptPredicate.test(entity, target.getMainHandItem()) || this.temptPredicate.test( - entity, - target.getOffhandItem() - ); - }); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.ITEM_TEMPTING.get(); - } - - /** - * Set the items to temptable items for the entity. - * - * @param temptingItems An ingredient representing the temptations for the entity - * @deprecated Use {@link ItemTemptingSensor#temptedWith} - * @return this - */ - @Deprecated(forRemoval = true) - public ItemTemptingSensor setTemptingItems(Ingredient temptingItems) { - return temptedWith((entity, stack) -> temptingItems.test(stack)); - } - - /** - * Set the items to temptable items for the entity. - * - * @param predicate An ingredient representing the temptations for the entity - * @return this - */ - public ItemTemptingSensor temptedWith(final BiPredicate predicate) { - this.temptPredicate = predicate; - - return this; - } - - /** - * Set the radius for the player sensor to scan - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public ItemTemptingSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the player sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public ItemTemptingSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Player player; - final List nearbyPlayers = BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_PLAYERS); - - if (nearbyPlayers != null) { - player = nearbyPlayers.stream() - .filter(pl -> predicate().test(pl, entity)) - .min(Comparator.comparing(pl -> pl.distanceToSqr(entity))) - .orElse(null); - } else { - player = EntityRetrievalUtil.getNearestPlayer( - entity, - this.radius.xzRadius(), - this.radius.yRadius(), - this.radius.xzRadius(), - target -> predicate().test(target, entity) - ); - } - - if (player == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.TEMPTING_PLAYER); - } else { - BrainUtils.setMemory(entity, MemoryModuleType.TEMPTING_PLAYER, player); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyAdultSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyAdultSensor.java deleted file mode 100644 index 44b41040b..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyAdultSensor.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import net.minecraft.world.entity.AgeableMob; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.SensorType; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; - -/** - * A sensor that sets the {@link MemoryModuleType#NEAREST_VISIBLE_ADULT} memory by checking the existing visible - * entities for nearby adults of the same entity type.
    - * - * @see net.minecraft.world.entity.ai.sensing.AdultSensor - * @param The entity - */ -public class NearbyAdultSensor extends EntityFilteringSensor { - - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_VISIBLE_ADULT; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_ADULT.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> target.getType() == entity.getType() && !target.isBaby(); - } - - @Nullable - @Override - protected AgeableMob findMatches(E entity, NearestVisibleLivingEntities matcher) { - return (AgeableMob) matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyBabySensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyBabySensor.java deleted file mode 100644 index 4c2debe9d..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyBabySensor.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import com.google.common.collect.ImmutableList; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.SensorType; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; - -/** - * A sensor that sets the {@link MemoryModuleType#VISIBLE_VILLAGER_BABIES} memory by checking the existing visible - * entities for nearby babies of the same entity type.
    - * - * @see net.minecraft.world.entity.ai.sensing.VillagerBabiesSensor - * @param The entity - */ -public class NearbyBabySensor extends EntityFilteringSensor, E> { - - @Override - public MemoryModuleType> getMemory() { - return MemoryModuleType.VISIBLE_VILLAGER_BABIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_BABY.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> target.getType() == entity.getType() && target.isBaby(); - } - - @Nullable - @Override - protected List findMatches(E entity, NearestVisibleLivingEntities matcher) { - return ImmutableList.copyOf(matcher.findAll(target -> predicate().test(target, entity))); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyGolemSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyGolemSensor.java deleted file mode 100644 index 9e8d6f887..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyGolemSensor.java +++ /dev/null @@ -1,90 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A sensor that sets the {@link MemoryModuleType#GOLEM_DETECTED_RECENTLY} memory by checking if any of the detected - * nearby entities are {@link net.minecraft.world.entity.animal.IronGolem Iron Golems}.
    - * Defaults: - *
      - *
    • 200-tick scan rate
    • - *
    • Only detects vanilla Iron Golems
    • - *
    • Remembers the nearby golem for 600 ticks
    • - *
    - * - * @see net.minecraft.world.entity.ai.sensing.GolemSensor - * @param The entity - */ -public class NearbyGolemSensor extends PredicateSensor { - - private static final List> MEMORIES = ObjectArrayList.of( - MemoryModuleType.GOLEM_DETECTED_RECENTLY - ); - - private int timeToRemember = 600; - - public NearbyGolemSensor() { - setScanRate(entity -> 200); - setPredicate((target, entity) -> target.getType() == EntityType.IRON_GOLEM && target.isAlive()); - } - - /** - * Set the amount of ticks the entity should remember that the golem is there. - * - * @param ticks The number of ticks to remember for - * @return this - */ - public NearbyGolemSensor setMemoryTime(int ticks) { - this.timeToRemember = ticks; - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_GOLEM.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.withMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entityList -> { - if (entityList.isEmpty()) - return; - - for (LivingEntity target : entityList) { - if (predicate().test(target, entity)) { - BrainUtils.setForgettableMemory( - entity, - MemoryModuleType.GOLEM_DETECTED_RECENTLY, - true, - this.timeToRemember - ); - - return; - } - } - }); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyHostileSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyHostileSensor.java deleted file mode 100644 index e2d916e16..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyHostileSensor.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.SensorType; -import org.jetbrains.annotations.Nullable; - -import java.util.Map; -import java.util.function.BiPredicate; - -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; - -/** - * A sensor that sets the {@link MemoryModuleType#NEAREST_HOSTILE} memory by checking the existing visible entities for - * nearby hostiles.
    - * By default, this is used for villager hostile detection, but it can be configured at instantiation for any types. - * - * @see net.minecraft.world.entity.ai.sensing.VillagerHostilesSensor - * @param The entity - */ -public class NearbyHostileSensor extends EntityFilteringSensor { - - private final Map, Float> hostileDistanceMap = new Object2FloatOpenHashMap<>(11); - - public NearbyHostileSensor() { - setHostiles( - Pair.of(EntityType.DROWNED, 8f), - Pair.of(EntityType.HUSK, 8f), - Pair.of(EntityType.VEX, 8f), - Pair.of(EntityType.ZOMBIE, 8f), - Pair.of(EntityType.ZOMBIE_VILLAGER, 8f), - Pair.of(EntityType.VINDICATOR, 10f), - Pair.of(EntityType.ZOGLIN, 10f), - Pair.of(EntityType.EVOKER, 12f), - Pair.of(EntityType.ILLUSIONER, 12f), - Pair.of(EntityType.RAVAGER, 12f), - Pair.of(EntityType.PILLAGER, 15f) - ); - } - - /** - * Clear the hostile types map, and add all of the given entries. - * - * @param entries The collection of entity types and distances to set the hostile types map to - * @return this - */ - public NearbyHostileSensor setHostiles(Pair, Float>... entries) { - this.hostileDistanceMap.clear(); - - for (Pair, Float> entry : entries) { - this.hostileDistanceMap.put(entry.getFirst(), entry.getSecond()); - } - - return this; - } - - /** - * Add an entity type to the hostile types map. - * - * @param entry The entity type and distance to which it should be considered. - * @return this - */ - public NearbyHostileSensor addHostile(Pair, Float> entry) { - this.hostileDistanceMap.put(entry.getFirst(), entry.getSecond()); - - return this; - } - - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_HOSTILE; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_HOSTILE.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> { - Float distance = this.hostileDistanceMap.get(target.getType()); - - return distance != null && target.distanceToSqr(entity) <= distance * distance; - }; - } - - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyLivingEntitySensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyLivingEntitySensor.java deleted file mode 100644 index 43a59ea64..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyLivingEntitySensor.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import org.jetbrains.annotations.Nullable; - -import java.util.Comparator; -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.FixedNearestVisibleLivingEntities; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -/** - * A sensor that looks for nearby living entities in the surrounding area, sorted by proximity to the brain owner.
    - * Defaults: - *
      - *
    • Radius is equivalent to the entity's {@link Attributes#FOLLOW_RANGE} attribute
    • - *
    • Only alive entities
    • - *
    - * - * @param The entity - */ -public class NearbyLivingEntitySensor extends PredicateSensor { - - private static final List> MEMORIES = ObjectArrayList.of( - MemoryModuleType.NEAREST_LIVING_ENTITIES, - MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES - ); - - @Nullable - protected SquareRadius radius = null; - - public NearbyLivingEntitySensor() { - super((target, entity) -> target != entity && target.isAlive()); - } - - /** - * Set the radius for the sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyLivingEntitySensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyLivingEntitySensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_LIVING_ENTITY.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - SquareRadius radius = this.radius; - - if (radius == null) { - double dist = entity.getAttributeValue(Attributes.FOLLOW_RANGE); - - radius = new SquareRadius(dist, dist); - } - - List entities = EntityRetrievalUtil.getEntities( - level, - entity.getBoundingBox().inflate(radius.xzRadius(), radius.yRadius(), radius.xzRadius()), - obj -> obj instanceof LivingEntity livingEntity && predicate().test(livingEntity, entity) - ); - - entities.sort(Comparator.comparingDouble(entity::distanceToSqr)); - - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities); - BrainUtils.setMemory( - entity, - MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, - new FixedNearestVisibleLivingEntities(entity, entities) - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyPlayersSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyPlayersSensor.java deleted file mode 100644 index c70fbfb52..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyPlayersSensor.java +++ /dev/null @@ -1,123 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.player.Player; -import org.jetbrains.annotations.Nullable; - -import java.util.Comparator; -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -/** - * A sensor that looks for nearby players in the surrounding area, sorted by proximity to the brain owner.
    - * Defaults: - *
      - *
    • Radius is equivalent to the entity's {@link Attributes#FOLLOW_RANGE} attribute
    • - *
    • No spectators
    • - *
    - * - * @param The entity - */ -public class NearbyPlayersSensor extends PredicateSensor { - - private static final List> MEMORIES = ObjectArrayList.of( - MemoryModuleType.NEAREST_PLAYERS, - MemoryModuleType.NEAREST_VISIBLE_PLAYER, - MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER - ); - - @Nullable - protected SquareRadius radius = null; - - public NearbyPlayersSensor() { - super((player, entity) -> !player.isSpectator()); - } - - /** - * Set the radius for the sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyPlayersSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyPlayersSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_PLAYERS.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - SquareRadius radius = this.radius; - - if (radius == null) { - double dist = entity.getAttributeValue(Attributes.FOLLOW_RANGE); - - radius = new SquareRadius(dist, dist); - } - - List players = EntityRetrievalUtil.getPlayers( - level, - radius.inflateAABB(entity.getBoundingBox()), - player -> predicate().test(player, entity) - ); - - players.sort(Comparator.comparingDouble(entity::distanceToSqr)); - - List targetablePlayers = new ObjectArrayList<>(players); - - targetablePlayers.removeIf(pl -> !isEntityTargetable(entity, pl)); - - List attackablePlayers = new ObjectArrayList<>(targetablePlayers); - - attackablePlayers.removeIf(pl -> !isEntityAttackable(entity, pl)); - - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_PLAYERS, players); - BrainUtils.setMemory( - entity, - MemoryModuleType.NEAREST_VISIBLE_PLAYER, - targetablePlayers.isEmpty() ? null : targetablePlayers.get(0) - ); - BrainUtils.setMemory( - entity, - MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, - attackablePlayers.isEmpty() ? null : attackablePlayers.get(0) - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestHomeSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestHomeSensor.java deleted file mode 100644 index 75ce366f8..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestHomeSensor.java +++ /dev/null @@ -1,116 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.behavior.AcquirePoi; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.ai.village.poi.PoiManager; -import net.minecraft.world.entity.ai.village.poi.PoiType; -import net.minecraft.world.entity.ai.village.poi.PoiTypes; -import net.minecraft.world.level.pathfinder.Path; - -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A sensor that looks for the nearest home point of interest in the surrounding area.
    - * Defaults: - *
      - *
    • 48 block radius
    • - *
    • Only runs if the owner of the brain is a baby
    • - *
    - * - * @param The entity - */ -public class NearestHomeSensor extends PredicateSensor { - - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_BED); - - protected int radius = 48; - - private final Object2LongOpenHashMap homesMap = new Object2LongOpenHashMap<>(5); - - private int tries = 0; - - public NearestHomeSensor() { - super((brainOwner, entity) -> brainOwner.isBaby()); - } - - /** - * Set the radius for the item sensor to scan - * - * @param radius The radius - * @return this - */ - public NearestHomeSensor setRadius(int radius) { - this.radius = radius; - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEAREST_HOME.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - if (!predicate().test(entity, entity)) - return; - - this.tries = 0; - long nodeExpiryTime = level.getGameTime() + level.getRandom().nextInt(20); - PoiManager poiManager = level.getPoiManager(); - Predicate predicate = pos -> { - if (this.homesMap.containsKey(pos)) - return false; - - if (++this.tries >= 5) - return false; - - this.homesMap.put(pos, nodeExpiryTime + 40); - - return true; - }; - Set, BlockPos>> poiLocations = poiManager.findAllWithType( - poiType -> poiType.is(PoiTypes.HOME), - predicate, - entity.blockPosition(), - this.radius, - PoiManager.Occupancy.ANY - ).collect(Collectors.toSet()); - Path pathToHome = AcquirePoi.findPathToPois(entity, poiLocations); - - if (pathToHome != null && pathToHome.canReach()) { - BlockPos targetPos = pathToHome.getTarget(); - - poiManager.getType(targetPos) - .ifPresent(poiType -> BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_BED, targetPos)); - } else if (this.tries < 5) { - this.homesMap.object2LongEntrySet().removeIf(pos -> pos.getLongValue() < nodeExpiryTime); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestItemSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestItemSensor.java deleted file mode 100644 index 899fdb1e2..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestItemSensor.java +++ /dev/null @@ -1,95 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -/** - * A sensor that looks for the nearest item entity in the surrounding area.
    - * Defaults: - *
      - *
    • 32x16x32 radius
    • - *
    • Only items that return true for {@link Mob#wantsToPickUp(ItemStack)}
    • - *
    • Only items that return true for {@link net.minecraft.world.entity.LivingEntity#hasLineOfSight(Entity)}
    • - *
    - * - * @param The entity - */ -public class NearestItemSensor extends PredicateSensor { - - private static final List> MEMORIES = ObjectArrayList.of( - MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM - ); - - protected SquareRadius radius = new SquareRadius(32, 16); - - public NearestItemSensor() { - super((item, entity) -> entity.wantsToPickUp(item.getItem()) && entity.hasLineOfSight(item)); - } - - /** - * Set the radius for the item sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearestItemSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the item sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearestItemSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEAREST_ITEM.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.setMemory( - entity, - MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, - EntityRetrievalUtil.getNearestEntity( - level, - this.radius.inflateAABB(entity.getBoundingBox()), - entity.position(), - obj -> obj instanceof ItemEntity item && predicate().test(item, entity) - ) - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinBruteSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinBruteSpecificSensor.java deleted file mode 100644 index 2881b4552..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinBruteSpecificSensor.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.boss.wither.WitherBoss; -import net.minecraft.world.entity.monster.WitherSkeleton; -import net.minecraft.world.entity.monster.piglin.AbstractPiglin; -import net.minecraft.world.entity.monster.piglin.Piglin; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.PiglinBruteSpecificSensor}. Not really - * useful, but included for completeness' sake and legibility.
    - * Keeps track of nearby {@link Piglin piglins} and {@link MemoryModuleType#NEAREST_VISIBLE_NEMESIS nemesis} - * - * @param The entity - */ -public class PiglinBruteSpecificSensor extends ExtendedSensor { - - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEARBY_ADULT_PIGLINS); - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.PIGLIN_BRUTE_SPECIFIC.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - List nearbyPiglins = new ObjectArrayList<>(); - - BrainUtils.withMemory( - brain, - MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, - entities -> BrainUtils.setMemory( - brain, - MemoryModuleType.NEAREST_VISIBLE_NEMESIS, - (Mob) entities.findClosest(target -> target instanceof WitherSkeleton || target instanceof WitherBoss) - .orElse(null) - ) - ); - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { - for (LivingEntity target : entities) { - if (target instanceof AbstractPiglin piglin && piglin.isAdult()) - nearbyPiglins.add(piglin); - } - }); - BrainUtils.setMemory(brain, MemoryModuleType.NEARBY_ADULT_PIGLINS, nearbyPiglins); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinSpecificSensor.java deleted file mode 100644 index cde09fd1c..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinSpecificSensor.java +++ /dev/null @@ -1,155 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.boss.wither.WitherBoss; -import net.minecraft.world.entity.monster.WitherSkeleton; -import net.minecraft.world.entity.monster.hoglin.Hoglin; -import net.minecraft.world.entity.monster.piglin.AbstractPiglin; -import net.minecraft.world.entity.monster.piglin.Piglin; -import net.minecraft.world.entity.monster.piglin.PiglinAi; -import net.minecraft.world.entity.monster.piglin.PiglinBrute; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.CampfireBlock; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.PiglinSpecificSensor}. Not really useful, but - * included for completeness' sake and legibility.
    - * Handles most of Piglin's memories at once. - * - * @param The entity - */ -public class PiglinSpecificSensor extends ExtendedSensor { - - private static final List> MEMORIES = ObjectArrayList.of( - MemoryModuleType.NEAREST_VISIBLE_NEMESIS, - MemoryModuleType.NEAREST_VISIBLE_HUNTABLE_HOGLIN, - MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, - MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, - MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD, - MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM, - MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, - MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, - MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, - MemoryModuleType.NEAREST_REPELLENT, - MemoryModuleType.NEAREST_LIVING_ENTITIES, - MemoryModuleType.NEARBY_ADULT_PIGLINS - ); - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.PIGLIN_SPECIFIC.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - List adultPiglins = new ObjectArrayList<>(); - - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, entities -> { - Mob nemesis = null; - Hoglin nearestHuntableHoglin = null; - Hoglin nearestBabyHoglin = null; - LivingEntity nearestZombified = null; - Player nearestPlayerWithoutGold = null; - Player nearestPlayerWithWantedItem = null; - List visibleAdultPiglins = new ObjectArrayList<>(); - int adultHoglinCount = 0; - - for (LivingEntity target : entities.findAll(obj -> true)) { - if (target instanceof Hoglin hoglin) { - if (hoglin.isBaby() && nearestBabyHoglin == null) { - nearestBabyHoglin = hoglin; - } else if (hoglin.isAdult()) { - adultHoglinCount++; - - if (nearestHuntableHoglin == null && hoglin.canBeHunted()) - nearestHuntableHoglin = hoglin; - } - } else if (target instanceof PiglinBrute brute) { - visibleAdultPiglins.add(brute); - } else if (target instanceof Piglin piglin) { - if (piglin.isAdult()) - visibleAdultPiglins.add(piglin); - } else if (target instanceof Player player) { - if (nearestPlayerWithoutGold == null && !PiglinAi.isWearingGold(player) && entity.canAttack(player)) - nearestPlayerWithoutGold = player; - - if ( - nearestPlayerWithWantedItem == null && !player.isSpectator() && PiglinAi - .isPlayerHoldingLovedItem(player) - ) - nearestPlayerWithWantedItem = player; - } else if (nemesis != null || !(target instanceof WitherSkeleton) && !(target instanceof WitherBoss)) { - if (nearestZombified == null && PiglinAi.isZombified(target.getType())) - nearestZombified = target; - } else { - nemesis = (Mob) target; - } - } - - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_NEMESIS, nemesis); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_HUNTABLE_HOGLIN, nearestHuntableHoglin); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, nearestBabyHoglin); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, nearestZombified); - BrainUtils.setMemory( - brain, - MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD, - nearestPlayerWithoutGold - ); - BrainUtils.setMemory( - brain, - MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM, - nearestPlayerWithWantedItem - ); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, visibleAdultPiglins); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, visibleAdultPiglins.size()); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, adultHoglinCount); - BrainUtils.setMemory( - brain, - MemoryModuleType.NEAREST_REPELLENT, - BlockPos.findClosestMatch(entity.blockPosition(), 8, 4, pos -> { - BlockState state = level.getBlockState(pos); - boolean isRepellent = state.is(BlockTags.PIGLIN_REPELLENTS); - - return isRepellent && state.is(Blocks.SOUL_CAMPFIRE) - ? CampfireBlock.isLitCampfire(state) - : isRepellent; - }).orElse(null) - ); - }); - - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { - for (LivingEntity target : entities) { - if (target instanceof AbstractPiglin piglin && piglin.isAdult()) - adultPiglins.add(piglin); - } - }); - BrainUtils.setMemory(brain, MemoryModuleType.NEARBY_ADULT_PIGLINS, adultPiglins); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/SecondaryPoiSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/SecondaryPoiSensor.java deleted file mode 100644 index f0d341f24..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/SecondaryPoiSensor.java +++ /dev/null @@ -1,111 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import com.google.common.collect.ImmutableSet; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.core.GlobalPos; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.npc.Villager; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A sensor that looks for a nearby {@link net.minecraft.world.entity.ai.village.poi.PoiTypes POI} block that matches a - * villager's secondary profession.
    - * Defaults: - *
      - *
    • 40-tick scan rate
    • - *
    • 8x4x8 radius
    • - *
    - * - * @param The entity - */ -public class SecondaryPoiSensor extends ExtendedSensor { - - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.SECONDARY_JOB_SITE); - - protected SquareRadius radius = new SquareRadius(8, 4); - - public SecondaryPoiSensor() { - setScanRate(entity -> 40); - } - - /** - * Set the radius for the sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public SecondaryPoiSensor setRadius(int radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SecondaryPoiSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.SECONDARY_POI.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - ResourceKey dimension = level.dimension(); - BlockPos pos = entity.blockPosition(); - ImmutableSet testPoiBlocks = entity.getVillagerData().getProfession().secondaryPoi(); - List poiPositions = new ObjectArrayList<>(); - - if (testPoiBlocks.isEmpty()) - return; - - for ( - BlockPos testPos : BlockPos.betweenClosed( - pos.getX() - (int) this.radius.xzRadius() / 2, - pos.getY() - (int) this.radius.yRadius() / 2, - pos.getZ() - (int) this.radius.xzRadius() / 2, - pos.getX() + (int) this.radius.xzRadius() / 2, - pos.getY() + (int) this.radius.yRadius() / 2, - pos.getZ() + (int) this.radius.xzRadius() / 2 - ) - ) { - if (testPoiBlocks.contains(level.getBlockState(testPos).getBlock())) - poiPositions.add(GlobalPos.of(dimension, testPos.immutable())); - } - - if (poiPositions.isEmpty()) { - BrainUtils.clearMemory(entity, MemoryModuleType.SECONDARY_JOB_SITE); - } else { - BrainUtils.setMemory(entity, MemoryModuleType.SECONDARY_JOB_SITE, poiPositions); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/WardenSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/WardenSpecificSensor.java deleted file mode 100644 index f796b4863..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/WardenSpecificSensor.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.monster.warden.Warden; -import net.minecraft.world.entity.player.Player; - -import java.util.List; - -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.WardenEntitySensor}. Not really useful, but - * included for completeness' sake and legibility.
    - * Handle's the Warden's nearest attackable target, prioritising players. - * - * @param The entity - */ -public class WardenSpecificSensor extends NearbyLivingEntitySensor { - - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_ATTACKABLE); - - public WardenSpecificSensor() { - setRadius(24); - setPredicate((target, entity) -> entity.canTargetEntity(target)); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.WARDEN_SPECIFIC.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - super.doTick(level, entity); - - BrainUtils.withMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { - LivingEntity fallbackTarget = null; - - for (LivingEntity target : entities) { - if (target instanceof Player) { - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE, target); - - return; - } else if (fallbackTarget == null) { - fallbackTarget = target; - } - } - - if (fallbackTarget != null) { - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE, fallbackTarget); - } else { - BrainUtils.clearMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE); - } - }); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourConsumer.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourConsumer.java deleted file mode 100644 index 493906f5a..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourConsumer.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import net.minecraft.world.entity.schedule.Activity; -import org.jetbrains.annotations.Nullable; - -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; - -/** - * Functional consumer for brain activity related functions - */ -@FunctionalInterface -public interface BrainBehaviourConsumer { - - /** - * Accepts the given behaviour and the information related to it - * - * @param priority The priority the behaviour is nested under - * @param activity The activity category the behaviour is under - * @param behaviour The behaviour - * @param parent The {@link net.minecraft.world.entity.ai.behavior.GateBehavior GateBehaviour} or - * {@link GroupBehaviour GroupBehaviour} the behaviour is a child of, if applicable - */ - void consume(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parent); -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourPredicate.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourPredicate.java deleted file mode 100644 index 8ff5d784c..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourPredicate.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import net.minecraft.world.entity.schedule.Activity; -import org.jetbrains.annotations.Nullable; - -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; - -/** - * Functional interface to handle passing multiple arguments back for behaviour-predication handling - */ -@FunctionalInterface -public interface BrainBehaviourPredicate { - - /** - * Tests whether the given behaviour is relevant to the predicate. - * - * @param priority The priority the behaviour is nested under - * @param activity The activity category the behaviour is under - * @param behaviour The behaviour to check - * @param parentBehaviour The {@link net.minecraft.world.entity.ai.behavior.GateBehavior GateBehaviour} or - * {@link GroupBehaviour GroupBehaviour} the behaviour is a child of, if applicable - */ - boolean isBehaviour( - int priority, - Activity activity, - BehaviorControl behaviour, - @Nullable BehaviorControl parentBehaviour - ); -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/ExtendedTargetingConditions.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/ExtendedTargetingConditions.java deleted file mode 100644 index 2d9dd70ac..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/ExtendedTargetingConditions.java +++ /dev/null @@ -1,157 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import net.minecraft.world.Difficulty; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.attributes.Attributes; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiPredicate; -import java.util.function.Function; - -import mod.azure.azurelib.sblforked.util.SensoryUtils; - -/** - * Replacement for Vanilla's {@link net.minecraft.world.entity.ai.targeting.TargetingConditions} due to its somewhat - * limited implementation - */ -public class ExtendedTargetingConditions { - - protected BiPredicate customFilter = null; - - protected Function rangeRetriever = null; - - protected boolean isAttacking = true; - - protected boolean checkLineOfSight = true; - - protected boolean ignoresInvisibility = false; - - public static ExtendedTargetingConditions forLookTarget() { - return new ExtendedTargetingConditions().isJustLooking(); - } - - public static ExtendedTargetingConditions forLookTargetIgnoringInvisibility() { - return forLookTarget().skipInvisibilityCheck(); - } - - public static ExtendedTargetingConditions forAttackTarget() { - return new ExtendedTargetingConditions(); - } - - public static ExtendedTargetingConditions forAttackTargetIgnoringInvisibility() { - return forAttackTarget().skipInvisibilityCheck(); - } - - /** - * Skip any attack-related checks in the predicate, such as difficulty, invulnerability, or teams - */ - public ExtendedTargetingConditions isJustLooking() { - this.isAttacking = false; - - return this; - } - - /** - * Filter out any targeting that occurs for entities larger than this distance away from the entity - */ - public ExtendedTargetingConditions withRange(double range) { - return withRange(entity -> range); - } - - /** - * Filter out any targeting that occurs for entities larger than the distance provided by this function from the - * entity - */ - public ExtendedTargetingConditions withRange(Function function) { - this.rangeRetriever = function; - - return this; - } - - /** - * Filter out any targeting that occurs for entities outside of the entity's {@link Attributes#FOLLOW_RANGE} - * attribute - */ - public ExtendedTargetingConditions withFollowRange() { - return withRange( - entity -> entity.getAttribute(Attributes.FOLLOW_RANGE) != null - ? entity.getAttributeValue(Attributes.FOLLOW_RANGE) - : 16d - ); - } - - /** - * Additionally filter out any specific cases that may apply. This check is applied before any other - * conditions are checked - *

    - * Note that the targeting entity may be null, for generic checks - *

    - * - * @return true if the entity should be allowed to target the target, or false if not - */ - public ExtendedTargetingConditions onlyTargeting(BiPredicate<@Nullable LivingEntity, LivingEntity> predicate) { - this.customFilter = predicate; - - return this; - } - - /** - * Skip the line of sight checks in the predicate. This can be useful for entities that track with other senses, or - * for other special-case situations - */ - public ExtendedTargetingConditions ignoreLineOfSight() { - this.checkLineOfSight = false; - - return this; - } - - /** - * Skip the invisibility check for targeting. This is often used where the entity is already being targeted/tracked, - * and we're just checking for attackability. - */ - public ExtendedTargetingConditions skipInvisibilityCheck() { - this.ignoresInvisibility = true; - - return this; - } - - public boolean test(@Nullable LivingEntity entity, LivingEntity target) { - if (entity == target || !target.canBeSeenByAnyone()) - return false; - - if (this.customFilter != null && !this.customFilter.test(entity, target)) - return false; - - if (entity == null) - return !this.isAttacking || (target.canBeSeenAsEnemy() && target.level() - .getDifficulty() != Difficulty.PEACEFUL); - - if ( - this.isAttacking && (!entity.canAttack(target) || !entity.canAttackType(target.getType()) || entity - .isAlliedTo(target)) - ) - return false; - - double range = this.rangeRetriever.apply(entity); - - if (range > 0) { - double sightRange = Math.max( - range * (this.ignoresInvisibility ? 1 : target.getVisibilityPercent(entity)), - 2 - ); - - if (entity.distanceToSqr(target) > sightRange * sightRange) - return false; - } - - if (this.checkLineOfSight) - return SensoryUtils.hasLineOfSight(entity, target); - - return true; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/FixedNearestVisibleLivingEntities.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/FixedNearestVisibleLivingEntities.java deleted file mode 100644 index be1d28b9b..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/FixedNearestVisibleLivingEntities.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; - -import java.util.List; -import java.util.function.Predicate; - -import mod.azure.azurelib.sblforked.util.SensoryUtils; - -/** - * Wrapper for {@link NearestVisibleLivingEntities} that supports follow range for entities rather than a hardcoded - * 16-block limit - */ -public class FixedNearestVisibleLivingEntities extends NearestVisibleLivingEntities { - - private FixedNearestVisibleLivingEntities() { - super(); - } - - public FixedNearestVisibleLivingEntities(LivingEntity entity, List entities) { - super(); - - this.nearbyEntities = entities; - this.lineOfSightTest = new Predicate<>() { - - final Object2BooleanOpenHashMap cache = new Object2BooleanOpenHashMap<>(entities.size()); - - @Override - public boolean test(LivingEntity target) { - return this.cache.computeIfAbsent( - target, - (Predicate) target1 -> SensoryUtils.isEntityTargetable(entity, target1) - ); - } - }; - } - - public static FixedNearestVisibleLivingEntities empty() { - return new FixedNearestVisibleLivingEntities(); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/FreePositionTracker.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/FreePositionTracker.java deleted file mode 100644 index 53af3ddc0..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/FreePositionTracker.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.PositionTracker; -import net.minecraft.world.phys.Vec3; - -public class FreePositionTracker implements PositionTracker { - - private final Vec3 pos; - - public FreePositionTracker(Vec3 pos) { - this.pos = pos; - } - - @Override - public Vec3 currentPosition() { - return pos; - } - - @Override - public BlockPos currentBlockPosition() { - return BlockPos.containing(pos); - } - - @Override - public boolean isVisibleBy(LivingEntity entity) { - return true; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/SBLShufflingList.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/SBLShufflingList.java deleted file mode 100644 index c7a4a4808..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/SBLShufflingList.java +++ /dev/null @@ -1,124 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectIterators; -import net.minecraft.util.RandomSource; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.function.Consumer; -import java.util.stream.Stream; - -public class SBLShufflingList implements Iterable { - - private final List> entries; - - private final RandomSource random = RandomSource.createNewThreadLocalInstance(); - - public SBLShufflingList() { - this.entries = new ObjectArrayList<>(); - } - - public SBLShufflingList(int size) { - this.entries = new ObjectArrayList<>(size); - } - - public SBLShufflingList(Pair... entries) { - this.entries = new ObjectArrayList<>(entries.length); - - for (Pair entry : entries) { - this.entries.add(new WeightedEntry<>(entry.getFirst(), entry.getSecond())); - } - } - - public SBLShufflingList shuffle() { - this.entries.forEach(entry -> entry.setShuffledWeight(this.random.nextFloat())); - this.entries.sort(Comparator.comparingDouble(WeightedEntry::getShuffledWeight)); - - return this; - } - - public boolean add(T entry, int weight) { - return this.entries.add(new WeightedEntry<>(entry, weight)); - } - - @Nullable - public T get(int index) { - return this.entries.get(index).get(); - } - - @NotNull - @Override - public Iterator iterator() { - return new ObjectIterators.AbstractIndexBasedIterator<>(0, 0) { - - @Override - protected T get(int location) { - return SBLShufflingList.this.entries.get(location).get(); - } - - @Override - protected void remove(int location) { - SBLShufflingList.this.entries.remove(location); - } - - @Override - protected int getMaxPos() { - return SBLShufflingList.this.entries.size(); - } - }; - } - - @Override - public void forEach(Consumer action) { - this.entries.forEach(entry -> action.accept(entry.get())); - } - - public Stream stream() { - return this.entries.stream().map(WeightedEntry::get); - } - - public static class WeightedEntry { - - private final T object; - - private final int weight; - - private double shuffledWeight; - - WeightedEntry(T object, int weight) { - this.object = object; - this.weight = weight; - } - - double getShuffledWeight() { - return this.shuffledWeight; - } - - T get() { - return this.object; - } - - int getWeight() { - return this.weight; - } - - void setShuffledWeight(float mod) { - this.shuffledWeight = -Math.pow(mod, 1f / this.weight); - } - - @Override - public String toString() { - return this.object + ":" + this.weight; - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/SquareRadius.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/SquareRadius.java deleted file mode 100644 index 0767b701b..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/SquareRadius.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Vec3i; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; - -/** - * Helper class to store radius values without needlessly using 3 values.
    - * Also comes with some handy helper methods. - * - * @param xzRadius The lateral radius value (X/Z direction) - * @param yRadius The vertical radius value (Y direction) - */ -public record SquareRadius( - double xzRadius, - double yRadius -) { - - public Vec3i toVec3i() { - return new Vec3i((int) this.xzRadius, (int) this.yRadius, (int) this.xzRadius); - } - - public BlockPos toBlockPos() { - return BlockPos.containing(this.xzRadius, this.yRadius, this.xzRadius); - } - - public Vec3 toVec3() { - return new Vec3(this.xzRadius, this.yRadius, this.xzRadius); - } - - public AABB inflateAABB(AABB bounds) { - return bounds.inflate(this.xzRadius, this.yRadius, this.xzRadius); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/TriPredicate.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/TriPredicate.java deleted file mode 100644 index 1bd8753b3..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/TriPredicate.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import java.util.Objects; - -/** - * Triple-argument variant of {@link java.util.function.Predicate} - */ -@FunctionalInterface -public interface TriPredicate { - - boolean test(A a, B b, C c); - - default TriPredicate and(TriPredicate other) { - Objects.requireNonNull(other); - - return (A a, B b, C c) -> test(a, b, c) && other.test(a, b, c); - } - - default TriPredicate negate() { - return (A a, B b, C c) -> !test(a, b, c); - } - - default TriPredicate or(TriPredicate other) { - Objects.requireNonNull(other); - - return (A a, B b, C c) -> test(a, b, c) || other.test(a, b, c); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLMemoryTypes.java b/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLMemoryTypes.java deleted file mode 100644 index df5d1b2d1..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLMemoryTypes.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.registry; - -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Codec; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.projectile.Projectile; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.List; -import java.util.Optional; -import java.util.function.Supplier; - -import mod.azure.azurelib.sblforked.SBLConstants; - -/** - * Registry class for custom {@link MemoryModuleType Memory Types} - */ -public final class SBLMemoryTypes { - - public static void init() {} - - public static final Supplier>> INCOMING_PROJECTILES = register( - "incoming_projectiles" - ); - - public static final Supplier> TARGET_UNREACHABLE = register("target_unreachable"); - - public static final Supplier> SPECIAL_ATTACK_COOLDOWN = register( - "special_attack_cooldown" - ); - - public static final Supplier>>> NEARBY_BLOCKS = register( - "nearby_blocks" - ); - - public static final Supplier>> NEARBY_ITEMS = register("nearby_items"); - - private static Supplier> register(String id) { - return register(id, Optional.empty()); - } - - private static Supplier> register(String id, Optional> codec) { - return SBLConstants.SBL_LOADER.registerMemoryType(id, codec); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLSensors.java b/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLSensors.java deleted file mode 100644 index afb456fb6..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLSensors.java +++ /dev/null @@ -1,139 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.registry; - -import net.minecraft.world.entity.ai.sensing.SensorType; - -import java.util.function.Supplier; - -import mod.azure.azurelib.sblforked.SBLConstants; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.custom.*; -import mod.azure.azurelib.sblforked.api.core.sensor.vanilla.*; - -/** - * Registry class for {@link ExtendedSensor} implementations - */ -public final class SBLSensors { - - public static void init() {} - - // Vanilla sensors - public static final Supplier>> NEAREST_ITEM = register( - "nearest_item", - NearestItemSensor::new - ); - - public static final Supplier>> NEARBY_LIVING_ENTITY = register( - "nearby_living_entity", - NearbyLivingEntitySensor::new - ); - - public static final Supplier>> NEARBY_PLAYERS = register( - "nearby_players", - NearbyPlayersSensor::new - ); - - public static final Supplier>> NEAREST_HOME = register( - "nearest_home", - NearestHomeSensor::new - ); - - public static final Supplier>> HURT_BY = register("hurt_by", HurtBySensor::new); - - public static final Supplier>> NEARBY_HOSTILE = register( - "nearby_hostile", - NearbyHostileSensor::new - ); - - public static final Supplier>> NEARBY_BABY = register( - "nearby_baby", - NearbyBabySensor::new - ); - - public static final Supplier>> SECONDARY_POI = register( - "secondary_poi", - SecondaryPoiSensor::new - ); - - public static final Supplier>> NEARBY_GOLEM = register( - "nearby_golem", - NearbyGolemSensor::new - ); - - public static final Supplier>> NEARBY_ADULT = register( - "nearby_adult", - NearbyAdultSensor::new - ); - - public static final Supplier>> ITEM_TEMPTING = register( - "item_tempting", - ItemTemptingSensor::new - ); - - public static final Supplier>> IN_WATER = register("in_water", InWaterSensor::new); - - // Entity Specific - public static final Supplier>> FROG_SPECIFIC = register( - "frog_specific", - FrogSpecificSensor::new - ); - - public static final Supplier>> AXOLOTL_SPECIFIC = register( - "axolotl_specific", - AxolotlSpecificSensor::new - ); - - public static final Supplier>> PIGLIN_SPECIFIC = register( - "piglin_specific", - PiglinSpecificSensor::new - ); - - public static final Supplier>> PIGLIN_BRUTE_SPECIFIC = register( - "piglin_brute_specific", - PiglinBruteSpecificSensor::new - ); - - public static final Supplier>> HOGLIN_SPECIFIC = register( - "hoglin_specific", - HoglinSpecificSensor::new - ); - - public static final Supplier>> WARDEN_SPECIFIC = register( - "warden_specific", - WardenSpecificSensor::new - ); - - // Custom - public static final Supplier>> INCOMING_PROJECTILES = register( - "incoming_projectiles", - IncomingProjectilesSensor::new - ); - - public static final Supplier>> GENERIC_ATTACK_TARGET = register( - "generic_attack_target", - GenericAttackTargetSensor::new - ); - - public static final Supplier>> UNREACHABLE_TARGET = register( - "unreachable_target", - UnreachableTargetSensor::new - ); - - public static final Supplier>> NEARBY_BLOCKS = register( - "nearby_blocks", - NearbyBlocksSensor::new - ); - - public static final Supplier>> NEARBY_ITEMS = register( - "nearby_items", - NearbyItemsSensor::new - ); - - private static > Supplier> register(String id, Supplier sensor) { - return SBLConstants.SBL_LOADER.registerSensorType(id, sensor); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/BrainUtils.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/BrainUtils.java deleted file mode 100644 index 7037b3276..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/BrainUtils.java +++ /dev/null @@ -1,650 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.util; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.behavior.Behavior; -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.behavior.GateBehavior; -import net.minecraft.world.entity.ai.memory.ExpirableValue; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.Sensor; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.schedule.Activity; -import net.minecraft.world.entity.schedule.Schedule; -import net.minecraft.world.entity.schedule.Timeline; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.stream.Stream; - -import mod.azure.azurelib.sblforked.api.core.BrainActivityGroup; -import mod.azure.azurelib.sblforked.api.core.SmartBrain; -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; -import mod.azure.azurelib.sblforked.api.core.schedule.SmartBrainSchedule; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.object.BrainBehaviourConsumer; -import mod.azure.azurelib.sblforked.object.BrainBehaviourPredicate; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; - -/** - * Utility class for various brain functions. Try to utilise this where possible to ensure consistency and safety. - */ -public final class BrainUtils { - - /** - * Get a memory value from an entity, with a fallback value if no memory is present - * - * @param entity The entity - * @param memory Memory type to get the value for - * @param fallback Fallback value if no memory value is present - * @return The stored memory, or fallback value if no memory was stored - * @param The type of object the memory uses - */ - public static T memoryOrDefault(LivingEntity entity, MemoryModuleType memory, Supplier fallback) { - return memoryOrDefault(entity.getBrain(), memory, fallback); - } - - /** - * Get a memory value from a brain, with a fallback value if no memory is present - * - * @param brain The brain - * @param memory Memory type to get the value for - * @param fallback Fallback value if no memory value is present - * @return The stored memory, or fallback value if no memory was stored - * @param The type of object the memory uses - */ - public static T memoryOrDefault(Brain brain, MemoryModuleType memory, Supplier fallback) { - return brain.getMemory(memory).orElseGet(fallback); - } - - /** - * Get a memory value from an entity, or null if no memory is present - * - * @param entity The entity - * @param memory Memory type to get the value for - * @return The stored memory, or null if no memory was stored - * @param The type of object the memory uses - */ - @Nullable - public static T getMemory(LivingEntity entity, MemoryModuleType memory) { - return getMemory(entity.getBrain(), memory); - } - - /** - * Get a memory value from a brain, or null if no memory is present - * - * @param brain The brain - * @param memory Memory type to get the value for - * @return The stored memory, or null if no memory was stored - * @param The type of object the memory uses - */ - @Nullable - public static T getMemory(Brain brain, MemoryModuleType memory) { - return memoryOrDefault(brain, memory, () -> null); - } - - /** - * Perform an operation on a given memory value, if present. If no memory value set, operation is not run - * - * @param entity The entity - * @param memory Memory type to get the value for - * @param consumer The operation to run if the memory is present - * @param The type of object the memory uses - */ - public static void withMemory(LivingEntity entity, MemoryModuleType memory, Consumer consumer) { - withMemory(entity.getBrain(), memory, consumer); - } - - /** - * Perform an operation on a given memory value, if present. If no memory value set, operation is not run - * - * @param brain The brain - * @param memory Memory type to get the value for - * @param consumer The operation to run if the memory is present - * @param The type of object the memory uses - */ - public static void withMemory(Brain brain, MemoryModuleType memory, Consumer consumer) { - brain.getMemory(memory).ifPresent(consumer); - } - - /** - * Check whether an entity has a memory value set. - * - * @param entity The entity - * @param memory Memory type to get the value for - * @return True if the memory value is present, or false if the memory value is absent or unregistered - */ - public static boolean hasMemory(LivingEntity entity, MemoryModuleType memory) { - return hasMemory(entity.getBrain(), memory); - } - - /** - * Check whether a brain has a memory value set. - * - * @param brain The brain - * @param memory Memory type to get the value for - * @return True if the memory value is present, or false if the memory value is absent or unregistered - */ - public static boolean hasMemory(Brain brain, MemoryModuleType memory) { - return brain.hasMemoryValue(memory); - } - - /** - * Gets the ticks remaining until a memory expires. - * - * @param entity The entity - * @param memory Memory type to get the expiry time for - * @return The ticks until the memory expires, or 0 if the memory doesn't exist or doesn't expire - */ - public static long getTimeUntilMemoryExpires(LivingEntity entity, MemoryModuleType memory) { - return getTimeUntilMemoryExpires(entity.getBrain(), memory); - } - - /** - * Gets the ticks remaining until a memory expires. - * - * @param brain The brain - * @param memory Memory type to get the expiry time for - * @return The ticks until the memory expires, or 0 if the memory doesn't exist or doesn't expire - */ - public static long getTimeUntilMemoryExpires(Brain brain, MemoryModuleType memory) { - return brain.getTimeUntilExpiry(memory); - } - - /** - * Set an entity's memory value for the given memory type.
    - * Use {@link BrainUtils#clearMemory(LivingEntity, MemoryModuleType)} if intending to set a memory to nothing. - * - * @param entity The entity - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param The type of object the memory uses - */ - public static void setMemory(LivingEntity entity, MemoryModuleType memoryType, T memory) { - setMemory(entity.getBrain(), memoryType, memory); - } - - /** - * Set a brain's memory value for the given memory type.
    - * Use {@link BrainUtils#clearMemory(Brain, MemoryModuleType)} if intending to set a memory to nothing. - * - * @param brain The brain - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param The type of object the memory uses - */ - public static void setMemory(Brain brain, MemoryModuleType memoryType, T memory) { - brain.setMemory(memoryType, memory); - } - - /** - * Set a brain's memory value for the given memory type, with the memory expiring after a certain time.
    - * Use {@link BrainUtils#clearMemory(LivingEntity, MemoryModuleType)} if intending to set a memory to nothing. - * - * @param entity The entity - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param expirationTicks How many ticks until the memory expires - * @param The type of object the memory uses - */ - public static void setForgettableMemory( - LivingEntity entity, - MemoryModuleType memoryType, - T memory, - int expirationTicks - ) { - setForgettableMemory(entity.getBrain(), memoryType, memory, expirationTicks); - } - - /** - * Set an entity's memory value for the given memory type, with the memory expiring after a certain time.
    - * Use {@link BrainUtils#clearMemory(Brain, MemoryModuleType)} if intending to set a memory to nothing. - * - * @param brain The brain - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param expirationTicks How many ticks until the memory expires - * @param The type of object the memory uses - */ - public static void setForgettableMemory( - Brain brain, - MemoryModuleType memoryType, - T memory, - int expirationTicks - ) { - brain.setMemoryWithExpiry(memoryType, memory, expirationTicks); - } - - /** - * Wipe an entity's memory value for the given memory type. This safely unsets a memory, returning it to empty. - * - * @param entity The entity - * @param memory Memory type to erase the value for - */ - public static void clearMemory(LivingEntity entity, MemoryModuleType memory) { - clearMemory(entity.getBrain(), memory); - } - - /** - * Wipe a brain's memory value for the given memory type. This safely unsets a memory, returning it to empty. - * - * @param brain The brain - * @param memory Memory type to erase the value for - */ - public static void clearMemory(Brain brain, MemoryModuleType memory) { - brain.eraseMemory(memory); - } - - /** - * Wipe multiple memories for a given entity. This safely unsets each memory, returning them to empty. - * - * @param entity The entity - * @param memories The list of memory types to erase the values for - */ - public static void clearMemories(LivingEntity entity, MemoryModuleType... memories) { - clearMemories(entity.getBrain(), memories); - } - - /** - * Wipe multiple memories for a given brain. This safely unsets each memory, returning them to empty. - * - * @param brain The brain - * @param memories The list of memory types to erase the values for - */ - public static void clearMemories(Brain brain, MemoryModuleType... memories) { - for (MemoryModuleType memory : memories) { - brain.eraseMemory(memory); - } - } - - /** - * Gets the current attack target of an entity, if present. - * - * @param entity The entity - * @return The current attack target of the entity, or null if none present - */ - @Nullable - public static LivingEntity getTargetOfEntity(LivingEntity entity) { - return getTargetOfEntity(entity, null); - } - - /** - * Gets the current attack target of an entity, if present, or an optional fallback entity if none present - * - * @param entity The entity - * @param fallback Optional fallback entity to return if no attack target is set. - * @return The current attack target of the entity, the fallback entity if provided, or null otherwise - */ - @Nullable - public static LivingEntity getTargetOfEntity(LivingEntity entity, @Nullable LivingEntity fallback) { - return memoryOrDefault(entity.getBrain(), MemoryModuleType.ATTACK_TARGET, () -> fallback); - } - - /** - * Gets the last entity to attack the given entity, if present.
    - * Requires that the entity uses the {@link MemoryModuleType#HURT_BY_ENTITY} memory type, and a sensor that sets it - * - * @param entity The entity - * @return The last entity to attack the given entity, or null if none present - */ - @Nullable - public static LivingEntity getLastAttacker(LivingEntity entity) { - return memoryOrDefault(entity, MemoryModuleType.HURT_BY_ENTITY, () -> null); - } - - /** - * Sets the attack target of the given entity, and safely sets the non-brain attack target for compatibility - * purposes.
    - * Provided target can be null to effectively remove an entity's attack target. - * - * @param entity The entity - * @param target The entity to target - */ - public static void setTargetOfEntity(LivingEntity entity, @Nullable LivingEntity target) { - if (entity instanceof Mob mob) - mob.setTarget(target); - - if (target == null) { - clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } else { - setMemory(entity, MemoryModuleType.ATTACK_TARGET, target); - } - } - - /** - * Replacement of {@link net.minecraft.world.entity.ai.behavior.BehaviorUtils#canSee}, falling back to a raytrace - * check in the event the target entity isn't in the {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory - * - * @param entity The entity to check the brain of - * @param target The target entity - * @return Whether the target entity is known to be visible or not - */ - public static boolean canSee(LivingEntity entity, LivingEntity target) { - Brain brain = entity.getBrain(); - - if (BehaviorUtils.entityIsVisible(brain, target)) - return true; - - return entity.hasLineOfSight(target); - } - - /** - * Sets a {@link SBLMemoryTypes#SPECIAL_ATTACK_COOLDOWN} value for a certain length of time.
    - * This can then be checked via {@link BrainUtils#isOnSpecialCooldown(LivingEntity)} as needed. - * - * @param entity The entity to check the brain of - * @param ticks The length of time (in ticks) the cooldown should apply for - */ - public static void setSpecialCooldown(LivingEntity entity, int ticks) { - setForgettableMemory(entity, SBLMemoryTypes.SPECIAL_ATTACK_COOLDOWN.get(), true, ticks); - } - - /** - * Checks whether the entity has had a {@link SBLMemoryTypes#SPECIAL_ATTACK_COOLDOWN} set, and it hasn't - * expired.
    - * This can be used for cross-behaviour cooldowns and interactions - * - * @param entity The entity to check the brain of - * @return Whether the entity has a cooldown currently active - */ - public static boolean isOnSpecialCooldown(LivingEntity entity) { - return hasMemory(entity, SBLMemoryTypes.SPECIAL_ATTACK_COOLDOWN.get()); - } - - /** - * Returns a stream of all {@link BehaviorControl Behaviours} registered to this brain - */ - public static Stream> getAllBehaviours(Brain brain) { - if (brain instanceof SmartBrain smartBrain) - return smartBrain.getBehaviours(); - - return brain.availableBehaviorsByPriority.values() - .stream() - .map(Map::values) - .flatMap(set -> set.stream().map(value -> value.stream().toList()).flatMap(List::stream)); - } - - /** - * Loops over all {@link BehaviorControl Behaviours} registered to this brain, calling the consumer for each - * - * @param brain The brain to scrape the behaviours of - * @param consumer The consumer called for each - */ - public static void forEachBehaviour(Brain brain, BrainBehaviourConsumer consumer) { - if (brain instanceof SmartBrain smartBrain) { - smartBrain.forEachBehaviour(consumer); - - return; - } - - Set>>>> behaviours = - (Set) brain.availableBehaviorsByPriority.entrySet(); - - for (Map.Entry>>> priorityEntry : behaviours) { - Integer priority = priorityEntry.getKey(); - - for (Map.Entry>> activityEntry : priorityEntry.getValue().entrySet()) { - Activity activity = activityEntry.getKey(); - - for (BehaviorControl behaviour : activityEntry.getValue()) { - consumeBehaviour(priority, activity, behaviour, null, consumer); - } - } - } - } - - private static void consumeBehaviour( - int priority, - Activity activity, - BehaviorControl behaviour, - @Nullable BehaviorControl parentBehaviour, - BrainBehaviourConsumer consumer - ) { - consumer.consume(priority, activity, behaviour, parentBehaviour); - - if (behaviour instanceof GateBehavior groupBehaviour) { - groupBehaviour.behaviors.stream() - .forEach( - childBehaviour -> consumeBehaviour( - priority, - activity, - (BehaviorControl) childBehaviour, - groupBehaviour, - consumer - ) - ); - } else if (behaviour instanceof GroupBehaviour groupBehaviour) { - groupBehaviour.getBehaviours() - .forEachRemaining( - childBehaviour -> consumeBehaviour( - priority, - activity, - (BehaviorControl) childBehaviour, - groupBehaviour, - consumer - ) - ); - } - } - - /** - * Removes any behaviours matching the given predicate from the provided brain.
    - * Removed behaviours are stopped prior to removal - * - * @param entity The owner of the brain - * @param predicate The predicate checked for each - */ - public static void removeBehaviour(E entity, BrainBehaviourPredicate predicate) { - if (entity.getBrain() instanceof SmartBrain smartBrain) { - smartBrain.removeBehaviour(entity, predicate); - - return; - } - - Set>>>> behaviours = (Set) entity - .getBrain().availableBehaviorsByPriority.entrySet(); - - for (Map.Entry>>> priorityEntry : behaviours) { - Integer priority = priorityEntry.getKey(); - - for (Map.Entry>> activityEntry : priorityEntry.getValue().entrySet()) { - Activity activity = activityEntry.getKey(); - - for (Iterator> iterator = activityEntry.getValue().iterator(); iterator.hasNext();) { - BehaviorControl behaviour = iterator.next(); - - checkBehaviour(priority, activity, behaviour, null, predicate, () -> { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.doStop((ServerLevel) entity.level(), entity, entity.level().getGameTime()); - - iterator.remove(); - }); - } - } - } - } - - private static void checkBehaviour( - int priority, - Activity activity, - BehaviorControl behaviour, - @Nullable BehaviorControl parentBehaviour, - BrainBehaviourPredicate predicate, - Runnable callback - ) { - if (predicate.isBehaviour(priority, activity, behaviour, parentBehaviour)) { - callback.run(); - } else if (behaviour instanceof GateBehavior groupBehaviour) { - for ( - Iterator> childBehaviourIterator = groupBehaviour.behaviors.iterator(); - childBehaviourIterator.hasNext(); - ) { - checkBehaviour( - priority, - activity, - childBehaviourIterator.next(), - groupBehaviour, - predicate, - childBehaviourIterator::remove - ); - } - - if (!groupBehaviour.behaviors.iterator().hasNext()) - callback.run(); - } else if (behaviour instanceof GroupBehaviour groupBehaviour) { - for ( - Iterator> childBehaviourIterator = groupBehaviour.getBehaviours(); - childBehaviourIterator.hasNext(); - ) { - checkBehaviour( - priority, - activity, - childBehaviourIterator.next(), - groupBehaviour, - predicate, - childBehaviourIterator::remove - ); - } - - if (!groupBehaviour.getBehaviours().hasNext()) - callback.run(); - } - } - - /** - * Safely a new {@link BehaviorControl Behaviour} to the given {@link Brain} - * - * @param brain The brain to add the behaviour to - * @param priority The priority index the behaviour belongs to (lower runs earlier) - * @param activity The activity category the behaviour belongs to - * @param behaviourControl The behaviour to add - */ - public static void addBehaviour(Brain brain, int priority, Activity activity, BehaviorControl behaviourControl) { - if (brain instanceof SmartBrain smartBrain) { - smartBrain.addBehaviour(priority, activity, behaviourControl); - - return; - } - - brain.availableBehaviorsByPriority.computeIfAbsent(priority, priority2 -> Maps.newHashMap()) - .computeIfAbsent(activity, activity2 -> Sets.newLinkedHashSet()) - .add(behaviourControl); - - if (behaviourControl instanceof Behavior behavior) { - for (MemoryModuleType memoryType : behavior.entryCondition.keySet()) { - brain.memories.putIfAbsent(memoryType, Optional.empty()); - } - } - } - - /** - * Adds a full {@link BrainActivityGroup} to the brain, inclusive of activities and conditions - */ - public static void addActivity(Brain brain, BrainActivityGroup behaviourGroup) { - if (brain instanceof SmartBrain smartBrain) { - smartBrain.addActivity(behaviourGroup); - - return; - } - - brain.addActivityAndRemoveMemoriesWhenStopped( - behaviourGroup.getActivity(), - (ImmutableList) behaviourGroup.pairBehaviourPriorities(), - behaviourGroup.getActivityStartMemoryConditions(), - behaviourGroup.getWipedMemoriesOnFinish() - ); - } - - /** - * Adds a sensor to the given brain, additionally allowing for custom instantiation.
    - * Automatically adds detected memories to the brain, but because of the nature of the vanilla brain system, you may - * need to {@link BrainUtils#addMemories add additional memories manually} if Mojang didn't set something up - * properly - */ - public static > void addSensor(Brain brain, SensorType sensorType, S sensor) { - if (brain instanceof SmartBrain smartBrain) { - if (!(sensor instanceof ExtendedSensor extendedSensor)) - throw new IllegalArgumentException( - "Attempted to provide sensor to SmartBrain, only ExtendedSensor subclasses acceptable. Sensor: " - + sensor.getClass() - ); - - smartBrain.addSensor(extendedSensor); - - return; - } - - brain.sensors.put((SensorType) sensorType, (Sensor) sensor); - addMemories(brain, sensor.requires().toArray(new MemoryModuleType[0])); - } - - /** - * Adds the given {@link MemoryModuleType} to the provided brain.
    - * Generally only required if modifying vanilla brains and additional memories are needed. - */ - public static void addMemories(Brain brain, MemoryModuleType... memories) { - if (brain instanceof SmartBrain smartBrain) { - for (MemoryModuleType memoryType : memories) { - smartBrain.getMemory(memoryType); - } - - return; - } - - for (MemoryModuleType memoryType : memories) { - brain.memories.computeIfAbsent(memoryType, key -> Optional.empty()).map(ExpirableValue::getValue); - } - } - - /** - * Adds the given scheduled activity transition to the provided brain's - * {@link net.minecraft.world.entity.schedule.Schedule schedule}, creating a new schedule if required. - * - * @param brain The brain the schedule belongs to - * @param activity The activity to transition to - * @param tickTime The tick-time the activity transition should happen - * @param tickType The type of tick tracking the schedule should use, if a new schedule has to be created. - */ - public static void addScheduledActivityTransition( - Brain brain, - Activity activity, - int tickTime, - SmartBrainSchedule.Type tickType - ) { - if (brain instanceof SmartBrain smartBrain) { - SmartBrainSchedule schedule; - - if ((schedule = smartBrain.getSchedule()) == null) - smartBrain.setSchedule((schedule = new SmartBrainSchedule(tickType))); - - schedule.activityAt(tickTime, activity); - } else { - Schedule schedule; - - if ((schedule = brain.getSchedule()) == Schedule.EMPTY) - brain.setSchedule(new Schedule()); - - Timeline timeline = schedule.timelines.computeIfAbsent(activity, key -> new Timeline()); - - timeline.addKeyframe(tickTime, 1); - - for (Map.Entry entry : schedule.timelines.entrySet()) { - if (entry.getKey() != activity) - entry.getValue().addKeyframe(tickTime, 0); - } - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/EntityRetrievalUtil.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/EntityRetrievalUtil.java deleted file mode 100644 index ed3ebcf5a..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/EntityRetrievalUtil.java +++ /dev/null @@ -1,370 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.util; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.apache.commons.lang3.mutable.MutableDouble; -import org.apache.commons.lang3.mutable.MutableObject; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.Predicate; - -/** - * A helper class for retrieving entities from a given world. This removes a lot of the overhead of vanilla's - * type-checking and redundant stream-collection. Ultimately this leaves casting up to the end-user, and streamlines the - * actual retrieval functions to their most optimised form. - */ -public final class EntityRetrievalUtil { - - /** - * Get the nearest entity from an existing list of entities. - * - * @param origin The center-point of the distance comparison - * @param entities The existing list of entities - * @return The closest entity to the origin point, or null if the input list was empty - * @param The entity type - */ - @Nullable - public static T getNearest(Vec3 origin, List entities) { - if (entities.isEmpty()) - return null; - - double dist = Double.MAX_VALUE; - T closest = null; - - for (T entity : entities) { - double entityDist = entity.distanceToSqr(origin); - - if (entityDist < dist) { - dist = entityDist; - closest = entity; - } - } - - return closest; - } - - /** - * Retrieve the nearest entity with a certain radius of a given origin point that meet a given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check - * {@code instanceof} in your predicate if you intend to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The predicate to filter entities by - * @return The closest entity found that meets the given criteria, or null if none found - * @param The output entity subtype - */ - @Nullable - public static T getNearestEntity( - Entity origin, - double radius, - Predicate predicate - ) { - return getNearestEntity(origin, radius, radius, radius, predicate); - } - - /** - * Retrieve the nearest entity with a certain radius of a given origin point that meet a given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check - * {@code instanceof} in your predicate if you intend to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The predicate to filter entities by - * @return The closest entity found that meets the given criteria, or null if none found - * @param The output entity subtype - */ - @Nullable - public static T getNearestEntity( - Entity origin, - double radiusX, - double radiusY, - double radiusZ, - Predicate predicate - ) { - return getNearestEntity( - origin.level(), - new AABB( - origin.getX() - radiusX, - origin.getY() - radiusY, - origin.getZ() - radiusZ, - origin.getX() + radiusX, - origin.getY() + radiusY, - origin.getZ() + radiusZ - ), - origin.position(), - predicate - ); - } - - /** - * Retrieve the nearest entity with a certain radius of a given origin point that meet a given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check - * {@code instanceof} in your predicate if you intend to use any subclass of Entity - * - * @param level The level to search in - * @param area The region to search for entities in - * @param origin The center-point of the search - * @param predicate The predicate to filter entities by - * @return The closest entity found that meets the given criteria, or null if none found - * @param The output entity subtype - */ - @Nullable - public static T getNearestEntity( - Level level, - AABB area, - Vec3 origin, - Predicate predicate - ) { - final Predicate typeSafePredicate = (Predicate) predicate; - final MutableDouble dist = new MutableDouble(Double.MAX_VALUE); - final MutableObject closest = new MutableObject<>(null); - - level.getEntities().get(area, entity -> { - if (typeSafePredicate.test(entity)) { - double entityDist = entity.distanceToSqr(origin); - - if (entityDist < dist.getValue()) { - dist.setValue(entityDist); - closest.setValue(entity); - } - } - }); - - return (T) closest.getValue(); - } - - /** - * Retrieve the nearest player with a certain radius of a given origin point that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The predicate to filter players by - * @return The closest entity found that meets the given criteria, or null if none found - */ - @Nullable - public static Player getNearestPlayer(Entity origin, double radius, Predicate predicate) { - return getNearestPlayer(origin, radius, radius, radius, predicate); - } - - /** - * Retrieve the nearest player with a certain radius of a given origin point that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The predicate to filter players by - * @return The closest entity found that meets the given criteria, or null if none found - */ - @Nullable - public static Player getNearestPlayer( - Entity origin, - double radiusX, - double radiusY, - double radiusZ, - Predicate predicate - ) { - return getNearestPlayer( - origin.level(), - new AABB( - origin.getX() - radiusX, - origin.getY() - radiusY, - origin.getZ() - radiusZ, - origin.getX() + radiusX, - origin.getY() + radiusY, - origin.getZ() + radiusZ - ), - origin.position(), - predicate - ); - } - - /** - * Retrieve the nearest player with a certain radius of a given origin point that meet a given criteria. - * - * @param level The level to search in - * @param area The region to search for players in - * @param origin The center-point of the search - * @param predicate The predicate to filter players by - * @return The closest entity found that meets the given criteria, or null if none found - */ - @Nullable - public static Player getNearestPlayer(Level level, AABB area, Vec3 origin, Predicate predicate) { - double dist = Double.MAX_VALUE; - Player closest = null; - - for (Player player : level.players()) { - if (area.contains(player.position()) && predicate.test(player)) { - double playerDist = player.distanceToSqr(origin); - - if (playerDist < dist) { - dist = playerDist; - closest = player; - } - } - } - - return closest; - } - - /** - * Get all players within a given region. - * - * @param level The level in which to search - * @param area The region in which to find players - * @return A list of players that are within the given region - */ - public static List getPlayers(Level level, AABB area) { - return getPlayers(level, area, pl -> true); - } - - /** - * Get all players within a given region that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The criteria to meet for a player to be included in the returned list - * @return A list of players that are within the given region that meet the criteria in the predicate - */ - public static List getPlayers(Entity origin, double radius, Predicate predicate) { - return getPlayers(origin, radius, radius, radius, predicate); - } - - /** - * Get all players within a given region that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The criteria to meet for a player to be included in the returned list - * @return A list of players that are within the given region that meet the criteria in the predicate - */ - public static List getPlayers( - Entity origin, - double radiusX, - double radiusY, - double radiusZ, - Predicate predicate - ) { - return getPlayers( - origin.level(), - new AABB( - origin.getX() - radiusX, - origin.getY() - radiusY, - origin.getZ() - radiusZ, - origin.getX() + radiusX, - origin.getY() + radiusY, - origin.getZ() + radiusZ - ), - predicate - ); - } - - /** - * Get all players within a given region that meet a given criteria. - * - * @param level The level in which to search - * @param area The region in which to find players - * @param predicate The criteria to meet for a player to be included in the returned list - * @return A list of players that are within the given region that meet the criteria in the predicate - */ - public static List getPlayers(Level level, AABB area, Predicate predicate) { - List players = new ObjectArrayList<>(); - - for (Player player : level.players()) { - if (area.contains(player.position()) && predicate.test(player)) - players.add(player); - } - - return players; - } - - /** - * Retrieve all nearby entities from the given area that meet the given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check - * {@code instanceof} in your predicate if you intend to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The predicate to filter entities by - * @return A list of entities found in the provided region that meet the criteria of the predicate, or an empty list - * if none match - * @param The output entity subtype - */ - public static List getEntities(Entity origin, double radius, Predicate predicate) { - return getEntities(origin, radius, radius, radius, predicate); - } - - /** - * Retrieve all nearby entities from the given area that meet the given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check - * {@code instanceof} in your predicate if you intend to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The predicate to filter entities by - * @return A list of entities found in the provided region that meet the criteria of the predicate, or an empty list - * if none match - * @param The output entity subtype - */ - public static List getEntities( - Entity origin, - double radiusX, - double radiusY, - double radiusZ, - Predicate predicate - ) { - return getEntities( - origin.level(), - new AABB( - origin.getX() - radiusX, - origin.getY() - radiusY, - origin.getZ() - radiusZ, - origin.getX() + radiusX, - origin.getY() + radiusY, - origin.getZ() + radiusZ - ), - predicate.and(entity -> entity != origin) - ); - } - - /** - * Retrieve all nearby entities from the given area that meet the given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of use. Make sure you check - * {@code instanceof} in your predicate if you intend to use any subclass of Entity - * - * @param level The level to search in - * @param area The region to search for entities in - * @param predicate The predicate to filter entities by - * @return A list of entities found in the provided region that meet the criteria of the predicate, or an empty list - * if none match - * @param The output entity subtype - */ - public static List getEntities(Level level, AABB area, Predicate predicate) { - Predicate typeSafePredicate = (Predicate) predicate; - List entities = new ObjectArrayList<>(); - - level.getEntities().get(area, entity -> { - if (typeSafePredicate.test(entity)) - entities.add((T) entity); - }); - - return entities; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/RandomUtil.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/RandomUtil.java deleted file mode 100644 index 3cc99081d..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/RandomUtil.java +++ /dev/null @@ -1,336 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.util; - -import net.minecraft.core.BlockPos; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.levelgen.PositionalRandomFactory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.BiPredicate; - -/** - * Utility class for easy and legible random functionality. - */ -public final class RandomUtil { - - public static final EasyRandom RANDOM = new EasyRandom(RandomSource.createThreadSafe()); - - public static ThreadLocalRandom getRandomInstance() { - return ThreadLocalRandom.current(); - } - - public static boolean fiftyFifty() { - return RANDOM.fiftyFifty(); - } - - public static boolean oneInNChance(int n) { - return RANDOM.oneInNChance(n); - } - - public static boolean percentChance(double percentChance) { - return RANDOM.percentChance(percentChance); - } - - public static boolean percentChance(float percentChance) { - return RANDOM.percentChance(percentChance); - } - - public static int randomNumberUpTo(int upperBound) { - return RANDOM.randomNumberUpTo(upperBound); - } - - public static float randomValueUpTo(float upperBound) { - return RANDOM.randomValueUpTo(upperBound); - } - - public static double randomValueUpTo(double upperBound) { - return RANDOM.randomValueUpTo(upperBound); - } - - public static double randomGaussianValue() { - return RANDOM.randomGaussianValue(); - } - - public static double randomScaledGaussianValue(double scale) { - return RANDOM.randomScaledGaussianValue(scale); - } - - public static int randomNumberBetween(int min, int max) { - return RANDOM.randomNumberBetween(min, max); - } - - public static double randomValueBetween(double min, double max) { - return RANDOM.randomValueBetween(min, max); - } - - public static T getRandomSelection(@NotNull T... options) { - return RANDOM.getRandomSelection(options); - } - - public static T getRandomSelection(@NotNull List options) { - return RANDOM.getRandomSelection(options); - } - - @NotNull - public static BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius) { - return RANDOM.getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius); - } - - @NotNull - public static BlockPos getRandomPositionWithinRange( - BlockPos centerPos, - int xRadius, - int yRadius, - int zRadius, - boolean safeSurfacePlacement, - Level world - ) { - return RANDOM.getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, safeSurfacePlacement, world); - } - - @NotNull - public static BlockPos getRandomPositionWithinRange( - BlockPos centerPos, - int xRadius, - int yRadius, - int zRadius, - int minSpreadX, - int minSpreadY, - int minSpreadZ, - boolean safeSurfacePlacement, - Level world, - int tries, - @Nullable BiPredicate statePredicate - ) { - return RANDOM.getRandomPositionWithinRange( - centerPos, - xRadius, - yRadius, - zRadius, - minSpreadX, - minSpreadY, - minSpreadZ, - safeSurfacePlacement, - world, - tries, - statePredicate - ); - } - - public static final class EasyRandom implements RandomSource { - - private final RandomSource random; - - public EasyRandom() { - this(RandomSource.create()); - } - - public EasyRandom(@NotNull RandomSource rand) { - this.random = rand; - } - - public RandomSource getSource() { - return RandomSource.create(); - } - - public boolean fiftyFifty() { - return random.nextBoolean(); - } - - public boolean oneInNChance(int n) { - if (n <= 0) - return false; - - return random.nextFloat() < 1 / (float) n; - } - - public boolean percentChance(double percentChance) { - if (percentChance <= 0) - return false; - - if (percentChance >= 1) - return true; - - return random.nextDouble() < percentChance; - } - - public boolean percentChance(float percentChance) { - if (percentChance <= 0) - return false; - - if (percentChance >= 1) - return true; - - return random.nextDouble() < percentChance; - } - - public int randomNumberUpTo(int upperBound) { - return random.nextInt(upperBound); - } - - public float randomValueUpTo(float upperBound) { - return random.nextFloat() * upperBound; - } - - public double randomValueUpTo(double upperBound) { - return random.nextDouble() * upperBound; - } - - public double randomGaussianValue() { - return random.nextGaussian(); - } - - public double randomScaledGaussianValue(double scale) { - return random.nextGaussian() * scale; - } - - public int randomNumberBetween(int min, int max) { - return min + (int) Math.floor(random.nextDouble() * (1 + max - min)); - } - - public double randomValueBetween(double min, double max) { - return min + random.nextDouble() * (max - min); - } - - public T getRandomSelection(@NotNull T... options) { - return options[random.nextInt(options.length)]; - } - - public T getRandomSelection(@NotNull List options) { - return options.get(random.nextInt(options.size())); - } - - @NotNull - public BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius) { - return getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, false, null); - } - - @NotNull - public BlockPos getRandomPositionWithinRange( - BlockPos centerPos, - int xRadius, - int yRadius, - int zRadius, - boolean safeSurfacePlacement, - Level world - ) { - return getRandomPositionWithinRange( - centerPos, - xRadius, - yRadius, - zRadius, - 0, - 0, - 0, - safeSurfacePlacement, - world, - 1, - null - ); - } - - @NotNull - public BlockPos getRandomPositionWithinRange( - BlockPos centerPos, - int xRadius, - int yRadius, - int zRadius, - int minSpreadX, - int minSpreadY, - int minSpreadZ, - boolean safeSurfacePlacement, - Level world, - int tries, - @Nullable BiPredicate statePredicate - ) { - BlockPos.MutableBlockPos mutablePos = centerPos.mutable(); - xRadius = Math.max(xRadius - minSpreadX, 0); - yRadius = Math.max(yRadius - minSpreadY, 0); - zRadius = Math.max(zRadius - minSpreadZ, 0); - - for (int i = 0; i < tries; i++) { - double xAdjust = random.nextFloat() * xRadius * 2 - xRadius; - double yAdjust = random.nextFloat() * yRadius * 2 - yRadius; - double zAdjust = random.nextFloat() * zRadius * 2 - zRadius; - int newX = (int) Math.floor(centerPos.getX() + xAdjust + minSpreadX * Math.signum(xAdjust)); - int newY = (int) Math.floor(centerPos.getY() + yAdjust + minSpreadY * Math.signum(yAdjust)); - int newZ = (int) Math.floor(centerPos.getZ() + zAdjust + minSpreadZ * Math.signum(zAdjust)); - - mutablePos.set(newX, newY, newZ); - - if (safeSurfacePlacement && world != null) - mutablePos.set(world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, mutablePos)); - - if ( - statePredicate == null || statePredicate.test( - world.getBlockState(mutablePos), - mutablePos.immutable() - ) - ) - return mutablePos.immutable(); - } - - return centerPos; - } - - @Override - public EasyRandom fork() { - return new EasyRandom(this.random.fork()); - } - - @Override - public PositionalRandomFactory forkPositional() { - return this.random.forkPositional(); - } - - @Override - public void setSeed(long seed) { - this.random.setSeed(seed); - } - - @Override - public int nextInt() { - return this.random.nextInt(); - } - - @Override - public int nextInt(int upperLimit) { - return this.random.nextInt(upperLimit); - } - - @Override - public long nextLong() { - return this.random.nextLong(); - } - - @Override - public boolean nextBoolean() { - return this.random.nextBoolean(); - } - - @Override - public float nextFloat() { - return this.random.nextFloat(); - } - - @Override - public double nextDouble() { - return this.random.nextDouble(); - } - - @Override - public double nextGaussian() { - return this.random.nextGaussian(); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/SensoryUtils.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/SensoryUtils.java deleted file mode 100644 index 052e2971a..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/SensoryUtils.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.util; - -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; - -import mod.azure.azurelib.sblforked.object.ExtendedTargetingConditions; - -/** - * Helper class for sensory-related utility methods. - *

    - * Mostly this just replaces the poorly implemented methods in {@link net.minecraft.world.entity.ai.sensing.Sensor} - *

    - */ -public class SensoryUtils { - - /** - * Check whether the given target is considered 'targetable' based on sensory and status conditions such as teams - * and line of sight - * - * @return Whether the target is considered targetable - */ - public static boolean isEntityTargetable(LivingEntity attacker, LivingEntity target) { - final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target - ? ExtendedTargetingConditions.forLookTarget().withFollowRange().skipInvisibilityCheck() - : ExtendedTargetingConditions.forLookTarget().withFollowRange(); - - return predicate.test(attacker, target); - } - - /** - * Check whether the given target is considered 'attackable' based on sensory and status conditions such as teams - * and line of sight - * - * @return Whether the target is considered attackable - */ - public static boolean isEntityAttackable(LivingEntity attacker, LivingEntity target) { - final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target - ? ExtendedTargetingConditions.forAttackTarget().withFollowRange().skipInvisibilityCheck() - : ExtendedTargetingConditions.forAttackTarget().withFollowRange(); - - return predicate.test(attacker, target); - } - - /** - * Check whether the given target is considered 'attackable' based on sensory and status conditions such as teams - * and difficulty, but specifically excluding a line of sight check - * - * @return Whether the target is considered attackable - */ - public static boolean isEntityAttackableIgnoringLineOfSight(LivingEntity attacker, LivingEntity target) { - final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target - ? ExtendedTargetingConditions.forAttackTarget() - .ignoreLineOfSight() - .withFollowRange() - .skipInvisibilityCheck() - : ExtendedTargetingConditions.forAttackTarget().ignoreLineOfSight().withFollowRange(); - - return predicate.test(attacker, target); - } - - /** - * Check whether the given target is visible to the entity - * - * @return Whether the entity has line of sight to the target - */ - public static boolean hasLineOfSight(LivingEntity entity, Entity target) { - if (entity instanceof Mob mob) - return mob.getSensing().hasLineOfSight(target); - - return entity.hasLineOfSight(target); - } -} diff --git a/common/src/main/resources/azurelib.accesswidener b/common/src/main/resources/azurelib.accesswidener index 4b9ef39ae..a5e636392 100644 --- a/common/src/main/resources/azurelib.accesswidener +++ b/common/src/main/resources/azurelib.accesswidener @@ -32,42 +32,6 @@ accessible method net/minecraft/client/renderer/RenderType create (Ljava/lang/St accessible field com/mojang/blaze3d/vertex/BufferBuilder building Z accessible class net/minecraft/world/level/block/entity/BlockEntityType$BlockEntitySupplier -# Brain -accessible field net/minecraft/world/entity/ai/Brain sensors Ljava/util/Map; -accessible method net/minecraft/world/entity/ai/Brain memories ()Ljava/util/stream/Stream; -accessible field net/minecraft/world/entity/ai/Brain memories Ljava/util/Map; -accessible field net/minecraft/world/entity/ai/Brain activityRequirements Ljava/util/Map; -accessible field net/minecraft/world/entity/ai/Brain activityMemoriesToEraseWhenStopped Ljava/util/Map; -accessible field net/minecraft/world/entity/ai/Brain availableBehaviorsByPriority Ljava/util/Map; -accessible field net/minecraft/world/entity/ai/behavior/Behavior entryCondition Ljava/util/Map; -accessible class net/minecraft/world/entity/ai/Brain$Provider -extendable class net/minecraft/world/entity/ai/Brain$Provider -accessible method net/minecraft/world/entity/ai/Brain$Provider (Ljava/util/Collection;Ljava/util/Collection;)V -accessible method net/minecraft/world/entity/ai/Brain setMemoryInternal (Lnet/minecraft/world/entity/ai/memory/MemoryModuleType;Ljava/util/Optional;)V -accessible method net/minecraft/world/entity/ai/Brain$MemoryValue setMemoryInternal (Lnet/minecraft/world/entity/ai/Brain;)V -accessible method net/minecraft/world/entity/ai/Brain forgetOutdatedMemories ()V -extendable method net/minecraft/world/entity/ai/Brain forgetOutdatedMemories ()V -accessible field net/minecraft/world/entity/ai/Brain coreActivities Ljava/util/Set; -accessible method net/minecraft/world/entity/ai/Brain setCoreActivities (Ljava/util/Set;)V -extendable method net/minecraft/world/entity/ai/Brain activityRequirementsAreMet (Lnet/minecraft/world/entity/schedule/Activity;)Z -extendable method net/minecraft/world/entity/ai/Brain setActiveActivity (Lnet/minecraft/world/entity/schedule/Activity;)V - -# Behaviour -accessible method net/minecraft/world/entity/ai/behavior/Behavior tryStart (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;J)Z -extendable method net/minecraft/world/entity/ai/behavior/Behavior tryStart (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;J)Z -accessible field net/minecraft/world/entity/ai/behavior/Behavior endTimestamp J -accessible field net/minecraft/world/entity/ai/behavior/Behavior status Lnet/minecraft/world/entity/ai/behavior/Behavior$Status; -accessible method net/minecraft/world/entity/ai/behavior/Behavior getStatus ()Lnet/minecraft/world/entity/ai/behavior/Behavior$Status; -accessible method net/minecraft/world/entity/ai/behavior/Behavior hasRequiredMemories (Lnet/minecraft/world/entity/LivingEntity;)Z -extendable method net/minecraft/world/entity/ai/behavior/Behavior hasRequiredMemories (Lnet/minecraft/world/entity/LivingEntity;)Z -accessible field net/minecraft/world/entity/ai/behavior/GateBehavior behaviors Lnet/minecraft/world/entity/ai/behavior/ShufflingList; - -# Sensor -accessible method net/minecraft/world/entity/ai/sensing/Sensor tick (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;)V -extendable method net/minecraft/world/entity/ai/sensing/Sensor tick (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;)V -accessible field net/minecraft/world/entity/ai/sensing/Sensor scanRate I -accessible field net/minecraft/world/entity/ai/sensing/Sensor RANDOM Lnet/minecraft/util/RandomSource; - # World accessible method net/minecraft/world/level/Level getEntities ()Lnet/minecraft/world/level/entity/LevelEntityGetter; accessible method net/minecraft/client/multiplayer/ClientLevel getEntities ()Lnet/minecraft/world/level/entity/LevelEntityGetter; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 18dee14ff..9f863138d 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -19,13 +19,11 @@ import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; import mod.azure.azurelib.fabric.platform.FabricAzureLibNetwork; -import mod.azure.azurelib.sblforked.SBLConstants; public final class FabricAzureLibMod implements ModInitializer { @Override public void onInitialize() { - SBLConstants.SBL_LOADER.init(null); ConfigIO.FILE_WATCH_MANAGER.startService(); AzureLib.initialize(); AzureLibMod.initRegistry(); diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricSBLForked.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricSBLForked.java deleted file mode 100644 index d52ef4000..000000000 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricSBLForked.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.fabric.platform; - -import com.mojang.serialization.Codec; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; - -import java.util.Optional; -import java.util.function.Supplier; - -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.sblforked.SBLLoader; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; - -public class FabricSBLForked implements SBLLoader { - - public void init(Object eventBus) { - SBLMemoryTypes.init(); - SBLSensors.init(); - } - - @Override - public boolean isDevEnv() { - return FabricLoader.getInstance().isDevelopmentEnvironment(); - } - - @Override - public Supplier> registerMemoryType(String id) { - return registerMemoryType(id, Optional.empty()); - } - - @Override - public Supplier> registerMemoryType(String id, Optional> codec) { - MemoryModuleType memoryType = Registry.register( - BuiltInRegistries.MEMORY_MODULE_TYPE, - ResourceLocation.fromNamespaceAndPath(AzureLib.MOD_ID, id), - new MemoryModuleType<>(codec) - ); - - return () -> memoryType; - } - - @Override - public > Supplier> registerSensorType(String id, Supplier sensor) { - SensorType sensorType = Registry.register( - BuiltInRegistries.SENSOR_TYPE, - ResourceLocation.fromNamespaceAndPath(AzureLib.MOD_ID, id), - new SensorType<>(sensor) - ); - - return () -> sensorType; - } -} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java index b6fd0cb2c..f7568ceb3 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java @@ -14,7 +14,6 @@ import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; import mod.azure.azurelib.common.internal.common.network.packet.*; import mod.azure.azurelib.neoforge.platform.NeoForgeCommonRegistry; -import mod.azure.azurelib.sblforked.SBLConstants; @Mod(AzureLib.MOD_ID) public final class NeoForgeAzureLibMod { @@ -35,7 +34,6 @@ public NeoForgeAzureLibMod(IEventBus modEventBus) { AzureLibMod.config = AzureLibMod.registerConfig(AzureLibConfig.class, ConfigFormats.json()).getConfigInstance(); modEventBus.addListener(this::init); modEventBus.addListener(this::registerMessages); - SBLConstants.SBL_LOADER.init(modEventBus); } private void init(FMLCommonSetupEvent event) { diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidNavigationElement.java b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidNavigationElement.java deleted file mode 100644 index 62905e7a1..000000000 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidNavigationElement.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under the MIT License. - */ -package mod.azure.azurelib.neoforge.api.core.navigation; - -import net.minecraft.world.entity.Mob; -import net.neoforged.neoforge.fluids.FluidType; - -/** - * Extracted interface to act as a helper utility for extensible implementations of (Neo)Forge's fluid API overhaul into - * pathfinding - */ -public interface MultiFluidNavigationElement { - - /** - * Determine whether a given fluidType is one that the given entity can actively navigate through - *

    - * Note that the provided entity may not necessarily be in the given fluid at the time of this call - * - * @param mob The entity to check the pathing capabilities for - * @param fluidType The FluidType to check - */ - default boolean canSwimInFluid(Mob mob, FluidType fluidType) { - return canSwimInFluid(mob, fluidType, 1); - } - - /** - * Determine whether a given fluidType is one that the given entity can actively navigate through - *

    - * Note that the provided entity may not necessarily be in the given fluid at the time of this call - * - * @param mob The entity to check the pathing capabilities for - * @param fluidType The FluidType to check - * @param fluidHeight The depth of the given fluid in the block. I.E. the percentage of the block the fluid is deep - */ - default boolean canSwimInFluid(Mob mob, FluidType fluidType, double fluidHeight) { - return fluidType.canSwim(mob); - } -} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidSmoothGroundNavigation.java b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidSmoothGroundNavigation.java deleted file mode 100644 index 76a66204c..000000000 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidSmoothGroundNavigation.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under the MIT License. - */ -package mod.azure.azurelib.neoforge.api.core.navigation; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; - -import mod.azure.azurelib.neoforge.api.core.navigation.nodeevaluator.MultiFluidWalkNodeEvaluator; -import mod.azure.azurelib.sblforked.api.core.navigation.SmoothGroundNavigation; - -/** - * An extension of {@link SmoothGroundNavigation} to allow for fluid-agnostic pathfinding based on (Neo)Forge's fluid - * API overhaul - *

    - * This allows for entities to pathfind in fluids other than water as necessary - * - * @see MultiFluidNavigationElement - */ -public class MultiFluidSmoothGroundNavigation extends SmoothGroundNavigation implements MultiFluidNavigationElement { - - public MultiFluidSmoothGroundNavigation(Mob mob, Level level) { - super(mob, level); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new MultiFluidWalkNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } - - /** - * Whether the navigator should consider the entity's current state valid for navigating through a path - *

    - * Note that this does not specifically apply to any given path (and the entity's path may even be null at times - * when this is called) - */ - @Override - protected boolean canUpdatePath() { - return this.mob.onGround() || this.mob.isInFluidType( - (fluidType, height) -> canSwimInFluid(this.mob, fluidType, height), - true - ) || this.mob.isPassenger(); - } - - /** - * Helper override to allow end-users to modify the fluids an entity can swim in, extensibly patching in - * (Neo)Forge's fluid API - *

    - * Don't use this method to adjust which fluids are 'swimmable', use - * {@link MultiFluidNavigationElement#canSwimInFluid} - * - * @return The nearest safe surface height for the entity - */ - @Override - public int getSurfaceY() { - if ( - this.mob.isInFluidType((fluidType, height) -> canSwimInFluid(this.mob, fluidType, height), true) - && canFloat() - ) { - final int basePos = this.mob.getBlockY(); - BlockPos.MutableBlockPos pos = BlockPos.containing(this.mob.getX(), basePos, this.mob.getZ()).mutable(); - BlockState state = this.level.getBlockState(pos); - FluidState fluidState = state.getFluidState(); - - while (canSwimInFluid(this.mob, fluidState.getFluidType(), fluidState.getHeight(this.level, pos))) { - state = this.level.getBlockState(pos.move(Direction.UP)); - fluidState = state.getFluidState(); - - if (pos.getY() - basePos > 16) - return basePos; - } - - return pos.getY(); - } - - return Mth.floor(this.mob.getY() + 0.5); - } -} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/nodeevaluator/MultiFluidWalkNodeEvaluator.java b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/nodeevaluator/MultiFluidWalkNodeEvaluator.java deleted file mode 100644 index 94064231a..000000000 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/nodeevaluator/MultiFluidWalkNodeEvaluator.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under the MIT License. - */ -package mod.azure.azurelib.neoforge.api.core.navigation.nodeevaluator; - -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.pathfinder.Node; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; -import net.minecraft.world.phys.AABB; -import org.jetbrains.annotations.NotNull; - -import mod.azure.azurelib.neoforge.api.core.navigation.MultiFluidNavigationElement; - -/** - * An extension of {@link WalkNodeEvaluator} to allow for fluid-agnostic pathfinding based on (Neo)Forge's fluid API - * overhaul - *

    - * This allows for entities to pathfind in fluids other than water as necessary - * - * @see MultiFluidNavigationElement - */ -public class MultiFluidWalkNodeEvaluator extends WalkNodeEvaluator implements MultiFluidNavigationElement { - - /** - * Determine and create a path node for the current starting position based on the surrounding environment - */ - @Override - public @NotNull Node getStart() { - int groundY = this.mob.getBlockY(); - final BlockPos.MutableBlockPos testPos = new BlockPos.MutableBlockPos( - this.mob.getX(), - groundY, - this.mob.getZ() - ); - BlockState groundState = this.currentContext.getBlockState(testPos); - - if (!this.mob.canStandOnFluid(groundState.getFluidState())) { - if ( - canFloat() && this.mob.isInFluidType((fluidType, height) -> canSwimInFluid(this.mob, fluidType, height)) - ) { - while (true) { - if ( - groundState.getFluidState().isEmpty() || !canSwimInFluid( - this.mob, - groundState.getFluidState().getFluidType() - ) - ) { - groundY--; - - break; - } - - groundState = this.currentContext.getBlockState(testPos.setY(++groundY)); - } - } else if (this.mob.onGround()) { - groundY = Mth.floor(this.mob.getY() + 0.5d); - } else { - testPos.setY(Mth.floor(this.mob.getY() + 1)); - - while (testPos.getY() > this.currentContext.level().getMinBuildHeight()) { - groundY = testPos.getY(); - testPos.setY(testPos.getY() - 1); - groundState = this.currentContext.getBlockState(testPos); - - if (!groundState.isAir() && !groundState.isPathfindable(PathComputationType.LAND)) - break; - } - } - } else { - while (this.mob.canStandOnFluid(groundState.getFluidState())) { - groundState = this.currentContext.getBlockState(testPos.setY(++groundY)); - } - - groundY--; - } - - if (!canStartAt(testPos.setY(groundY))) { - AABB entityBounds = this.mob.getBoundingBox(); - - if ( - canStartAt(testPos.set(entityBounds.minX, groundY, entityBounds.minZ)) - || canStartAt(testPos.set(entityBounds.minX, groundY, entityBounds.maxZ)) - || canStartAt(testPos.set(entityBounds.maxX, groundY, entityBounds.minZ)) - || canStartAt(testPos.set(entityBounds.maxX, groundY, entityBounds.maxZ)) - ) { - return getStartNode(testPos); - } - } - - return getStartNode(testPos.set(this.mob.getX(), groundY, this.mob.getZ())); - } - - /** - * Get the position the mob would stand on if it were standing at the given position - */ - @Override - protected double getFloorLevel(@NotNull BlockPos pos) { - final BlockGetter blockGetter = this.currentContext.level(); - FluidState fluidState = blockGetter.getFluidState(pos); - - return (canFloat() || isAmphibious()) && canSwimInFluid( - this.mob, - fluidState.getFluidType(), - fluidState.getHeight(blockGetter, pos) - ) - ? pos.getY() + 0.5d - : getFloorLevel(blockGetter, pos); - } -} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeSBLForked.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeSBLForked.java deleted file mode 100644 index 43ab23265..000000000 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeSBLForked.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. Original source: - * https://github.com/Tslat/SmartBrainLib Copyright © 2024 Tslat. Licensed under Mozilla Public License 2.0: - * https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.neoforge.platform; - -import com.mojang.serialization.Codec; -import net.minecraft.core.registries.Registries; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.neoforged.bus.api.IEventBus; -import net.neoforged.fml.loading.FMLLoader; -import net.neoforged.neoforge.registries.DeferredRegister; - -import java.util.Optional; -import java.util.function.Supplier; - -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.sblforked.SBLLoader; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; - -public class NeoForgeSBLForked implements SBLLoader { - - public static final DeferredRegister> MEMORY_TYPES = DeferredRegister.create( - Registries.MEMORY_MODULE_TYPE, - AzureLib.MOD_ID - ); - - public static final DeferredRegister> SENSORS = DeferredRegister.create( - Registries.SENSOR_TYPE, - AzureLib.MOD_ID - ); - - public static final DeferredRegister> ENTITY_TYPES = DeferredRegister.create( - Registries.ENTITY_TYPE, - AzureLib.MOD_ID - ); - - public void init(Object eventBus) { - final IEventBus modEventBus = (IEventBus) eventBus; - - MEMORY_TYPES.register(modEventBus); - SENSORS.register(modEventBus); - - SBLMemoryTypes.init(); - SBLSensors.init(); - } - - @Override - public boolean isDevEnv() { - return !FMLLoader.isProduction(); - } - - @Override - public Supplier> registerMemoryType(String id) { - return registerMemoryType(id, Optional.empty()); - } - - @Override - public Supplier> registerMemoryType(String id, Optional> codec) { - return MEMORY_TYPES.register(id, () -> new MemoryModuleType<>(codec)); - } - - @Override - public > Supplier> registerSensorType(String id, Supplier sensor) { - return SENSORS.register(id, () -> new SensorType<>(sensor)); - } -} diff --git a/neo/src/main/resources/META-INF/accesstransformer.cfg b/neo/src/main/resources/META-INF/accesstransformer.cfg index c53fb8529..1a8bff0c4 100644 --- a/neo/src/main/resources/META-INF/accesstransformer.cfg +++ b/neo/src/main/resources/META-INF/accesstransformer.cfg @@ -31,35 +31,6 @@ public com.mojang.blaze3d.vertex.BufferBuilder building # building public net.minecraft.world.level.block.entity.BlockEntityType$BlockEntitySupplier public net.minecraft.client.renderer.RenderStateShard$OverlayStateShard -# Brain -public net.minecraft.world.entity.ai.Brain sensors -public net.minecraft.world.entity.ai.Brain memories -public net.minecraft.world.entity.ai.Brain activityRequirements -public net.minecraft.world.entity.ai.Brain activityMemoriesToEraseWhenStopped -public net.minecraft.world.entity.ai.behavior.Behavior entryCondition -public-f net.minecraft.world.entity.ai.Brain$Provider -public net.minecraft.world.entity.ai.Brain$Provider (Ljava/util/Collection;Ljava/util/Collection;)V -public net.minecraft.world.entity.ai.Brain setMemoryInternal(Lnet/minecraft/world/entity/ai/memory/MemoryModuleType;Ljava/util/Optional;)V -public net.minecraft.world.entity.ai.Brain$MemoryValue setMemoryInternal(Lnet/minecraft/world/entity/ai/Brain;)V -public net.minecraft.world.entity.ai.Brain forgetOutdatedMemories()V -public net.minecraft.world.entity.ai.Brain coreActivities -public net.minecraft.world.entity.ai.Brain activeActivities -public net.minecraft.world.entity.ai.Brain availableBehaviorsByPriority -public net.minecraft.world.entity.ai.Brain activityRequirementsAreMet(Lnet/minecraft/world/entity/schedule/Activity;)Z -public net.minecraft.world.entity.ai.Brain setActiveActivity(Lnet/minecraft/world/entity/schedule/Activity;)V - -# Behaviour -public-f net.minecraft.world.entity.ai.behavior.Behavior tryStart(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;J)Z -public net.minecraft.world.entity.ai.behavior.Behavior endTimestamp -public net.minecraft.world.entity.ai.behavior.Behavior status -public net.minecraft.world.entity.ai.behavior.Behavior hasRequiredMemories(Lnet/minecraft/world/entity/LivingEntity;)Z -public net.minecraft.world.entity.ai.behavior.GateBehavior behaviors - -# Sensor -public-f net.minecraft.world.entity.ai.sensing.Sensor tick(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;)V -public net.minecraft.world.entity.ai.sensing.Sensor scanRate -public net.minecraft.world.entity.ai.sensing.Sensor RANDOM - # World public net.minecraft.world.level.Level getEntities()Lnet/minecraft/world/level/entity/LevelEntityGetter; public net.minecraft.client.multiplayer.ClientLevel getEntities()Lnet/minecraft/world/level/entity/LevelEntityGetter; From 579eadc72f8792e66367d276ae70a705b626e54c Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 15:03:33 -0500 Subject: [PATCH 037/224] Implemented AzBoneSnapshotCache.java, made AzAnimationController#keyFrameCallbacks not nullable. Signed-off-by: = --- .../controller/AzAnimationController.java | 44 +++++------------- .../controller/AzBoneSnapshotCache.java | 45 ++++++++++++++++++ .../keyframe/AzKeyFrameCallbackManager.java | 2 +- .../keyframe/AzKeyFrameCallbacks.java | 46 +++++++++---------- 4 files changed, 81 insertions(+), 56 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneSnapshotCache.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 8da099d5b..b3239ae89 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -1,8 +1,7 @@ package mod.azure.azurelib.core2.animation.controller; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; -import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,6 +10,7 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Queue; import java.util.function.Function; import java.util.function.ToDoubleFunction; @@ -31,6 +31,8 @@ import mod.azure.azurelib.core2.animation.AzAnimationProcessor; import mod.azure.azurelib.core2.animation.AzAnimationState; import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; @@ -48,12 +50,12 @@ public class AzAnimationController { protected final Map boneAnimationQueues = new Object2ObjectOpenHashMap<>(); - protected final Map boneSnapshots = new Object2ObjectOpenHashMap<>(); - protected final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); private final AzAnimator animator; + private final AzBoneSnapshotCache boneSnapshotCache; + private final AzKeyFrameCallbackManager keyFrameCallbackManager; protected Queue animationQueue = new LinkedList<>(); @@ -99,10 +101,13 @@ public AzAnimationController(AzAnimator animator, String name, int transition this.animator = animator; this.name = name; this.transitionLength = transitionTickTime; + this.boneSnapshotCache = new AzBoneSnapshotCache(); + this.keyFrameCallbacks = AzKeyFrameCallbacks.noop(); this.keyFrameCallbackManager = new AzKeyFrameCallbackManager<>(this); } - public AzAnimationController setKeyFrameCallbacks(AzKeyFrameCallbacks keyFrameCallbacks) { + public AzAnimationController setKeyFrameCallbacks(@NotNull AzKeyFrameCallbacks keyFrameCallbacks) { + Objects.requireNonNull(keyFrameCallbacks); this.keyFrameCallbacks = keyFrameCallbacks; return this; } @@ -422,7 +427,7 @@ public void process( return; } - saveSnapshotsForAnimation(currentAnimation, snapshots); + boneSnapshotCache.put(currentAnimation, snapshots.values()); } if (currentAnimation != null) { @@ -430,7 +435,7 @@ public void process( for (var boneAnimation : currentAnimation.animation().boneAnimations()) { var boneAnimationQueue = boneAnimationQueues.get(boneAnimation.boneName()); - var boneSnapshot = boneSnapshots.get(boneAnimation.boneName()); + var boneSnapshot = boneSnapshotCache.getOrNull(boneAnimation.boneName()); var bone = bones.get(boneAnimation.boneName()); if (bone == null) { @@ -594,31 +599,6 @@ protected void createInitialQueues(Collection modelRendererList) { } } - /** - * Cache the relevant {@link BoneSnapshot BoneSnapshots} for the current {@link AzQueuedAnimation} for animation - * lerping - * - * @param animation The {@code QueuedAnimation} to filter {@code BoneSnapshots} for - * @param snapshots The master snapshot collection to pull filter from - */ - protected void saveSnapshotsForAnimation( - AzQueuedAnimation animation, - Map snapshots - ) { - if (animation.animation().boneAnimations() == null) { - return; - } - - for (var snapshot : snapshots.values()) { - for (var boneAnimation : animation.animation().boneAnimations()) { - if (boneAnimation.boneName().equals(snapshot.getBone().getName())) { - boneSnapshots.put(boneAnimation.boneName(), BoneSnapshot.copy(snapshot)); - break; - } - } - } - } - /** * Adjust a tick value depending on the controller's current state and speed modifier.
    * Is used when starting a new animation, transitioning, and a few other key areas diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneSnapshotCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneSnapshotCache.java new file mode 100644 index 000000000..ade445ab5 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneSnapshotCache.java @@ -0,0 +1,45 @@ +package mod.azure.azurelib.core2.animation.controller; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Map; + +import mod.azure.azurelib.core.state.BoneSnapshot; +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; + +public class AzBoneSnapshotCache { + + private final Map boneSnapshots; + + public AzBoneSnapshotCache() { + this.boneSnapshots = new Object2ObjectOpenHashMap<>(); + } + + /** + * Cache the relevant {@link BoneSnapshot BoneSnapshots} for the current {@link AzQueuedAnimation} for animation + * lerping + * + * @param animation The {@code QueuedAnimation} to filter {@code BoneSnapshots} for + * @param snapshots The master snapshot collection to pull filter from + */ + public void put(AzQueuedAnimation animation, Collection snapshots) { + if (animation.animation().boneAnimations() == null) { + return; + } + + for (var snapshot : snapshots) { + for (var boneAnimation : animation.animation().boneAnimations()) { + if (boneAnimation.boneName().equals(snapshot.getBone().getName())) { + boneSnapshots.put(boneAnimation.boneName(), BoneSnapshot.copy(snapshot)); + break; + } + } + } + } + + public @Nullable BoneSnapshot getOrNull(String name) { + return boneSnapshots.get(name); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java index da8848b09..8419415b5 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java @@ -1,13 +1,13 @@ package mod.azure.azurelib.core2.animation.controller.keyframe; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Set; import mod.azure.azurelib.core.keyframe.event.data.KeyFrameData; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbacks.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbacks.java index f0246590d..ff2aa20b4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbacks.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbacks.java @@ -1,5 +1,7 @@ package mod.azure.azurelib.core2.animation.controller.keyframe; +import org.jetbrains.annotations.Nullable; + import mod.azure.azurelib.core2.animation.controller.keyframe.handler.AzCustomKeyframeHandler; import mod.azure.azurelib.core2.animation.controller.keyframe.handler.AzParticleKeyframeHandler; import mod.azure.azurelib.core2.animation.controller.keyframe.handler.AzSoundKeyframeHandler; @@ -9,31 +11,38 @@ public class AzKeyFrameCallbacks { - private final AzCustomKeyframeHandler customKeyframeHandler; + private static final AzKeyFrameCallbacks NO_OP = new AzKeyFrameCallbacks<>(null, null, null); + + @SuppressWarnings("unchecked") + public static AzKeyFrameCallbacks noop() { + return (AzKeyFrameCallbacks) NO_OP; + } + + private final @Nullable AzCustomKeyframeHandler customKeyframeHandler; - private final AzParticleKeyframeHandler particleKeyframeHandler; + private final @Nullable AzParticleKeyframeHandler particleKeyframeHandler; - private final AzSoundKeyframeHandler soundKeyframeHandler; + private final @Nullable AzSoundKeyframeHandler soundKeyframeHandler; private AzKeyFrameCallbacks( - AzCustomKeyframeHandler customKeyframeHandler, - AzParticleKeyframeHandler particleKeyframeHandler, - AzSoundKeyframeHandler soundKeyframeHandler + @Nullable AzCustomKeyframeHandler customKeyframeHandler, + @Nullable AzParticleKeyframeHandler particleKeyframeHandler, + @Nullable AzSoundKeyframeHandler soundKeyframeHandler ) { this.customKeyframeHandler = customKeyframeHandler; this.particleKeyframeHandler = particleKeyframeHandler; this.soundKeyframeHandler = soundKeyframeHandler; } - public AzCustomKeyframeHandler getCustomKeyframeHandler() { + public @Nullable AzCustomKeyframeHandler getCustomKeyframeHandler() { return customKeyframeHandler; } - public AzParticleKeyframeHandler getParticleKeyframeHandler() { + public @Nullable AzParticleKeyframeHandler getParticleKeyframeHandler() { return particleKeyframeHandler; } - public AzSoundKeyframeHandler getSoundKeyframeHandler() { + public @Nullable AzSoundKeyframeHandler getSoundKeyframeHandler() { return soundKeyframeHandler; } @@ -43,11 +52,11 @@ public static Builder builder() { public static class Builder { - private AzCustomKeyframeHandler customKeyframeHandler; + private @Nullable AzCustomKeyframeHandler customKeyframeHandler; - private AzParticleKeyframeHandler particleKeyframeHandler; + private @Nullable AzParticleKeyframeHandler particleKeyframeHandler; - private AzSoundKeyframeHandler soundKeyframeHandler; + private @Nullable AzSoundKeyframeHandler soundKeyframeHandler; private Builder() {} @@ -59,7 +68,6 @@ private Builder() {} */ public Builder setSoundKeyframeHandler(AzSoundKeyframeHandler soundHandler) { this.soundKeyframeHandler = soundHandler; - return this; } @@ -71,7 +79,6 @@ public Builder setSoundKeyframeHandler(AzSoundKeyframeHandler soundHandler */ public Builder setParticleKeyframeHandler(AzParticleKeyframeHandler particleHandler) { this.particleKeyframeHandler = particleHandler; - return this; } @@ -81,20 +88,13 @@ public Builder setParticleKeyframeHandler(AzParticleKeyframeHandler partic * * @return this */ - public Builder setCustomInstructionKeyframeHandler( - AzCustomKeyframeHandler customInstructionHandler - ) { + public Builder setCustomInstructionKeyframeHandler(AzCustomKeyframeHandler customInstructionHandler) { this.customKeyframeHandler = customInstructionHandler; - return this; } public AzKeyFrameCallbacks build() { - return new AzKeyFrameCallbacks<>( - customKeyframeHandler, - particleKeyframeHandler, - soundKeyframeHandler - ); + return new AzKeyFrameCallbacks<>(customKeyframeHandler, particleKeyframeHandler, soundKeyframeHandler); } } } From c663fce977ddf56d22cc203eb1f0721912fb3973 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:34:13 -0500 Subject: [PATCH 038/224] WIP support to come with rewrite --- .../mod/azure/azurelib/core/utils/Interpolation.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java b/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java index 0308a9032..4524f3dcc 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java @@ -85,6 +85,16 @@ public float interpolate(float a, float b, float x) { return a + (b - a) * (float) (-Math.pow(2, -10 * x) + 1); } }, + CATMULLROM("catmullrom") { + + @Override + public float interpolate(float a, float b, float x) { + return 0.5f * ((2 * a) + + (-(a - (b - a)) + b) * x + + (2 * (a - (b - a)) - 5 * a + 4 * b - (b + (b - a))) * (x * x) + + (-(a - (b - a)) + 3 * a - 3 * b + (b + (b - a))) * (x * x * x)); + } + }, EXP_INOUT("exp_inout") { @Override From 03927e2fb94c174cf3e80d63d4dbcb60173c5b5f Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 15:55:38 -0500 Subject: [PATCH 039/224] Implemented AzAnimationQueue.java, AzKeyFrameProcessor.java. Signed-off-by: = --- .../controller/AzAnimationController.java | 277 ++++-------------- .../controller/AzAnimationQueue.java | 43 +++ .../keyframe/AzKeyFrameProcessor.java | 251 ++++++++++++++++ 3 files changed, 347 insertions(+), 224 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index b3239ae89..fcd303a55 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -6,26 +6,14 @@ import org.slf4j.LoggerFactory; import java.util.Collection; -import java.util.LinkedList; -import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Objects; -import java.util.Queue; import java.util.function.Function; import java.util.function.ToDoubleFunction; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animation.EasingType; -import mod.azure.azurelib.core.keyframe.AnimationPoint; import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; -import mod.azure.azurelib.core.keyframe.Keyframe; -import mod.azure.azurelib.core.keyframe.KeyframeLocation; -import mod.azure.azurelib.core.math.Constant; -import mod.azure.azurelib.core.math.IValue; -import mod.azure.azurelib.core.molang.MolangParser; -import mod.azure.azurelib.core.molang.MolangQueries; -import mod.azure.azurelib.core.object.Axis; import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core2.animation.AzAnimationProcessor; @@ -33,6 +21,7 @@ import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameProcessor; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; @@ -52,13 +41,15 @@ public class AzAnimationController { protected final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); + private final AzAnimationQueue animationQueue; + private final AzAnimator animator; private final AzBoneSnapshotCache boneSnapshotCache; private final AzKeyFrameCallbackManager keyFrameCallbackManager; - protected Queue animationQueue = new LinkedList<>(); + private final AzKeyFrameProcessor keyFrameProcessor; protected boolean isJustStarting = false; @@ -101,9 +92,11 @@ public AzAnimationController(AzAnimator animator, String name, int transition this.animator = animator; this.name = name; this.transitionLength = transitionTickTime; + this.animationQueue = new AzAnimationQueue(); this.boneSnapshotCache = new AzBoneSnapshotCache(); this.keyFrameCallbacks = AzKeyFrameCallbacks.noop(); this.keyFrameCallbackManager = new AzKeyFrameCallbackManager<>(this); + this.keyFrameProcessor = new AzKeyFrameProcessor<>(this); } public AzAnimationController setKeyFrameCallbacks(@NotNull AzKeyFrameCallbacks keyFrameCallbacks) { @@ -297,7 +290,8 @@ public void setAnimation(T animatable, AzRawAnimation rawAnimation) { var animations = animator.getAnimationProcessor().buildAnimationQueue(animatable, rawAnimation); if (animations != null) { - this.animationQueue = animations; + animationQueue.clear(); + animationQueue.addAll(animations); this.currentRawAnimation = rawAnimation; this.shouldResetTick = true; this.animationState = AzAnimationControllerState.TRANSITIONING; @@ -415,11 +409,22 @@ public void process( } if (getAnimationState() == AzAnimationControllerState.RUNNING) { - processCurrentAnimation(animatable, adjustedTick, seekTime, crashWhenCantFindBone); + keyFrameProcessor.runCurrentAnimation( + boneAnimationQueues, + animatable, + adjustedTick, + seekTime, + crashWhenCantFindBone + ); + var canTransition = transitionLength == 0 && shouldResetTick; + + if (canTransition && animationState == AzAnimationControllerState.TRANSITIONING) { + this.currentAnimation = this.animationQueue.next(); + } } else if (animationState == AzAnimationControllerState.TRANSITIONING) { if (adjustedTick == 0 || isJustStarting) { this.justStartedTransition = false; - this.currentAnimation = animationQueue.poll(); + this.currentAnimation = animationQueue.next(); keyFrameCallbackManager.reset(); @@ -431,159 +436,14 @@ public void process( } if (currentAnimation != null) { - MolangParser.INSTANCE.setValue(MolangQueries.ANIM_TIME, () -> 0); - - for (var boneAnimation : currentAnimation.animation().boneAnimations()) { - var boneAnimationQueue = boneAnimationQueues.get(boneAnimation.boneName()); - var boneSnapshot = boneSnapshotCache.getOrNull(boneAnimation.boneName()); - var bone = bones.get(boneAnimation.boneName()); - - if (bone == null) { - if (crashWhenCantFindBone) - throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); - - continue; - } - - var rotationKeyFrames = boneAnimation.rotationKeyFrames(); - var positionKeyFrames = boneAnimation.positionKeyFrames(); - var scaleKeyFrames = boneAnimation.scaleKeyFrames(); - - if (!rotationKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addNextRotation( - null, - adjustedTick, - transitionLength, - boneSnapshot, - bone.getInitialSnapshot(), - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) - ); - } - - if (!positionKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addNextPosition( - null, - adjustedTick, - transitionLength, - boneSnapshot, - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) - ); - } - - if (!scaleKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addNextScale( - null, - adjustedTick, - transitionLength, - boneSnapshot, - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) - ); - } - } - } - } - } - - /** - * Handle the current animation's state modifications and translations - * - * @param adjustedTick The controller-adjusted tick for animation purposes - * @param seekTime The lerped tick (current tick + partial tick) - * @param crashWhenCantFindBone Whether the controller should throw an exception when unable to find the required - * bone, or continue with the remaining bones - */ - protected void processCurrentAnimation( - T animatable, - double adjustedTick, - double seekTime, - boolean crashWhenCantFindBone - ) { - if (adjustedTick >= currentAnimation.animation().length()) { - if ( - currentAnimation.loopType().shouldPlayAgain(animatable, this, this.currentAnimation.animation()) - ) { - if (animationState != AzAnimationControllerState.PAUSED) { - this.shouldResetTick = true; - - adjustedTick = adjustTick(animatable, seekTime); - keyFrameCallbackManager.reset(); - } - } else { - var nextAnimation = animationQueue.peek(); - - keyFrameCallbackManager.reset(); - - if (nextAnimation == null) { - this.animationState = AzAnimationControllerState.STOPPED; - - return; - } else { - this.animationState = AzAnimationControllerState.TRANSITIONING; - this.shouldResetTick = true; - this.currentAnimation = nextAnimation; - } - } - } - - final double finalAdjustedTick = adjustedTick; - - MolangParser.INSTANCE.setMemoizedValue(MolangQueries.ANIM_TIME, () -> finalAdjustedTick / 20d); - - for (var boneAnimation : currentAnimation.animation().boneAnimations()) { - var boneAnimationQueue = boneAnimationQueues.get(boneAnimation.boneName()); - - if (boneAnimationQueue == null) { - if (crashWhenCantFindBone) - throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); - - continue; - } - - var rotationKeyFrames = boneAnimation.rotationKeyFrames(); - var positionKeyFrames = boneAnimation.positionKeyFrames(); - var scaleKeyFrames = boneAnimation.scaleKeyFrames(); - - if (!rotationKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addRotations( - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) - ); - } - - if (!positionKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addPositions( - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) - ); - } - - if (!scaleKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addScales( - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + keyFrameProcessor.transitionFromCurrentAnimation( + boneAnimationQueues, + bones, + crashWhenCantFindBone, + adjustedTick ); } } - - adjustedTick += this.transitionLength; - - keyFrameCallbackManager.handle(animatable, adjustedTick); - - if ( - this.transitionLength == 0 && this.shouldResetTick - && this.animationState == AzAnimationControllerState.TRANSITIONING - ) { - this.currentAnimation = this.animationQueue.poll(); - } } /** @@ -607,7 +467,7 @@ protected void createInitialQueues(Collection modelRendererList) { * @return 0 if {@link AzAnimationController#shouldResetTick} is set to false, or a * {@link AzAnimationController#animationSpeedModifier} modified value otherwise */ - protected double adjustTick(T animatable, double tick) { + public double adjustTick(T animatable, double tick) { if (!shouldResetTick) { return animationSpeedModifier.applyAsDouble(animatable) * Math.max(tick - tickOffset, 0); } @@ -622,76 +482,45 @@ protected double adjustTick(T animatable, double tick) { } /** - * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} + * Returns the current state of this controller. */ - protected AnimationPoint getAnimationPointAtTick( - List> frames, - double tick, - boolean isRotation, - Axis axis - ) { - var location = getCurrentKeyFrameLocation(frames, tick); - var currentFrame = location.keyframe(); - var startValue = currentFrame.startValue().get(); - var endValue = currentFrame.endValue().get(); - - if (isRotation) { - if (!(currentFrame.startValue() instanceof Constant)) { - startValue = Math.toRadians(startValue); - - if (axis == Axis.X || axis == Axis.Y) { - startValue *= -1; - } - } - - if (!(currentFrame.endValue() instanceof Constant)) { - endValue = Math.toRadians(endValue); + public AzAnimationControllerState getAnimationState() { + return animationState; + } - if (axis == Axis.X || axis == Axis.Y) { - endValue *= -1; - } - } - } + public void setAnimationState(AzAnimationControllerState animationState) { + this.animationState = animationState; + } - return new AnimationPoint(currentFrame, location.startTick(), currentFrame.length(), startValue, endValue); + public AzAnimationQueue getAnimationQueue() { + return animationQueue; } - /** - * Returns the {@link Keyframe} relevant to the current tick time - * - * @param frames The list of {@code KeyFrames} to filter through - * @param ageInTicks The current tick time - * @return A new {@code KeyFrameLocation} containing the current {@code KeyFrame} and the tick time used to find it - */ - protected KeyframeLocation> getCurrentKeyFrameLocation( - List> frames, - double ageInTicks - ) { - var totalFrameTime = 0; + public AzBoneSnapshotCache getBoneSnapshotCache() { + return boneSnapshotCache; + } - for (var frame : frames) { - totalFrameTime += frame.length(); + public AzKeyFrameCallbacks getKeyFrameCallbacks() { + return keyFrameCallbacks; + } - if (totalFrameTime > ageInTicks) { - return new KeyframeLocation<>(frame, (ageInTicks - (totalFrameTime - frame.length()))); - } - } + public AzKeyFrameCallbackManager getKeyFrameCallbackManager() { + return keyFrameCallbackManager; + } - return new KeyframeLocation<>(frames.get(frames.size() - 1), ageInTicks); + public double getTransitionLength() { + return transitionLength; } - /** - * Returns the current state of this controller. - */ - public AzAnimationControllerState getAnimationState() { - return animationState; + public boolean shouldResetTick() { + return shouldResetTick; } - public void setAnimationState(AzAnimationControllerState animationState) { - this.animationState = animationState; + public void setShouldResetTick(boolean shouldResetTick) { + this.shouldResetTick = shouldResetTick; } - public AzKeyFrameCallbacks getKeyFrameCallbacks() { - return keyFrameCallbacks; + public void setCurrentAnimation(AzQueuedAnimation currentAnimation) { + this.currentAnimation = currentAnimation; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java new file mode 100644 index 000000000..24b8af924 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java @@ -0,0 +1,43 @@ +package mod.azure.azurelib.core2.animation.controller; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.Queue; + +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; + +public class AzAnimationQueue { + + private final Queue animationQueue; + + public AzAnimationQueue() { + this.animationQueue = new LinkedList<>(); + } + + public void add(@NotNull AzQueuedAnimation queuedAnimation) { + animationQueue.add(queuedAnimation); + } + + public void addAll(@NotNull Collection queuedAnimations) { + animationQueue.addAll(queuedAnimations); + } + + public @Nullable AzQueuedAnimation peek() { + return animationQueue.peek(); + } + + public @Nullable AzQueuedAnimation next() { + return animationQueue.poll(); + } + + public void clear() { + animationQueue.clear(); + } + + public boolean isEmpty() { + return animationQueue.isEmpty(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java new file mode 100644 index 000000000..df1330f16 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java @@ -0,0 +1,251 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; + +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.keyframe.AnimationPoint; +import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.keyframe.KeyframeLocation; +import mod.azure.azurelib.core.math.Constant; +import mod.azure.azurelib.core.math.IValue; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.MolangQueries; +import mod.azure.azurelib.core.object.Axis; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerState; + +public class AzKeyFrameProcessor { + + private final AzAnimationController animationController; + + public AzKeyFrameProcessor(AzAnimationController animationController) { + this.animationController = animationController; + } + + /** + * Handle the current animation's state modifications and translations + * + * @param boneAnimationQueues + * @param adjustedTick The controller-adjusted tick for animation purposes + * @param seekTime The lerped tick (current tick + partial tick) + * @param crashWhenCantFindBone Whether the controller should throw an exception when unable to find the required + * bone, or continue with the remaining bones + */ + public void runCurrentAnimation( + Map boneAnimationQueues, + T animatable, + double adjustedTick, + double seekTime, + boolean crashWhenCantFindBone + ) { + var animationQueue = animationController.getAnimationQueue(); + var animationState = animationController.getAnimationState(); + var currentAnimation = animationController.getCurrentAnimation(); + var keyFrameCallbackManager = animationController.getKeyFrameCallbackManager(); + var transitionLength = animationController.getTransitionLength(); + + if (adjustedTick >= currentAnimation.animation().length()) { + if ( + currentAnimation.loopType() + .shouldPlayAgain(animatable, animationController, currentAnimation.animation()) + ) { + if (animationState != AzAnimationControllerState.PAUSED) { + animationController.setShouldResetTick(true); + + adjustedTick = animationController.adjustTick(animatable, seekTime); + keyFrameCallbackManager.reset(); + } + } else { + var nextAnimation = animationQueue.peek(); + + keyFrameCallbackManager.reset(); + + if (nextAnimation == null) { + animationController.setAnimationState(AzAnimationControllerState.STOPPED); + + return; + } else { + animationController.setAnimationState(AzAnimationControllerState.TRANSITIONING); + animationController.setShouldResetTick(true); + animationController.setCurrentAnimation(nextAnimation); + } + } + } + + final double finalAdjustedTick = adjustedTick; + + MolangParser.INSTANCE.setMemoizedValue(MolangQueries.ANIM_TIME, () -> finalAdjustedTick / 20d); + + for (var boneAnimation : currentAnimation.animation().boneAnimations()) { + var boneAnimationQueue = boneAnimationQueues.get(boneAnimation.boneName()); + + if (boneAnimationQueue == null) { + if (crashWhenCantFindBone) + throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); + + continue; + } + + var rotationKeyFrames = boneAnimation.rotationKeyFrames(); + var positionKeyFrames = boneAnimation.positionKeyFrames(); + var scaleKeyFrames = boneAnimation.scaleKeyFrames(); + + if (!rotationKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addRotations( + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) + ); + } + + if (!positionKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addPositions( + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + ); + } + + if (!scaleKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addScales( + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + ); + } + } + + adjustedTick += transitionLength; + + keyFrameCallbackManager.handle(animatable, adjustedTick); + } + + public void transitionFromCurrentAnimation( + Map boneAnimationQueues, + Map bones, + boolean crashWhenCantFindBone, + double adjustedTick + ) { + var boneSnapshotCache = animationController.getBoneSnapshotCache(); + var currentAnimation = animationController.getCurrentAnimation(); + var transitionLength = animationController.getTransitionLength(); + + MolangParser.INSTANCE.setValue(MolangQueries.ANIM_TIME, () -> 0); + + for (var boneAnimation : currentAnimation.animation().boneAnimations()) { + var boneAnimationQueue = boneAnimationQueues.get(boneAnimation.boneName()); + var boneSnapshot = boneSnapshotCache.getOrNull(boneAnimation.boneName()); + var bone = bones.get(boneAnimation.boneName()); + + if (bone == null) { + if (crashWhenCantFindBone) + throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); + + continue; + } + + var rotationKeyFrames = boneAnimation.rotationKeyFrames(); + var positionKeyFrames = boneAnimation.positionKeyFrames(); + var scaleKeyFrames = boneAnimation.scaleKeyFrames(); + + if (!rotationKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addNextRotation( + null, + adjustedTick, + transitionLength, + boneSnapshot, + bone.getInitialSnapshot(), + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) + ); + } + + if (!positionKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addNextPosition( + null, + adjustedTick, + transitionLength, + boneSnapshot, + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) + ); + } + + if (!scaleKeyFrames.xKeyframes().isEmpty()) { + boneAnimationQueue.addNextScale( + null, + adjustedTick, + transitionLength, + boneSnapshot, + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) + ); + } + } + } + + /** + * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} + */ + private AnimationPoint getAnimationPointAtTick( + List> frames, + double tick, + boolean isRotation, + Axis axis + ) { + var location = getCurrentKeyFrameLocation(frames, tick); + var currentFrame = location.keyframe(); + var startValue = currentFrame.startValue().get(); + var endValue = currentFrame.endValue().get(); + + if (isRotation) { + if (!(currentFrame.startValue() instanceof Constant)) { + startValue = Math.toRadians(startValue); + + if (axis == Axis.X || axis == Axis.Y) { + startValue *= -1; + } + } + + if (!(currentFrame.endValue() instanceof Constant)) { + endValue = Math.toRadians(endValue); + + if (axis == Axis.X || axis == Axis.Y) { + endValue *= -1; + } + } + } + + return new AnimationPoint(currentFrame, location.startTick(), currentFrame.length(), startValue, endValue); + } + + /** + * Returns the {@link Keyframe} relevant to the current tick time + * + * @param frames The list of {@code KeyFrames} to filter through + * @param ageInTicks The current tick time + * @return A new {@code KeyFrameLocation} containing the current {@code KeyFrame} and the tick time used to find it + */ + protected KeyframeLocation> getCurrentKeyFrameLocation( + List> frames, + double ageInTicks + ) { + var totalFrameTime = 0; + + for (var frame : frames) { + totalFrameTime += frame.length(); + + if (totalFrameTime > ageInTicks) { + return new KeyframeLocation<>(frame, (ageInTicks - (totalFrameTime - frame.length()))); + } + } + + return new KeyframeLocation<>(frames.get(frames.size() - 1), ageInTicks); + } +} From 4793c73c205f4100f17f8d19c526a0418e1f14a3 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 16:03:43 -0500 Subject: [PATCH 040/224] Fixed javadoc. Signed-off-by: = --- .../animation/event/AzCustomInstructionKeyframeEvent.java | 3 ++- .../core2/animation/event/AzParticleKeyframeEvent.java | 4 ++-- .../azurelib/core2/animation/event/AzSoundKeyframeEvent.java | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java index 8eb37ea4d..42b17951e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java @@ -2,9 +2,10 @@ import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; /** - * The {@link AzKeyFrameEvent} specific to the {@link AzAnimationController#customKeyframeHandler}.
    + * The {@link AzKeyFrameEvent} specific to the {@link AzKeyFrameCallbacks#getCustomKeyframeHandler()}.
    * Called when a custom instruction keyframe is encountered */ public class AzCustomInstructionKeyframeEvent extends AzKeyFrameEvent { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java index 59221de64..f68df7c8f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java @@ -5,12 +5,12 @@ */ package mod.azure.azurelib.core2.animation.event; -import mod.azure.azurelib.core.keyframe.event.KeyFrameEvent; import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; /** - * The {@link KeyFrameEvent} specific to the {@link AzAnimationController#particleKeyframeHandler}.
    + * The {@link AzKeyFrameEvent} specific to the {@link AzKeyFrameCallbacks#getParticleKeyframeHandler()}.
    * Called when a particle instruction keyframe is encountered */ public class AzParticleKeyframeEvent extends AzKeyFrameEvent { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java index 1a074a5d5..cd39b0971 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java @@ -5,12 +5,12 @@ */ package mod.azure.azurelib.core2.animation.event; -import mod.azure.azurelib.core.keyframe.event.KeyFrameEvent; import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; /** - * The {@link KeyFrameEvent} specific to the {@link AzAnimationController#soundKeyframeHandler}.
    + * The {@link AzKeyFrameEvent} specific to the {@link AzKeyFrameCallbacks#getSoundKeyframeHandler()}.
    * Called when a sound instruction keyframe is encountered */ public class AzSoundKeyframeEvent extends AzKeyFrameEvent { From 736432766d2064802264487dd49d0d73e817ab90 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 18:20:21 -0500 Subject: [PATCH 041/224] Added facehugger entity. Signed-off-by: = --- .../entity/facehugger.animation.json | 1981 +++++++++++++++++ .../azurelib/geo/entity/facehugger.geo.json | 397 ++++ .../azurelib/textures/entity/facehugger.png | Bin 0 -> 3201 bytes .../azure/azurelib/fabric/ClientListener.java | 2 + .../core2/example/ExampleEntityTypes.java | 6 + .../fabric/core2/example/Facehugger.java | 24 + .../core2/example/FacehuggerAnimator.java | 31 + .../core2/example/FacehuggerRenderer.java | 35 + 8 files changed, 2476 insertions(+) create mode 100644 common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json create mode 100644 common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json create mode 100644 common/src/main/resources/assets/azurelib/textures/entity/facehugger.png create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java diff --git a/common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json b/common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json new file mode 100644 index 000000000..8e8afd594 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json @@ -0,0 +1,1981 @@ +{ + "format_version": "1.8.0", + "animations": { + "animation.tailsway": { + "loop": true, + "animation_length": 2, + "bones": { + "gTail1": { + "rotation": { + "vector": [-5.5, "Math.cos(query.anim_time*180)*-0.5", "Math.cos(query.anim_time*180)*-0.4"] + } + }, + "gTail2": { + "rotation": { + "vector": [-5, "Math.cos(query.anim_time*180)*-1", "Math.cos(query.anim_time*180)*-0.4"] + } + }, + "gTail3": { + "rotation": { + "vector": [-2, "Math.cos(query.anim_time*180)*-1", "Math.cos(query.anim_time*180)*-0.4"] + } + }, + "gTail4": { + "rotation": { + "vector": ["5+Math.sin(query.anim_time*180)*0.5", "Math.cos(query.anim_time*180)*-2", "Math.cos(query.anim_time*180)*-0.3"] + } + }, + "gTail5": { + "rotation": { + "vector": ["Math.cos(query.anim_time*180)+19.5", "Math.cos(query.anim_time*180)*-2.5", "Math.cos(query.anim_time*180)*-0.4"] + } + }, + "gTail6": { + "rotation": { + "vector": ["15+Math.sin(query.anim_time*180)*0.5", "Math.cos(query.anim_time*180)*-3", "Math.cos(query.anim_time*180)*-0.4"] + } + }, + "gTail7": { + "rotation": { + "vector": ["Math.cos(query.anim_time*180)+7", "Math.sin(query.anim_time*180)*-3.5", "Math.sin(query.anim_time*180)*-0.8"] + } + }, + "gTail8": { + "rotation": { + "vector": ["10+Math.sin(query.anim_time*180)*0.5", "Math.sin(query.anim_time*180)*-4", "Math.sin(query.anim_time*180)*-0.8"] + } + }, + "gTail9": { + "rotation": { + "vector": ["Math.cos(query.anim_time*180)+12", "Math.sin(query.anim_time*180)*-4.5", "Math.sin(query.anim_time*180)*-0.8"] + } + }, + "gTail10": { + "rotation": { + "vector": ["12.5+Math.sin(query.anim_time*180)*0.5", "Math.sin(query.anim_time*180)*-5", "Math.sin(query.anim_time*180)*-0.8"] + } + }, + "gTail11": { + "rotation": { + "vector": [0, "Math.sin(query.anim_time*180)*-5.5", "Math.sin(query.anim_time*180)*-0.8"] + } + }, + "gMainBody": { + "rotation": { + "vector": ["Math.cos(query.anim_time*180)*-0.5", 0, 0] + } + }, + "gLowerBody": { + "rotation": { + "vector": ["Math.sin(query.anim_time*180)*0.25", 0, 0] + } + } + } + }, + "animation.sack": { + "loop": true, + "animation_length": 2, + "bones": { + "gSackLeft": { + "scale": { + "0.0": { + "vector": [1, 1, 1] + }, + "1.0": { + "vector": [0.95, 0.95, 0.95], + "easing": "easeInQuad" + }, + "2.0": { + "vector": [1, 1, 1], + "easing": "easeInQuad" + } + } + }, + "gSackRight": { + "scale": { + "0.0": { + "vector": [1, 1, 1] + }, + "1.0": { + "vector": [0.95, 0.95, 0.95], + "easing": "easeInQuad" + }, + "2.0": { + "vector": [1, 1, 1], + "easing": "easeInQuad" + } + } + } + } + }, + "animation.tailflail": { + "loop": true, + "animation_length": 0.5, + "bones": { + "gTail1": { + "rotation": { + "vector": ["-7+Math.cos(query.anim_time*1630)*-0.4", "Math.cos(query.anim_time*680)*-1.5", "Math.cos(query.anim_time*650)*-0.4"] + } + }, + "gTail2": { + "rotation": { + "vector": ["-8.5+ Math.cos(query.anim_time*1630)*-0.4", "Math.cos(query.anim_time*680)*-3", "Math.cos(query.anim_time*650)*-0.4"] + } + }, + "gTail3": { + "rotation": { + "vector": ["7.5+Math.cos(query.anim_time*1630)*-0.4", "Math.cos(query.anim_time*680)*-4.5", "Math.cos(query.anim_time*650)*-0.4"] + } + }, + "gTail4": { + "rotation": { + "vector": ["Math.cos(query.anim_time*1630)*5.6", "Math.cos(query.anim_time*680)*-6", "Math.cos(query.anim_time*650)*-0.4"] + } + }, + "gTail5": { + "rotation": { + "vector": ["12.5+Math.cos(query.anim_time*1630)*-0.4", "Math.cos(query.anim_time*680)*-7.5", "Math.cos(query.anim_time*650)*-0.4"] + } + }, + "gTail6": { + "rotation": { + "vector": ["12.5+Math.cos(query.anim_time*1630)*-0.4", "Math.cos(query.anim_time*680)*-9", "Math.cos(query.anim_time*650)*-0.4"] + } + }, + "gTail7": { + "rotation": { + "vector": ["10+Math.sin(query.anim_time*1630)*-0.8", "Math.sin(query.anim_time*680)*-10.5", "Math.sin(query.anim_time*650)*-0.8"] + } + }, + "gTail8": { + "rotation": { + "vector": ["5+Math.sin(query.anim_time*1630)*-0.8", "Math.sin(query.anim_time*680)*-12", "Math.sin(query.anim_time*650)*-0.8"] + } + }, + "gTail9": { + "rotation": { + "vector": ["Math.sin(query.anim_time*1630)*-0.8", "Math.sin(query.anim_time*680)*-13.5", "Math.sin(query.anim_time*650)*-0.8"] + } + }, + "gTail10": { + "rotation": { + "vector": ["Math.sin(query.anim_time*1630)*-0.8", "Math.sin(query.anim_time*600)*-15", "Math.sin(query.anim_time*600)*-0.8"] + } + }, + "gTail11": { + "rotation": { + "vector": ["Math.sin(query.anim_time*1630)*-0.8", "Math.sin(query.anim_time*680)*-15", "Math.sin(query.anim_time*650)*-0.8"] + } + } + } + }, + "animation.run": { + "loop": true, + "animation_length": 0.5, + "bones": { + "gWholeBody": { + "rotation": { + "vector": [0, "Math.cos(query.anim_time*680)*2.5", "Math.sin(query.anim_time*650)*2.5"] + }, + "position": { + "vector": [0, -1.2, 0] + } + }, + "gLowerBody": { + "rotation": { + "vector": ["-11+Math.sin(query.anim_time*680)*0.25", 0, 0] + } + }, + "gLMidLeg1": { + "rotation": { + "vector": [0, 0, 20] + } + }, + "gLMidLeg2": { + "rotation": { + "vector": [0, 0, 20] + } + }, + "gLBottomLeg": { + "rotation": { + "vector": [0, 0, 20] + } + }, + "gLBottomLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, -42.5] + }, + "0.0417": { + "vector": [0, 0, -55], + "easing": "easeOutSine" + }, + "0.0833": { + "vector": [0, 0, -60], + "easing": "easeOutSine" + }, + "0.125": { + "vector": [0, 0, -67.5], + "easing": "easeOutSine" + }, + "0.1667": { + "vector": [0, 0, -50], + "easing": "easeOutSine" + }, + "0.25": { + "vector": [0, 0, -42.5], + "easing": "easeOutSine" + }, + "0.2917": { + "vector": [0, 0, -52.5], + "easing": "easeOutSine" + }, + "0.3333": { + "vector": [0, 0, -55], + "easing": "easeOutSine" + }, + "0.375": { + "vector": [0, 0, -62.5], + "easing": "easeOutSine" + }, + "0.4167": { + "vector": [0, 0, -47.5], + "easing": "easeOutSine" + }, + "0.5": { + "vector": [0, 0, -40], + "easing": "easeOutSine" + } + } + }, + "gLBottomLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 8.5] + }, + "0.0417": { + "vector": [0, 0, 31], + "easing": "easeOutSine" + }, + "0.0833": { + "vector": [0, 0, 41], + "easing": "easeOutSine" + }, + "0.125": { + "vector": [0, 0, 8.5], + "easing": "easeOutSine" + }, + "0.1667": { + "vector": [0, 0, -4], + "easing": "easeOutSine" + }, + "0.25": { + "vector": [0, 0, 8.5], + "easing": "easeOutSine" + }, + "0.2917": { + "vector": [0, 0, 33.5], + "easing": "easeOutSine" + }, + "0.3333": { + "vector": [0, 0, 41], + "easing": "easeOutSine" + }, + "0.375": { + "vector": [0, 0, 8.5], + "easing": "easeOutSine" + }, + "0.4167": { + "vector": [0, 0, -4], + "easing": "easeOutSine" + }, + "0.5": { + "vector": [0, 0, 8.5], + "easing": "easeOutSine" + } + } + }, + "gLFrontLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, -32.5] + }, + "0.0417": { + "vector": [0, 0, -16] + }, + "0.0833": { + "vector": [0, 0, -1] + }, + "0.125": { + "vector": [0, 0, -21] + }, + "0.1667": { + "vector": [0, 0, -30] + }, + "0.25": { + "vector": [0, 0, -32.5] + }, + "0.2917": { + "vector": [0, 0, -16] + }, + "0.3333": { + "vector": [0, 0, 1.5] + }, + "0.375": { + "vector": [0, 0, -18.5] + }, + "0.4167": { + "vector": [0, 0, -27.5] + }, + "0.5": { + "vector": [0, 0, -32.5] + } + } + }, + "gLFrontLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, -32.5] + }, + "0.0417": { + "vector": [0, 0, -32], + "easing": "easeOutQuad" + }, + "0.0833": { + "vector": [0, 0, -33.5], + "easing": "easeOutQuad" + }, + "0.125": { + "vector": [0, 0, 3.5], + "easing": "easeOutQuad" + }, + "0.1667": { + "vector": [0, 0, 25.5], + "easing": "easeOutQuad" + }, + "0.25": { + "vector": [0, 0, -32.5] + }, + "0.2917": { + "vector": [0, 0, -32], + "easing": "easeOutQuad" + }, + "0.3333": { + "vector": [0, 0, -31], + "easing": "easeOutQuad" + }, + "0.375": { + "vector": [0, 0, 6], + "easing": "easeOutQuad" + }, + "0.4167": { + "vector": [0, 0, 28], + "easing": "easeOutQuad" + }, + "0.5": { + "vector": [0, 0, -32.5], + "easing": "easeOutQuad" + } + } + }, + "gLMidLeg1Mid": { + "rotation": { + "0.0": { + "vector": [0, 0, -32] + }, + "0.0417": { + "vector": [0, 0, -45] + }, + "0.0833": { + "vector": [0, 0, -57.5] + }, + "0.125": { + "vector": [0, 0, -62.5] + }, + "0.1667": { + "vector": [0, 0, -40] + }, + "0.25": { + "vector": [0, 0, -32] + }, + "0.2917": { + "vector": [0, 0, -42.5] + }, + "0.3333": { + "vector": [0, 0, -57.5] + }, + "0.375": { + "vector": [0, 0, -62.5] + }, + "0.4167": { + "vector": [0, 0, -40] + }, + "0.5": { + "vector": [0, 0, -29.5] + } + } + }, + "gLMidLeg1Bottom": { + "rotation": { + "0.0": { + "vector": [0, 0, -15] + }, + "0.0417": { + "vector": [0, 0, 12.5] + }, + "0.0833": { + "vector": [0, 0, 35] + }, + "0.125": { + "vector": [0, 0, -5] + }, + "0.1667": { + "vector": [0, 0, -25] + }, + "0.25": { + "vector": [0, 0, -15] + }, + "0.2917": { + "vector": [0, 0, 12.5] + }, + "0.3333": { + "vector": [0, 0, 35] + }, + "0.375": { + "vector": [0, 0, -5] + }, + "0.4167": { + "vector": [0, 0, -25] + }, + "0.5": { + "vector": [0, 0, -15] + } + } + }, + "gLMidLeg2Mid": { + "rotation": { + "0.0": { + "vector": [0, 0, -70] + }, + "0.0417": { + "vector": [0, 0, -47.5] + }, + "0.0833": { + "vector": [0, 0, -32.5] + }, + "0.125": { + "vector": [0, 0, -50] + }, + "0.1667": { + "vector": [0, 0, -67] + }, + "0.25": { + "vector": [0, 0, -70] + }, + "0.2917": { + "vector": [0, 0, -47.5] + }, + "0.3333": { + "vector": [0, 0, -27.5] + }, + "0.375": { + "vector": [0, 0, -45] + }, + "0.4167": { + "vector": [0, 0, -62] + }, + "0.5": { + "vector": [0, 0, -70] + } + } + }, + "gLMidLeg2Bottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.0417": { + "vector": [0, 0, -12.5], + "easing": "easeInQuad" + }, + "0.0833": { + "vector": [0, 0, -15.5], + "easing": "easeInQuad" + }, + "0.125": { + "vector": [0, 0, 15.5], + "easing": "easeInQuad" + }, + "0.1667": { + "vector": [0, 0, 47.5], + "easing": "easeInQuad" + }, + "0.25": { + "vector": [0, 0, 0], + "easing": "easeInQuad" + }, + "0.2917": { + "vector": [0, 0, -10], + "easing": "easeInQuad" + }, + "0.3333": { + "vector": [0, 0, -10.5], + "easing": "easeInQuad" + }, + "0.375": { + "vector": [0, 0, 20.5], + "easing": "easeInQuad" + }, + "0.4167": { + "vector": [0, 0, 50], + "easing": "easeInQuad" + }, + "0.5": { + "vector": [0, 0, 0], + "easing": "easeInQuad" + } + } + }, + "gRFrontLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, 1] + }, + "0.0417": { + "vector": [0, 0, 21] + }, + "0.0833": { + "vector": [0, 0, 30] + }, + "0.125": { + "vector": [0, 0, 32.5] + }, + "0.1667": { + "vector": [0, 0, 16] + }, + "0.25": { + "vector": [0, 0, 1] + }, + "0.2917": { + "vector": [0, 0, 21] + }, + "0.3333": { + "vector": [0, 0, 30] + }, + "0.375": { + "vector": [0, 0, 32.5] + }, + "0.4167": { + "vector": [0, 0, 16] + }, + "0.5": { + "vector": [0, 0, 1] + } + } + }, + "gRFrontLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 33.5] + }, + "0.0417": { + "vector": [0, 0, 3.5] + }, + "0.0833": { + "vector": [0, 0, -25.5] + }, + "0.125": { + "vector": [0, 0, 32.5] + }, + "0.1667": { + "vector": [0, 0, 32] + }, + "0.25": { + "vector": [0, 0, 33.5] + }, + "0.2917": { + "vector": [0, 0, 3.5] + }, + "0.3333": { + "vector": [0, 0, -25.5] + }, + "0.375": { + "vector": [0, 0, 32.5] + }, + "0.4167": { + "vector": [0, 0, 32] + }, + "0.5": { + "vector": [0, 0, 33.5] + } + } + }, + "gRMidLeg1Mid": { + "rotation": { + "0.0": { + "vector": [0, 0, 30] + }, + "0.0417": { + "vector": [0, 0, 35], + "easing": "easeInExpo" + }, + "0.0833": { + "vector": [0, 0, 12.5], + "easing": "easeInExpo" + }, + "0.125": { + "vector": [0, 0, 32], + "easing": "easeInExpo" + }, + "0.1667": { + "vector": [0, 0, 17.5], + "easing": "easeInExpo" + }, + "0.25": { + "vector": [0, 0, 27.5] + }, + "0.2917": { + "vector": [0, 0, 32.5], + "easing": "easeInExpo" + }, + "0.3333": { + "vector": [0, 0, 10], + "easing": "easeInExpo" + }, + "0.375": { + "vector": [0, 0, 29.5], + "easing": "easeInExpo" + }, + "0.4167": { + "vector": [0, 0, 25], + "easing": "easeInExpo" + }, + "0.5": { + "vector": [0, 0, 32.5] + } + } + }, + "gRMidLeg1Bottom": { + "rotation": { + "0.0": { + "vector": [0, 0, -35] + }, + "0.0417": { + "vector": [0, 0, 5] + }, + "0.0833": { + "vector": [0, 0, 25] + }, + "0.125": { + "vector": [0, 0, -15] + }, + "0.1667": { + "vector": [0, 0, -12.5] + }, + "0.25": { + "vector": [0, 0, -35] + }, + "0.2917": { + "vector": [0, 0, 5] + }, + "0.3333": { + "vector": [0, 0, 25] + }, + "0.375": { + "vector": [0, 0, -15] + }, + "0.4167": { + "vector": [0, 0, -12.5] + }, + "0.5": { + "vector": [0, 0, -35] + } + } + }, + "gRMidLeg2Mid": { + "rotation": { + "0.0": { + "vector": [0, 0, 5] + }, + "0.0417": { + "vector": [0, 0, 22.5] + }, + "0.0833": { + "vector": [0, 0, 32] + }, + "0.125": { + "vector": [0, 0, 42.5] + }, + "0.1667": { + "vector": [0, 0, 20] + }, + "0.25": { + "vector": [0, 0, 5] + }, + "0.2917": { + "vector": [0, 0, 22.5] + }, + "0.3333": { + "vector": [0, 0, 32] + }, + "0.375": { + "vector": [0, 0, 42.5] + }, + "0.4167": { + "vector": [0, 0, 20] + }, + "0.5": { + "vector": [0, 0, 7.5] + } + } + }, + "gRMidLeg2Bottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 15.5] + }, + "0.0417": { + "vector": [0, 0, -15.5] + }, + "0.0833": { + "vector": [0, 0, -47.5] + }, + "0.125": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [0, 0, 12.5] + }, + "0.25": { + "vector": [0, 0, 15.5] + }, + "0.2917": { + "vector": [0, 0, -15.5] + }, + "0.3333": { + "vector": [0, 0, -47.5] + }, + "0.375": { + "vector": [0, 0, 0] + }, + "0.4167": { + "vector": [0, 0, 12.5] + }, + "0.5": { + "vector": [0, 0, 15.5] + } + } + }, + "gRBottomLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, 30] + }, + "0.0417": { + "vector": [0, 0, 40] + }, + "0.0833": { + "vector": [0, 0, 22.5] + }, + "0.125": { + "vector": [0, 0, 15] + }, + "0.1667": { + "vector": [0, 0, 25] + }, + "0.25": { + "vector": [0, 0, 30] + }, + "0.2917": { + "vector": [0, 0, 40] + }, + "0.3333": { + "vector": [0, 0, 22.5] + }, + "0.375": { + "vector": [0, 0, 22.5] + }, + "0.4167": { + "vector": [0, 0, 32.5] + }, + "0.5": { + "vector": [0, 0, 35] + } + } + }, + "gRBottomLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, -41] + }, + "0.0417": { + "vector": [0, 0, -8.5] + }, + "0.0833": { + "vector": [0, 0, 4] + }, + "0.125": { + "vector": [0, 0, -8.5] + }, + "0.1667": { + "vector": [0, 0, -31] + }, + "0.25": { + "vector": [0, 0, -41] + }, + "0.2917": { + "vector": [0, 0, -8.5] + }, + "0.3333": { + "vector": [0, 0, 4] + }, + "0.375": { + "vector": [0, 0, -8.5] + }, + "0.4167": { + "vector": [0, 0, -31] + }, + "0.5": { + "vector": [0, 0, -41] + } + } + } + } + }, + "animation.leap": { + "loop": "hold_on_last_frame", + "animation_length": 1, + "bones": { + "gWholeBody": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -2, 0] + } + } + }, + "gLFrontLeg": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, -15] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "gLFrontLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, -17.5] + }, + "1.0": { + "vector": [0, 0, 3] + } + } + }, + "gLFrontLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, -52.5] + }, + "1.0": { + "vector": [0, 0, -65] + } + } + }, + "gRFrontLeg": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 15] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "gRFrontLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 17.5] + }, + "1.0": { + "vector": [0, 0, -3] + } + } + }, + "gRFrontLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 52.5] + }, + "1.0": { + "vector": [0, 0, 65] + } + } + }, + "gLeftSide": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, -15] + } + } + }, + "gLMidLeg1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [28, 8, 19] + }, + "0.75": { + "vector": [39, -4, 39] + }, + "1.0": { + "vector": [-8, 14, 6] + } + } + }, + "gLMidLeg1Mid": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [5, -2, -20], + "easing": "linear" + }, + "0.375": { + "vector": [4, -1, -18], + "easing": "linear" + }, + "0.5": { + "vector": [-3, -2, -13], + "easing": "easeInExpo" + }, + "0.75": { + "vector": [-3, 1, 45] + }, + "1.0": { + "vector": [-3, -2, -3] + } + } + }, + "gLMidLeg1Bottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [1, 4, 22], + "easing": "easeInElastic", + "easingArgs": [6] + }, + "0.75": { + "vector": [-4, 2, -49] + }, + "1.0": { + "vector": [-4, 1, -59] + } + }, + "position": { + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0.39619, -0.1141, 0.00413] + } + } + }, + "gLMidLeg2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [31, 15, 10] + }, + "0.75": { + "vector": [26, 6, 25] + }, + "1.0": { + "vector": [-7, 4, 10] + } + } + }, + "gLMidLeg2Mid": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [1, -2, -21] + }, + "0.375": { + "vector": [1, -2, -29] + }, + "0.4583": { + "vector": [0, -1, -14] + }, + "0.5": { + "vector": [0, 0, -33], + "easing": "easeInExpo" + }, + "0.75": { + "vector": [0, 0, 47] + }, + "1.0": { + "vector": [0, 0, -8] + } + } + }, + "gLMidLeg2Bottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 60], + "easing": "easeInOutElastic", + "easingArgs": [4] + }, + "0.75": { + "vector": [0, 0, -38] + }, + "1.0": { + "vector": [0, 0, -55] + } + }, + "position": { + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0.21346, -0.39277, -0.0131] + }, + "1.0": { + "vector": [0.21, -0.39, -0.01] + } + } + }, + "gLBottomLeg": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [28, 19, -3] + }, + "0.75": { + "vector": [23, 11, 13] + }, + "1.0": { + "vector": [-4, 0, 3] + } + } + }, + "gLBottomLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-2, 0, -21] + }, + "0.375": { + "vector": [-1, 0, -27] + }, + "0.5": { + "vector": [0, 0, -27.5], + "easing": "easeInExpo" + }, + "0.75": { + "vector": [0, 0, 53] + }, + "1.0": { + "vector": [0, 0, -8] + } + } + }, + "gLBottomLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 55], + "easing": "easeInOutElastic", + "easingArgs": [1] + }, + "0.75": { + "vector": [0, 0, -38] + }, + "1.0": { + "vector": [0, 0, -53] + } + } + }, + "gRightSide": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 15] + } + } + }, + "gRMidLeg1Mid": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [5, 2, 20] + }, + "0.375": { + "vector": [4, 1, 18] + }, + "0.5": { + "vector": [0, 0, 19] + }, + "0.75": { + "vector": [3, -1, -45] + }, + "1.0": { + "vector": [3, 2, -3] + } + } + }, + "gRMidLeg1Bottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [1, -4, -22], + "easing": "easeInElastic", + "easingArgs": [6] + }, + "0.75": { + "vector": [-4, -2, 49] + }, + "1.0": { + "vector": [-4, -1, 59] + } + }, + "position": { + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [-0.38391, -0.09245, -0.0264] + } + } + }, + "gRMidLeg2Mid": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [1, -2, 21] + }, + "0.375": { + "vector": [1, 2, 29] + }, + "0.4583": { + "vector": [0, 1, 14] + }, + "0.5": { + "vector": [0, 0, 33] + }, + "0.75": { + "vector": [0, 0, -47] + }, + "1.0": { + "vector": [0, 0, -8] + } + } + }, + "gRMidLeg2Bottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, -60] + }, + "0.75": { + "vector": [0, 0, 38] + }, + "1.0": { + "vector": [0, 0, 55] + } + }, + "position": { + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [-0.36551, -0.25416, -0.01] + }, + "1.0": { + "vector": [-0.37, -0.25, -0.01] + } + } + }, + "gRBottomLeg": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [28, -19, 3] + }, + "0.75": { + "vector": [23, -11, -13] + }, + "1.0": { + "vector": [-4, 0, -3] + } + } + }, + "gRBottomLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [2, 0, 21] + }, + "0.375": { + "vector": [1, 0, 27] + }, + "0.5": { + "vector": [0, 0, 27.5] + }, + "0.75": { + "vector": [0, 0, -53] + }, + "1.0": { + "vector": [0, 0, 8] + } + } + }, + "gRBottomLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, -55], + "easing": "easeInOutElastic", + "easingArgs": [1] + }, + "0.75": { + "vector": [0, 0, 38] + }, + "1.0": { + "vector": [0, 0, 53] + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [22.5, 0, 0] + }, + "0.6667": { + "vector": [2.5, 0, 0] + }, + "1.0": { + "vector": [25, 0, 0] + } + } + }, + "gTail1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0.62758, 19.6835, 3.61644], + "easing": "easeInOutSine" + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "gTail2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [9.50596, -70.30667, -8.99253], + "easing": "easeInOutSine" + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "gTail3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [-3.4038, -51.72343, -9.85026], + "easing": "easeInOutSine" + }, + "1.0": { + "vector": [5, 0, 0] + } + } + }, + "gTail4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [8.72705, 74.11249, 18.71331], + "easing": "easeInOutSine" + }, + "1.0": { + "vector": [5, 0, 0] + } + } + }, + "gTail5": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1667": { + "vector": [24.91131, 16.54561, 40.56656] + }, + "0.5": { + "vector": [159.64524, 66.18244, 162.26626], + "easing": "easeInOutSine" + }, + "0.7917": { + "vector": [30.34459, 8.75787, 33.21299] + }, + "1.0": { + "vector": [5, 0, 0] + } + } + }, + "gTail6": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2917": { + "vector": [15.1586, 11.48604, 5.77037] + }, + "0.3333": { + "vector": [13.68098, 14.16562, 5.81233] + }, + "0.5": { + "vector": [-0.31521, 39.54698, 6.20975], + "easing": "easeInOutSine" + }, + "0.7917": { + "vector": [12.36866, 16.47791, 2.5874] + }, + "1.0": { + "vector": [5, 0, 0] + } + } + }, + "gTail7": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [1.48528, -64.27201, -11.77905], + "easing": "easeInOutSine" + }, + "1.0": { + "vector": [7.5, 0, 0] + } + } + }, + "gTail8": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [28.58147, -32.08955, -22.12633] + }, + "0.25": { + "vector": [44.53674, -54.27114, -77.87602] + }, + "0.375": { + "vector": [187.05612, -77.32591, -191.78217] + }, + "0.5": { + "vector": [188.70832, -71.31063, -190.44535], + "easing": "easeInOutSine" + }, + "0.7917": { + "vector": [48.62847, -29.71276, -79.35223] + }, + "1.0": { + "vector": [5, 0, 0] + } + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [1.86218, -22.39881, 12.94741] + }, + "0.3333": { + "vector": [13.55561, -28.83001, 3.72954] + }, + "0.5": { + "vector": [2.84529, -38.89591, -12.03609], + "easing": "easeInOutSine" + }, + "0.7917": { + "vector": [28.68554, -16.20663, -5.01504] + }, + "1.0": { + "vector": [5, 0, 0] + } + } + }, + "gTail10": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [2.8142, -19.66726, 13.79217] + }, + "0.3333": { + "vector": [12.39061, -17.37222, 3.8378] + }, + "0.5": { + "vector": [-1.99961, -19.87032, -2.40596], + "easing": "easeInOutSine" + }, + "0.7917": { + "vector": [21.66683, -8.2793, -1.00248] + }, + "1.0": { + "vector": [2.5, 0, 0] + } + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.125": { + "vector": [4.34312, -11.50509, 19.45564] + }, + "0.5": { + "vector": [7.15184, 64.18323, 12.64352], + "easing": "easeInOutSine" + }, + "1.0": { + "vector": [2.5, 0, 0] + } + } + }, + "root": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [-32.5, 0, 0] + }, + "0.625": { + "vector": [-32.5, 0, 0] + }, + "1.0": { + "vector": [-90, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 5, 0] + } + } + }, + "gRMidLeg1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [30, -6, -24] + }, + "0.75": { + "vector": [39, 4, -39] + }, + "1.0": { + "vector": [-8, -14, -6] + } + } + }, + "gRMidLeg2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [31, -15, -10] + }, + "0.75": { + "vector": [26, -6, -25] + }, + "1.0": { + "vector": [-7, -4, -10] + } + } + } + } + }, + "animation.hug": { + "loop": "hold_on_last_frame", + "animation_length": 1, + "bones": { + "gWholeBody": { + "position": { + "vector": [0, -2, 0] + } + }, + "gLFrontLeg": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "gLFrontLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, 3] + }, + "0.5": { + "vector": [0, 0, 9], + "easing": "easeOutElastic" + } + } + }, + "gLFrontLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, -65] + }, + "0.5": { + "vector": [0, 0, 5], + "easing": "easeOutElastic" + } + } + }, + "gRFrontLeg": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "gRFrontLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, -3] + }, + "0.5": { + "vector": [0, 0, -3], + "easing": "easeOutElastic" + } + } + }, + "gRFrontLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 65] + }, + "0.5": { + "vector": [0, 0, -12], + "easing": "easeOutElastic" + } + } + }, + "gLeftSide": { + "rotation": { + "vector": [0, 0, -15] + } + }, + "gLMidLeg1": { + "rotation": { + "vector": [-8, 14, 6] + } + }, + "gLMidLeg1Mid": { + "rotation": { + "0.0": { + "vector": [-3, -2, -3] + }, + "0.5": { + "vector": [-3.5975, -0.2333, 26.95495], + "easing": "easeOutElastic", + "easingArgs": [2] + } + } + }, + "gLMidLeg1Bottom": { + "rotation": { + "0.0": { + "vector": [-4, 1, -59] + }, + "0.5": { + "vector": [-0.49984, 4.09255, 10.01706], + "easing": "easeOutExpo" + } + }, + "position": { + "vector": [0.4, -0.11, 0] + } + }, + "gLMidLeg2": { + "rotation": { + "vector": [-7, 4, 10] + } + }, + "gLMidLeg2Mid": { + "rotation": { + "0.0": { + "vector": [0, 0, -8] + }, + "0.5": { + "vector": [0, 0, 42], + "easing": "easeOutElastic", + "easingArgs": [2] + } + } + }, + "gLMidLeg2Bottom": { + "rotation": { + "0.0": { + "vector": [0, 0, -55] + }, + "0.5": { + "vector": [0, 0, -4], + "easing": "easeOutExpo" + } + }, + "position": { + "vector": [0.21, -0.39, -0.01] + } + }, + "gLBottomLeg": { + "rotation": { + "vector": [-4, 0, 3] + } + }, + "gLBottomLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, -8] + }, + "0.5": { + "vector": [0, 0, 50], + "easing": "easeOutElastic" + } + } + }, + "gLBottomLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, -53] + }, + "0.5": { + "vector": [0, 0, -8], + "easing": "easeOutExpo" + } + } + }, + "gRightSide": { + "rotation": { + "vector": [0, 0, 15] + } + }, + "gRMidLeg1Mid": { + "rotation": { + "0.0": { + "vector": [3, 2, -3] + }, + "0.5": { + "vector": [1.9804, 3.01297, -26.00029], + "easing": "easeOutElastic", + "easingArgs": [2] + } + } + }, + "gRMidLeg1Bottom": { + "rotation": { + "0.0": { + "vector": [-4, -1, 59] + }, + "0.5": { + "vector": [-0.14064, -4.12051, -15.02986], + "easing": "easeOutExpo" + } + }, + "position": { + "vector": [-0.38, -0.09, -0.03] + } + }, + "gRMidLeg2Mid": { + "rotation": { + "0.0": { + "vector": [0, 0, -8] + }, + "0.5": { + "vector": [0, 0, -41], + "easing": "easeOutElastic", + "easingArgs": [2] + } + } + }, + "gRMidLeg2Bottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 55] + }, + "0.5": { + "vector": [0, 0, 1], + "easing": "easeOutExpo" + } + }, + "position": { + "vector": [-0.37, -0.25, -0.01] + } + }, + "gRBottomLeg": { + "rotation": { + "vector": [-4, 0, -3] + } + }, + "gRBottomLegMid": { + "rotation": { + "0.0": { + "vector": [0, 0, 8] + }, + "0.5": { + "vector": [0, 0, -47], + "easing": "easeOutElastic" + } + } + }, + "gRBottomLegBottom": { + "rotation": { + "0.0": { + "vector": [0, 0, 53] + }, + "0.5": { + "vector": [0, 0, 4], + "easing": "easeOutExpo" + } + } + }, + "gLowerBody": { + "rotation": { + "0.0": { + "vector": [25, 0, 0] + }, + "0.5": { + "vector": [-10, 0, 0] + } + } + }, + "gTail1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.8333": { + "vector": [0, -27.5, 0], + "easing": "easeInExpo" + } + } + }, + "gTail2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.8333": { + "vector": [-16.21137, -47.24891, -22.58857], + "easing": "easeInExpo" + } + } + }, + "gTail3": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.8333": { + "vector": [3.43152, -22.7754, -2.55335], + "easing": "easeInExpo" + } + } + }, + "gTail4": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.8333": { + "vector": [-10.64538, -20.54777, 0.36816], + "easing": "easeInExpo" + } + } + }, + "gTail5": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.8333": { + "vector": [-21.76638, -21.57644, 11.52333], + "easing": "easeInExpo" + } + } + }, + "gTail6": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.8333": { + "vector": [-24.62328, 12.59297, -1.83968], + "easing": "easeInExpo" + } + } + }, + "gTail7": { + "rotation": { + "0.0": { + "vector": [7.5, 0, 0] + }, + "0.875": { + "vector": [-6.41797, 27.79564, -8.65747], + "easing": "easeInExpo" + } + } + }, + "gTail8": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.9167": { + "vector": [-46.34717, -35.75299, 16.98305], + "easing": "easeInExpo" + } + } + }, + "gTail9": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.9583": { + "vector": [-43.8764, -31.91772, 31.35942], + "easing": "easeInExpo" + } + } + }, + "gTail10": { + "rotation": { + "0.0": { + "vector": [2.5, 0, 0] + }, + "1.0": { + "vector": [17.06812, -8.43755, -9.68622], + "easing": "easeInExpo" + } + } + }, + "gTail11": { + "rotation": { + "0.0": { + "vector": [2.5, 0, 0] + }, + "1.0": { + "vector": [28.99061, -19.72598, -15.93986], + "easing": "easeInExpo" + } + } + }, + "root": { + "rotation": { + "vector": [-90, 0, 0] + }, + "position": { + "vector": [0, 5, 0] + } + }, + "gRMidLeg1": { + "rotation": { + "vector": [-8, -14, -6] + } + }, + "gRMidLeg2": { + "rotation": { + "vector": [-7, -4, -10] + } + } + } + } + }, + "azurelib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json b/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json new file mode 100644 index 000000000..fb4306d0c --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json @@ -0,0 +1,397 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 40, + "texture_height": 35, + "visible_bounds_width": 5, + "visible_bounds_height": 1.5, + "visible_bounds_offset": [0, 0.25, 0] + }, + "bones": [ + { + "name": "root", + "pivot": [0, 4, 0] + }, + { + "name": "gWholeBody", + "parent": "root", + "pivot": [0, 4, 0] + }, + { + "name": "gLFrontLeg", + "parent": "gWholeBody", + "pivot": [1.03227, 3.85146, -2.40085], + "rotation": [0, 47.5, -12.5], + "cubes": [ + {"origin": [0.36561, 2.95146, -2.90085], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15]} + ] + }, + { + "name": "gLFrontLegMid", + "parent": "gLFrontLeg", + "pivot": [2.06732, 3.37757, -2.40085], + "rotation": [0, 0, 7.5], + "cubes": [ + {"origin": [1.50206, 2.97329, -5.30085], "size": [1, 1, 3], "inflate": -0.1, "pivot": [2.00206, 3.87329, -2.40085], "rotation": [0, -90, 0], "uv": [15, 18], "mirror": true} + ] + }, + { + "name": "gLFrontLegBottom", + "parent": "gLFrontLegMid", + "pivot": [4.50361, 3.42542, -2.44872], + "rotation": [0, 0, 75], + "cubes": [ + {"origin": [3.91895, 2.90714, -5.00085], "size": [1, 1, 3], "inflate": -0.15, "pivot": [4.41895, 3.30714, -2.40085], "rotation": [0, -90, 0], "uv": [15, 23], "mirror": true}, + {"origin": [2.61895, 2.60714, -7.80085], "size": [3, 2, 4], "inflate": -1, "pivot": [4.11895, 3.40714, -2.40085], "rotation": [0, -90, 0], "uv": [12, 28]} + ] + }, + { + "name": "gRFrontLeg", + "parent": "gWholeBody", + "pivot": [-1.03227, 3.85146, -2.40085], + "rotation": [0, -47.5, 12.5], + "cubes": [ + {"origin": [-2.36561, 2.95146, -2.90085], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15], "mirror": true} + ] + }, + { + "name": "gRFrontLegMid", + "parent": "gRFrontLeg", + "pivot": [-2.06732, 3.37757, -2.40085], + "rotation": [0, 0, -7.5], + "cubes": [ + {"origin": [-2.50206, 2.97329, -5.30085], "size": [1, 1, 3], "inflate": -0.1, "pivot": [-2.00206, 3.87329, -2.40085], "rotation": [0, 90, 0], "uv": [15, 18]} + ] + }, + { + "name": "gRFrontLegBottom", + "parent": "gRFrontLegMid", + "pivot": [-4.50361, 3.42542, -2.44872], + "rotation": [0, 0, -75], + "cubes": [ + {"origin": [-4.91895, 2.90714, -5.00085], "size": [1, 1, 3], "inflate": -0.15, "pivot": [-4.41895, 3.30714, -2.40085], "rotation": [0, 90, 0], "uv": [15, 23]}, + {"origin": [-5.61895, 2.60714, -7.80085], "size": [3, 2, 4], "inflate": -1, "pivot": [-4.11895, 3.40714, -2.40085], "rotation": [0, 90, 0], "uv": [12, 28], "mirror": true} + ] + }, + { + "name": "gLeftSide", + "parent": "gWholeBody", + "pivot": [0.80141, 4.2, -0.10743], + "rotation": [4, 0, 20], + "cubes": [ + {"origin": [0.79859, 3.30146, -1.64929], "size": [1, 1, 3], "uv": [15, 10]} + ] + }, + { + "name": "gLMidLeg1", + "parent": "gLeftSide", + "pivot": [1.81902, 3.6746, -1.19876], + "rotation": [0, 15, -37.5], + "cubes": [ + {"origin": [1.15236, 3.2746, -1.69876], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15]} + ] + }, + { + "name": "gLMidLeg1Mid", + "parent": "gLMidLeg1", + "pivot": [2.62976, 3.7434, -1.19876], + "rotation": [0, 0, 15], + "cubes": [ + {"origin": [2.12976, 3.3434, -4.09876], "size": [1, 1, 3], "inflate": -0.1, "pivot": [2.62976, 4.2434, -1.19876], "rotation": [0, -90, 0], "uv": [15, 18], "mirror": true} + ] + }, + { + "name": "gLMidLeg1Bottom", + "parent": "gLMidLeg1Mid", + "pivot": [5.03309, 3.66477, -1.35008], + "rotation": [0, 0, 75], + "cubes": [ + {"origin": [4.44755, 3.27521, -3.69876], "size": [1, 1, 3], "inflate": -0.15, "pivot": [4.94755, 3.67521, -1.19876], "rotation": [0, -90, 0], "uv": [15, 23], "mirror": true}, + {"origin": [3.64755, 2.97521, -5.99876], "size": [3, 2, 4], "inflate": -1, "pivot": [5.14755, 3.77521, -1.19876], "rotation": [0, -90, 0], "uv": [12, 28]} + ] + }, + { + "name": "gLMidLeg2", + "parent": "gLeftSide", + "pivot": [1.7643, 4.15146, -0.128], + "rotation": [0, 0, -37.5], + "cubes": [ + {"origin": [1.09763, 3.25146, -0.628], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15]} + ] + }, + { + "name": "gLMidLeg2Mid", + "parent": "gLMidLeg2", + "pivot": [2.68198, 3.70005, -0.128], + "rotation": [0, 0, 17.5], + "cubes": [ + {"origin": [2.18198, 3.30005, -3.028], "size": [1, 1, 3], "inflate": -0.1, "pivot": [2.68198, 4.20005, -0.128], "rotation": [0, -90, 0], "uv": [15, 18], "mirror": true} + ] + }, + { + "name": "gLMidLeg2Bottom", + "parent": "gLMidLeg2Mid", + "pivot": [4.88236, 3.80108, -0.15959], + "rotation": [0, 0, 70], + "cubes": [ + {"origin": [4.53845, 3.66674, -2.68896], "size": [1, 1, 3], "inflate": -0.15, "pivot": [5.04084, 4.16066, -0.12323], "rotation": [0, -90, 0], "uv": [15, 23], "mirror": true}, + {"origin": [3.20657, 3.36674, -5.62561], "size": [3, 2, 4], "inflate": -1, "pivot": [4.70657, 4.16674, -0.12561], "rotation": [0, -90, 0], "uv": [12, 28]} + ] + }, + { + "name": "gLBottomLeg", + "parent": "gLeftSide", + "pivot": [1.56487, 4.05487, 0.90676], + "rotation": [0, -15, -37.5], + "cubes": [ + {"origin": [0.8982, 3.15487, 0.40676], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15]} + ] + }, + { + "name": "gLBottomLegMid", + "parent": "gLBottomLeg", + "pivot": [2.52659, 3.69929, 0.90676], + "rotation": [0, 0, 20], + "cubes": [ + {"origin": [3.42659, 3.19929, -0.59324], "size": [1, 1, 3], "inflate": -0.1, "pivot": [3.92659, 3.69929, 0.90676], "rotation": [0, -90, 0], "uv": [15, 18], "mirror": true} + ] + }, + { + "name": "gLBottomLegBottom", + "parent": "gLBottomLegMid", + "pivot": [5.15708, 3.61705, 0.83966], + "rotation": [0, 0, 67.5], + "cubes": [ + {"origin": [4.53053, 3.02755, -1.79324], "size": [1, 1, 3], "inflate": -0.15, "pivot": [5.03053, 3.52755, 0.90676], "rotation": [0, -90, 0], "uv": [15, 23], "mirror": true}, + {"origin": [3.33053, 2.72755, -4.49324], "size": [3, 2, 4], "inflate": -1, "pivot": [4.83053, 3.52755, 0.90676], "rotation": [0, -90, 0], "uv": [12, 28]} + ] + }, + { + "name": "gRightSide", + "parent": "gWholeBody", + "pivot": [-0.80141, 4.2, -0.10743], + "rotation": [4, 0, -20], + "cubes": [ + {"origin": [-1.79859, 3.30146, -1.64929], "size": [1, 1, 3], "uv": [15, 10], "mirror": true} + ] + }, + { + "name": "gRMidLeg1", + "parent": "gRightSide", + "pivot": [-1.81902, 3.6746, -1.19876], + "rotation": [0, -15, 37.5], + "cubes": [ + {"origin": [-3.15236, 3.2746, -1.69876], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15], "mirror": true} + ] + }, + { + "name": "gRMidLeg1Mid", + "parent": "gRMidLeg1", + "pivot": [-2.62976, 3.7434, -1.19876], + "rotation": [0, 0, -15], + "cubes": [ + {"origin": [-3.12976, 3.3434, -4.09876], "size": [1, 1, 3], "inflate": -0.1, "pivot": [-2.62976, 4.2434, -1.19876], "rotation": [0, 90, 0], "uv": [15, 18]} + ] + }, + { + "name": "gRMidLeg1Bottom", + "parent": "gRMidLeg1Mid", + "pivot": [-5.03309, 3.66477, -1.35008], + "rotation": [0, 0, -75], + "cubes": [ + {"origin": [-5.45071, 3.27521, -3.64165], "size": [1, 1, 3], "inflate": -0.15, "pivot": [-4.97769, 3.76667, -1.17179], "rotation": [0, 90, 0], "uv": [15, 23]}, + {"origin": [-6.64755, 2.97521, -5.99876], "size": [3, 2, 4], "inflate": -1, "pivot": [-5.14755, 3.77521, -1.19876], "rotation": [0, 90, 0], "uv": [12, 28], "mirror": true} + ] + }, + { + "name": "gRMidLeg2", + "parent": "gRightSide", + "pivot": [-1.7643, 4.15146, -0.128], + "rotation": [0, 0, 37.5], + "cubes": [ + {"origin": [-3.09763, 3.25146, -0.628], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15], "mirror": true} + ] + }, + { + "name": "gRMidLeg2Mid", + "parent": "gRMidLeg2", + "pivot": [-2.68198, 3.70005, -0.128], + "rotation": [0, 0, -17.5], + "cubes": [ + {"origin": [-3.18198, 3.30005, -3.028], "size": [1, 1, 3], "inflate": -0.1, "pivot": [-2.68198, 4.20005, -0.128], "rotation": [0, 90, 0], "uv": [15, 18]} + ] + }, + { + "name": "gRMidLeg2Bottom", + "parent": "gRMidLeg2Mid", + "pivot": [-4.88244, 3.7013, -0.16615], + "rotation": [0, 0, -70], + "cubes": [ + {"origin": [-5.37859, 3.5071, -2.728], "size": [1, 1, 3], "inflate": -0.15, "pivot": [-4.87859, 3.9071, -0.128], "rotation": [0, 90, 0], "uv": [15, 23]}, + {"origin": [-6.07859, 3.2071, -5.628], "size": [3, 2, 4], "inflate": -1, "pivot": [-4.57859, 4.0071, -0.128], "rotation": [0, 90, 0], "uv": [12, 28], "mirror": true} + ] + }, + { + "name": "gRBottomLeg", + "parent": "gRightSide", + "pivot": [-1.56487, 4.05487, 0.90676], + "rotation": [0, 15, 37.5], + "cubes": [ + {"origin": [-2.8982, 3.15487, 0.40676], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15], "mirror": true} + ] + }, + { + "name": "gRBottomLegMid", + "parent": "gRBottomLeg", + "pivot": [-2.52659, 3.69929, 0.90676], + "rotation": [0, 0, -20], + "cubes": [ + {"origin": [-4.42659, 3.19929, -0.59324], "size": [1, 1, 3], "inflate": -0.1, "pivot": [-3.92659, 3.69929, 0.90676], "rotation": [0, 90, 0], "uv": [15, 18]} + ] + }, + { + "name": "gRBottomLegBottom", + "parent": "gRBottomLegMid", + "pivot": [-5.15708, 3.61705, 0.83966], + "rotation": [0, 0, -67.5], + "cubes": [ + {"origin": [-5.53053, 3.02755, -1.79324], "size": [1, 1, 3], "inflate": -0.15, "pivot": [-5.03053, 3.52755, 0.90676], "rotation": [0, 90, 0], "uv": [15, 23]}, + {"origin": [-6.33053, 2.72755, -4.49324], "size": [3, 2, 4], "inflate": -1, "pivot": [-4.83053, 3.52755, 0.90676], "rotation": [0, 90, 0], "uv": [12, 28], "mirror": true} + ] + }, + { + "name": "gMainBody", + "parent": "gWholeBody", + "pivot": [0.70442, 4.12465, 0.6], + "cubes": [ + {"origin": [-0.5, 3.2, -3.1], "size": [1, 1, 2], "uv": [2, 10]}, + {"origin": [-0.53592, 3.52293, -3.29019], "size": [2, 2, 3], "inflate": -0.46, "pivot": [-0.09289, 4.94853, -0.70488], "rotation": [11.46188, -11.23918, 43.86846], "uv": [0, 15]}, + {"origin": [-0.79289, 2.54853, -1.20488], "size": [2, 2, 3], "inflate": -0.26, "pivot": [0.70711, 4.04853, -0.70488], "rotation": [4.96208, -4.94357, 44.78567], "uv": [0, 22]}, + {"origin": [-2, 1.9, -3.5], "size": [4, 3, 6], "inflate": -0.7, "pivot": [0, 2.9, -1.5], "rotation": [4, 0, 0], "uv": [0, 0]} + ] + }, + { + "name": "gLowerBody", + "parent": "gMainBody", + "pivot": [0, 4.02465, 1.4], + "cubes": [ + {"origin": [-1, 3.1, 1.1], "size": [2, 1, 2], "pivot": [0, 4.1, 1.6], "rotation": [9, 0, 0], "uv": [29, 15]}, + {"origin": [-0.8339, 3.58254, 0.20856], "size": [2, 2, 3], "inflate": -0.72, "pivot": [0.12399, 4.8, 2], "rotation": [-2.47641, 2.4741, 44.94652], "uv": [0, 29]}, + {"origin": [-1, 3.12465, 0.9], "size": [2, 2, 3], "inflate": -0.43, "pivot": [0, 4.3, 1.5], "rotation": [3, 0, 0], "uv": [28, 2]} + ] + }, + { + "name": "gSackLeft", + "parent": "gLowerBody", + "pivot": [1.38741, 3.66306, 3.09836], + "cubes": [ + {"origin": [0.01285, 3.10867, 2.1041], "size": [3, 1, 2], "inflate": -0.1, "pivot": [1.38741, 3.66306, 3.09836], "rotation": [2.55101, -34.39062, 9.17266], "uv": [28, 23], "mirror": true}, + {"origin": [-0.39514, 3.1672, 1.46743], "size": [3, 1, 2], "inflate": -0.2, "pivot": [1.38741, 3.66306, 3.09836], "rotation": [2.22264, -58.48308, 10.5621], "uv": [28, 19]}, + {"origin": [-0.18688, 3.15891, 2.53294], "size": [3, 1, 2], "inflate": -0.2, "pivot": [1.38741, 3.66306, 3.09836], "rotation": [1.22861, -18.99823, 12.05711], "uv": [28, 27]} + ] + }, + { + "name": "gSackRight", + "parent": "gLowerBody", + "pivot": [-1.38741, 3.66306, 3.09836], + "cubes": [ + {"origin": [-2.81312, 3.15891, 2.53294], "size": [3, 1, 2], "inflate": -0.2, "pivot": [-1.38741, 3.66306, 3.09836], "rotation": [1.22861, 18.99823, -12.05711], "uv": [28, 27]}, + {"origin": [-3.01285, 3.10867, 2.1041], "size": [3, 1, 2], "inflate": -0.1, "pivot": [-1.38741, 3.66306, 3.09836], "rotation": [2.55101, 34.39062, -9.17266], "uv": [28, 23]}, + {"origin": [-2.60486, 3.1672, 1.46743], "size": [3, 1, 2], "inflate": -0.2, "pivot": [-1.38741, 3.66306, 3.09836], "rotation": [2.22264, 58.48308, -10.5621], "uv": [28, 19]} + ] + }, + { + "name": "gTail1", + "parent": "gLowerBody", + "pivot": [0, 4.22433, 3.10657], + "cubes": [ + {"origin": [-1, 3.22433, 2.50657], "size": [2, 2, 3], "inflate": -0.46, "uv": [28, 2]} + ] + }, + { + "name": "gTail2", + "parent": "gTail1", + "pivot": [0, 4.22433, 4.70657], + "cubes": [ + {"origin": [-1, 3.22433, 4.10657], "size": [2, 2, 3], "inflate": -0.49, "uv": [28, 2]} + ] + }, + { + "name": "gTail3", + "parent": "gTail2", + "pivot": [0, 4.22433, 6.30657], + "cubes": [ + {"origin": [-1, 3.22433, 5.60657], "size": [2, 2, 3], "inflate": -0.52, "uv": [28, 2]} + ] + }, + { + "name": "gTail4", + "parent": "gTail3", + "pivot": [0, 4.22433, 7.80657], + "cubes": [ + {"origin": [-1, 3.22433, 7.10657], "size": [2, 2, 3], "inflate": -0.55, "uv": [28, 2]} + ] + }, + { + "name": "gTail5", + "parent": "gTail4", + "pivot": [0, 4.22433, 9.30657], + "cubes": [ + {"origin": [-1, 3.22433, 8.40657], "size": [2, 2, 4], "inflate": -0.58, "uv": [27, 8]} + ] + }, + { + "name": "gTail6", + "parent": "gTail5", + "pivot": [0, 4.22433, 11.50657], + "cubes": [ + {"origin": [-1, 3.22433, 10.80657], "size": [2, 2, 4], "inflate": -0.61, "uv": [27, 8]} + ] + }, + { + "name": "gTail7", + "parent": "gTail6", + "pivot": [0, 4.22433, 14.10657], + "cubes": [ + {"origin": [-1, 3.22433, 13.00657], "size": [2, 2, 4], "inflate": -0.64, "uv": [27, 8]} + ] + }, + { + "name": "gTail8", + "parent": "gTail7", + "pivot": [0, 4.22433, 16.10657], + "cubes": [ + {"origin": [-1, 3.22433, 15.30657], "size": [2, 2, 4], "inflate": -0.67, "uv": [27, 8]} + ] + }, + { + "name": "gTail9", + "parent": "gTail8", + "pivot": [0, 4.22433, 18.30657], + "cubes": [ + {"origin": [-1, 3.22433, 17.50657], "size": [2, 2, 4], "inflate": -0.7, "uv": [27, 8]} + ] + }, + { + "name": "gTail10", + "parent": "gTail9", + "pivot": [0, 4.22433, 20.50657], + "cubes": [ + {"origin": [-1, 3.22433, 19.60657], "size": [2, 2, 4], "inflate": -0.73, "uv": [27, 8]} + ] + }, + { + "name": "gTail11", + "parent": "gTail10", + "pivot": [0, 4.22433, 22.60657], + "cubes": [ + {"origin": [-1, 3.22433, 21.70657], "size": [2, 2, 4], "inflate": -0.76, "uv": [27, 8]} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/textures/entity/facehugger.png b/common/src/main/resources/assets/azurelib/textures/entity/facehugger.png new file mode 100644 index 0000000000000000000000000000000000000000..edb0ae86beabcc3b97b1af96963f2d4e6d32f997 GIT binary patch literal 3201 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 literal 0 HcmV?d00001 diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index 1220a670b..cc215f65f 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -1,6 +1,7 @@ package mod.azure.azurelib.fabric; import com.mojang.blaze3d.platform.InputConstants; +import mod.azure.azurelib.fabric.core2.example.FacehuggerRenderer; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; @@ -63,5 +64,6 @@ public void onInitializeClient() { ClientPlayNetworking.registerGlobalReceiver(SendConfigDataPacket.TYPE, (packet, context) -> packet.handle()); EntityRendererRegistry.register(ExampleEntityTypes.DRONE, DroneRenderer::new); + EntityRendererRegistry.register(ExampleEntityTypes.FACEHUGGER, FacehuggerRenderer::new); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java index d9205ed5e..a7c10ec0b 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java @@ -16,6 +16,11 @@ public class ExampleEntityTypes { EntityType.Builder.of(Drone::new, MobCategory.MONSTER).sized(0.8f, 1.98f) ); + public static final EntityType FACEHUGGER = register( + "facehugger", + EntityType.Builder.of(Facehugger::new, MobCategory.MONSTER).sized(0.75f, 0.25f) + ); + private static EntityType register(String name, EntityType.Builder builder) { var entityType = builder.build(name); var resourceLocation = AzureLib.modResource(name); @@ -25,5 +30,6 @@ private static EntityType register(String name, EntityType public static void initialize() { FabricDefaultAttributeRegistry.register(DRONE, Drone.createMonsterAttributes()); + FabricDefaultAttributeRegistry.register(FACEHUGGER, Facehugger.createMonsterAttributes()); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java new file mode 100644 index 000000000..71ec7afcb --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java @@ -0,0 +1,24 @@ +package mod.azure.azurelib.fabric.core2.example; + +import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.level.Level; + +public class Facehugger extends Monster { + + private final AzAnimationDispatcher animationDispatcher; + + public Facehugger(EntityType entityType, Level level) { + super(entityType, level); + this.animationDispatcher = new AzAnimationDispatcher<>(this); + } + + public void tick() { + super.tick(); + + if (this.level().isClientSide) { + animationDispatcher.dispatchFromClient("base_controller", "animation.run"); + } + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java new file mode 100644 index 000000000..8d0d72291 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java @@ -0,0 +1,31 @@ +package mod.azure.azurelib.fabric.core2.example; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +public class FacehuggerAnimator extends AzEntityAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource("animations/entity/facehugger.animation.json"); + + private static final String IDLE_ANIMATION_NAME = "animation.run"; + + private static final AzRawAnimation IDLE_ANIMATION = AzRawAnimation.begin().thenLoop(IDLE_ANIMATION_NAME); + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + new AzAnimationController<>(this, "base_controller", 0) + .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(Facehugger facehugger) { + return ANIMATIONS; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java new file mode 100644 index 000000000..312e6d765 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java @@ -0,0 +1,35 @@ +package mod.azure.azurelib.fabric.core2.example; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class FacehuggerRenderer extends AzEntityRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/entity/facehugger.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/facehugger.png"); + + public FacehuggerRenderer(EntityRendererProvider.Context context) { + super(context); + } + + @Override + protected @Nullable AzEntityAnimator createAnimator() { + return new FacehuggerAnimator(); + } + + @Override + protected @NotNull ResourceLocation getModelLocation(Facehugger facehugger) { + return MODEL; + } + + @Override + public @NotNull ResourceLocation getTextureLocation(@NotNull Facehugger facehugger) { + return TEXTURE; + } +} From efd74ad4ac9564a6ae1af80f41cd84b0b4219b74 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:21:36 -0500 Subject: [PATCH 042/224] Add Doom Hunter Example --- .../entity/doomhunter.animation.json | 2917 +++++++++++++++++ .../azurelib/geo/entity/doomhunter.geo.json | 1295 ++++++++ .../azurelib/textures/entity/doomhunter.png | Bin 0 -> 387006 bytes .../textures/entity/doomhunter.png.mcmeta | 15 + .../azure/azurelib/fabric/ClientListener.java | 2 + .../core2/example/ExampleEntityTypes.java | 7 + .../core2/example/azure/DoomHunter.java | 61 + .../example/azure/DoomHunterAnimator.java | 36 + .../example/azure/DoomHunterRenderer.java | 35 + 9 files changed, 4368 insertions(+) create mode 100644 common/src/main/resources/assets/azurelib/animations/entity/doomhunter.animation.json create mode 100644 common/src/main/resources/assets/azurelib/geo/entity/doomhunter.geo.json create mode 100644 common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png create mode 100644 common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png.mcmeta create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterRenderer.java diff --git a/common/src/main/resources/assets/azurelib/animations/entity/doomhunter.animation.json b/common/src/main/resources/assets/azurelib/animations/entity/doomhunter.animation.json new file mode 100644 index 000000000..69b6c2c9a --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/entity/doomhunter.animation.json @@ -0,0 +1,2917 @@ +{ + "format_version": "1.8.0", + "animations": { + "idle": { + "loop": true, + "animation_length": 1.76, + "bones": { + "body": { + "rotation": { + "0.0": { + "vector": [0, 0, 2.5] + }, + "0.72": { + "vector": [0, 0, -2.5] + }, + "1.04": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, 2.5] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [-0.38, 1, 0] + }, + "0.24": { + "vector": [-2.77, 2, 0] + }, + "0.36": { + "vector": [-4.88, 1, 0] + }, + "0.48": { + "vector": [-5, 0, 0] + }, + "0.6": { + "vector": [-3.88, -2.5, 0] + }, + "0.72": { + "vector": [-2.77, -3, 0] + }, + "0.88": { + "vector": [-0.77, -0.5, 0] + }, + "1.04": { + "vector": [3.23, 2, 0] + }, + "1.16": { + "vector": [4.11, 2, 0] + }, + "1.28": { + "vector": [5, 0, 0] + }, + "1.4": { + "vector": [4.89, -1.5, 0] + }, + "1.52": { + "vector": [2.77, -3, 0] + }, + "1.64": { + "vector": [1.39, -2.5, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "lowJaw": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.48": { + "vector": [12.5, 0, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0] + }, + "0.48": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, -0.25, 0] + } + } + }, + "rShoulder": { + "rotation": { + "0.0": { + "vector": [0, 10, 30] + }, + "0.52": { + "vector": [-2.18558, 9.76061, 17.31336] + }, + "1.4": { + "vector": [-0.19637, 9.94863, 28.85482] + }, + "1.76": { + "vector": [0, 10, 30] + } + } + }, + "lArm1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.48": { + "vector": [0, 0, -5] + }, + "1.28": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "propulsion1": { + "rotation": { + "0.0": { + "vector": [0, 0, -5] + }, + "0.24": { + "vector": [0, 0, -5] + }, + "0.72": { + "vector": [0, 0, 0] + }, + "1.04": { + "vector": [0, 0, 5] + }, + "1.52": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, -5] + } + } + }, + "propulsion2": { + "rotation": { + "0.0": { + "vector": [0, 0, -5] + }, + "0.24": { + "vector": [0, 0, -5] + }, + "0.72": { + "vector": [0, 0, 0] + }, + "1.04": { + "vector": [0, 0, 5] + }, + "1.52": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, -5] + } + } + }, + "propulsion3": { + "rotation": { + "0.0": { + "vector": [0, 0, -5] + }, + "0.24": { + "vector": [0, 0, -5] + }, + "0.72": { + "vector": [0, 0, -5] + }, + "1.04": { + "vector": [0, 0, 0] + }, + "1.52": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, -5] + } + } + }, + "propulsion4": { + "rotation": { + "0.0": { + "vector": [0, 0, -5] + }, + "0.24": { + "vector": [0, 0, -5] + }, + "0.72": { + "vector": [0, 0, -5] + }, + "1.04": { + "vector": [0, 0, 0] + }, + "1.52": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, -5] + } + } + }, + "chest": { + "rotation": { + "vector": [12.5, 0, 0] + }, + "position": { + "vector": [0, 0, -3] + } + }, + "head": { + "rotation": { + "0.0": { + "vector": [0, 0, 2.5] + }, + "0.48": { + "vector": [0, 0, -2.5] + }, + "1.28": { + "vector": [0, 0, 2.5] + } + } + }, + "rArm1": { + "rotation": { + "0.0": { + "vector": [0, 0, -7.5] + }, + "0.48": { + "vector": [0, 0, -7.5] + }, + "1.28": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, -7.5] + } + } + }, + "rArm2": { + "rotation": { + "0.0": { + "vector": [-25, 0, 0] + }, + "0.48": { + "vector": [-24.89078, -3.53329, -3.54002] + }, + "1.28": { + "vector": [-25, 0, 0] + }, + "1.76": { + "vector": [-25, 0, 0] + } + } + }, + "bone8": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.48": { + "vector": [1, 0, 0] + }, + "1.28": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [0, 0, -12.5] + }, + "0.72": { + "vector": [0, 0, 12.5] + }, + "1.04": { + "vector": [0, 0, 7.5] + }, + "1.76": { + "vector": [0, 0, -12.5] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [-0.38, 1, 0] + }, + "0.24": { + "vector": [-2.77, 2, 0] + }, + "0.36": { + "vector": [-4.88, 1, 0] + }, + "0.48": { + "vector": [-5, 0, 0] + }, + "0.6": { + "vector": [-3.88, -2.5, 0] + }, + "0.72": { + "vector": [-2.77, -3, 0] + }, + "0.88": { + "vector": [-0.77, -0.5, 0] + }, + "1.04": { + "vector": [3.23, 2, 0] + }, + "1.16": { + "vector": [4.11, 2, 0] + }, + "1.28": { + "vector": [5, 0, 0] + }, + "1.4": { + "vector": [4.89, -1.5, 0] + }, + "1.52": { + "vector": [2.77, -3, 0] + }, + "1.64": { + "vector": [1.39, -2.5, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "lGun": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.48": { + "vector": [0, -2.5, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "rGun2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.48": { + "vector": [0, 0, 0] + }, + "1.04": { + "vector": [0, 2.5, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "base": { + "position": { + "0.0": { + "vector": [-2, 0, 0] + }, + "0.84": { + "vector": [2, 0, 0] + }, + "1.76": { + "vector": [-2, 0, 0] + } + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25] + }, + "0.08": { + "vector": [-2, 0, 1.25] + }, + "0.12": { + "vector": [-0.5, 0, 1.25] + }, + "0.16": { + "vector": [0, 0, -0.75] + }, + "0.2": { + "vector": [0, 0, 1.25] + }, + "0.24": { + "vector": [-2, 0, 1.25] + }, + "0.28": { + "vector": [-0.5, 0, 1.25] + }, + "0.32": { + "vector": [0, 0, -0.75] + }, + "0.36": { + "vector": [0, 0, 1.25] + }, + "0.4": { + "vector": [-2, 0, 1.25] + }, + "0.44": { + "vector": [-0.5, 0, 1.25] + }, + "0.48": { + "vector": [0, 0, -0.75] + }, + "0.52": { + "vector": [0, 0, 1.25] + }, + "0.56": { + "vector": [-2, 0, 1.25] + }, + "0.6": { + "vector": [-0.5, 0, 1.25] + }, + "0.64": { + "vector": [0, 0, -0.75] + }, + "0.68": { + "vector": [0, 0, 1.25] + }, + "0.72": { + "vector": [-2, 0, 1.25] + }, + "0.76": { + "vector": [-0.5, 0, 1.25] + }, + "0.8": { + "vector": [0, 0, -0.75] + }, + "0.84": { + "vector": [0, 0, 1.25] + }, + "0.88": { + "vector": [-2, 0, 1.25] + }, + "0.92": { + "vector": [-0.5, 0, 1.25] + }, + "0.96": { + "vector": [0, 0, -0.75] + }, + "1.0": { + "vector": [0, 0, 1.25] + }, + "1.04": { + "vector": [-2, 0, 1.25] + }, + "1.08": { + "vector": [-0.5, 0, 1.25] + }, + "1.12": { + "vector": [0, 0, -0.75] + }, + "1.16": { + "vector": [0, 0, 1.25] + }, + "1.2": { + "vector": [-2, 0, 1.25] + }, + "1.24": { + "vector": [-0.5, 0, 1.25] + }, + "1.28": { + "vector": [0, 0, -0.75] + }, + "1.32": { + "vector": [0, 0, 1.25] + }, + "1.36": { + "vector": [-2, 0, 1.25] + }, + "1.4": { + "vector": [-0.5, 0, 1.25] + }, + "1.44": { + "vector": [0, 0, -0.75] + }, + "1.48": { + "vector": [0, 0, 1.25] + }, + "1.52": { + "vector": [-2, 0, 1.25] + }, + "1.56": { + "vector": [-0.5, 0, 1.25] + }, + "1.6": { + "vector": [0, 0, -0.75] + }, + "1.64": { + "vector": [0, 0, 1.25] + }, + "1.68": { + "vector": [-2, 0, 1.25] + }, + "1.72": { + "vector": [-0.5, 0, 1.25] + }, + "1.76": { + "vector": [0, 0, -0.75] + } + } + }, + "lShoulder": { + "rotation": { + "vector": [0, 0, 0] + } + } + } + }, + "walking": { + "loop": true, + "animation_length": 1.8, + "bones": { + "base": { + "rotation": { + "0.0": { + "vector": [5.00474, -2.49048, -0.21803] + }, + "0.44": { + "vector": [5.04292, -7.4713, -0.6574] + }, + "0.96": { + "vector": [5.00474, 2.49048, 0.21803] + }, + "1.48": { + "vector": [5.019, 4.98093, 0.43688] + }, + "1.8": { + "vector": [5.00474, -2.49048, -0.21803] + } + }, + "position": { + "0.0": { + "vector": [0, 4, 2.5] + }, + "0.08": { + "vector": [0, 5.41, 1.84] + }, + "0.2": { + "vector": [0, 6, 0] + }, + "0.32": { + "vector": [0, 5.16, -2.34] + }, + "0.44": { + "vector": [1, 4, -4] + }, + "0.56": { + "vector": [0, 2.91, -2.16] + }, + "0.68": { + "vector": [0, 2.25, 0] + }, + "0.8": { + "vector": [0, 2.84, 1.84] + }, + "0.92": { + "vector": [0, 4, 2.5] + }, + "1.0": { + "vector": [0, 5.41, 1.84] + }, + "1.12": { + "vector": [0, 6, 0] + }, + "1.24": { + "vector": [0, 5.16, -2.34] + }, + "1.36": { + "vector": [0, 4, -4] + }, + "1.48": { + "vector": [-1, 2.91, -2.16] + }, + "1.6": { + "vector": [0, 2.25, 0] + }, + "1.72": { + "vector": [0, 2.84, 1.84] + }, + "1.8": { + "vector": [0, 4, 2.5] + } + } + }, + "body": { + "rotation": { + "vector": [20, 0, 0] + }, + "position": { + "vector": [0, -1, 3] + } + }, + "lowJaw": { + "rotation": { + "0.0": { + "vector": [12.5, 0, 0] + }, + "0.88": { + "vector": [0, 0, 0] + }, + "1.8": { + "vector": [12.5, 0, 0] + } + } + }, + "rShoulder": { + "rotation": { + "0.0": { + "vector": [35, 0, 27.5] + }, + "0.28": { + "vector": [27.5, 0, 27.5] + }, + "0.64": { + "vector": [2.48637, 0.64686, 25.08508] + }, + "1.0": { + "vector": [20, 0, 27.5] + }, + "1.32": { + "vector": [32.5, 0, 27.5] + }, + "1.8": { + "vector": [35, 0, 27.5] + } + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25] + }, + "0.08": { + "vector": [-2, 0, 1.25] + }, + "0.12": { + "vector": [-0.5, 0, 1.25] + }, + "0.16": { + "vector": [0, 0, -0.75] + }, + "0.2": { + "vector": [0, 0, 1.25] + }, + "0.24": { + "vector": [-2, 0, 1.25] + }, + "0.28": { + "vector": [-0.5, 0, 1.25] + }, + "0.32": { + "vector": [0, 0, -0.75] + }, + "0.36": { + "vector": [0, 0, 1.25] + }, + "0.4": { + "vector": [-2, 0, 1.25] + }, + "0.44": { + "vector": [-0.5, 0, 1.25] + }, + "0.48": { + "vector": [0, 0, -0.75] + }, + "0.52": { + "vector": [0, 0, 1.25] + }, + "0.56": { + "vector": [-2, 0, 1.25] + }, + "0.6": { + "vector": [-0.5, 0, 1.25] + }, + "0.64": { + "vector": [0, 0, -0.75] + }, + "0.68": { + "vector": [0, 0, 1.25] + }, + "0.72": { + "vector": [-2, 0, 1.25] + }, + "0.76": { + "vector": [-0.5, 0, 1.25] + }, + "0.8": { + "vector": [0, 0, -0.75] + }, + "0.84": { + "vector": [0, 0, 1.25] + }, + "0.88": { + "vector": [-2, 0, 1.25] + }, + "0.92": { + "vector": [-0.5, 0, 1.25] + }, + "0.96": { + "vector": [0, 0, -0.75] + }, + "1.0": { + "vector": [0, 0, 1.25] + }, + "1.04": { + "vector": [-2, 0, 1.25] + }, + "1.08": { + "vector": [-0.5, 0, 1.25] + }, + "1.12": { + "vector": [0, 0, -0.75] + }, + "1.16": { + "vector": [0, 0, 1.25] + }, + "1.2": { + "vector": [-2, 0, 1.25] + }, + "1.24": { + "vector": [-0.5, 0, 1.25] + }, + "1.28": { + "vector": [0, 0, -0.75] + }, + "1.32": { + "vector": [0, 0, 1.25] + }, + "1.36": { + "vector": [-2, 0, 1.25] + }, + "1.4": { + "vector": [-0.5, 0, 1.25] + }, + "1.44": { + "vector": [0, 0, -0.75] + }, + "1.48": { + "vector": [0, 0, 1.25] + }, + "1.52": { + "vector": [-2, 0, 1.25] + }, + "1.56": { + "vector": [-0.5, 0, 1.25] + }, + "1.6": { + "vector": [0, 0, -0.75] + }, + "1.64": { + "vector": [0, 0, 1.25] + }, + "1.68": { + "vector": [-2, 0, 1.25] + }, + "1.72": { + "vector": [-0.5, 0, 1.25] + }, + "1.76": { + "vector": [0, 0, -0.75] + } + } + }, + "lArm1": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "propulsion1": { + "rotation": { + "0.0": { + "vector": [15, 0, 0] + }, + "0.28": { + "vector": [10, 0, 0] + }, + "0.56": { + "vector": [-2.5, 0, 0] + }, + "0.88": { + "vector": [15, 0, 0] + }, + "1.24": { + "vector": [10, 0, 0] + }, + "1.52": { + "vector": [-2.5, 0, 0] + }, + "1.8": { + "vector": [15, 0, 0] + } + } + }, + "propulsion2": { + "rotation": { + "0.0": { + "vector": [15, 0, 0] + }, + "0.28": { + "vector": [15, 0, 0] + }, + "0.56": { + "vector": [-5, 0, 0] + }, + "0.88": { + "vector": [15, 0, 0] + }, + "1.24": { + "vector": [15, 0, 0] + }, + "1.52": { + "vector": [-5, 0, 0] + }, + "1.8": { + "vector": [15, 0, 0] + } + } + }, + "propulsion3": { + "rotation": { + "0.0": { + "vector": [20, 0, 0] + }, + "0.28": { + "vector": [19.75778, 4.81281, -5.7589] + }, + "0.56": { + "vector": [19.97314, 1.60667, -1.91561] + }, + "0.88": { + "vector": [20, 0, 0] + }, + "1.24": { + "vector": [19.89247, -3.21154, 3.83424] + }, + "1.52": { + "vector": [19.97314, -1.60667, 1.91561] + }, + "1.8": { + "vector": [20, 0, 0] + } + } + }, + "propulsion4": { + "rotation": { + "0.0": { + "vector": [20, 0, 0] + }, + "0.28": { + "vector": [19.89247, 3.21154, -3.83424] + }, + "0.56": { + "vector": [19.97314, 1.60667, -1.91561] + }, + "0.88": { + "vector": [20, 0, 0] + }, + "1.24": { + "vector": [19.75778, -4.81281, 5.7589] + }, + "1.52": { + "vector": [19.97314, -1.60667, 1.91561] + }, + "1.8": { + "vector": [20, 0, 0] + } + } + }, + "chest": { + "rotation": { + "0.0": { + "vector": [-15, 0, 0] + }, + "0.56": { + "vector": [-15.34721, -12.06754, 3.28396] + }, + "1.52": { + "vector": [-15.22074, 9.65594, -2.61298] + }, + "1.8": { + "vector": [-15, 0, 0] + } + }, + "position": { + "vector": [0, -1, 1] + } + }, + "neck": { + "rotation": { + "vector": [-2.5, 0, 0] + } + }, + "head": { + "rotation": { + "0.0": { + "vector": [-2.50238, -2.49762, 0.10912] + }, + "0.56": { + "vector": [-2.5, 0, 0] + }, + "1.04": { + "vector": [-2.50238, -2.49762, 0.10912] + }, + "1.52": { + "vector": [-2.50954, -4.99523, 0.21865] + }, + "1.8": { + "vector": [-2.50238, -2.49762, 0.10912] + } + } + }, + "bone8": { + "rotation": { + "0.0": { + "vector": [0.5, 0, 0] + }, + "0.28": { + "vector": [0, 0, 0] + }, + "0.56": { + "vector": [0.5, 0, 0] + }, + "0.88": { + "vector": [0, 0, 0] + }, + "1.56": { + "vector": [0, 0, 0] + }, + "1.8": { + "vector": [0.5, 0, 0] + } + } + }, + "lShoulder": { + "rotation": { + "0.0": { + "vector": [25.01229, 7.69749, -4.68915] + }, + "0.44": { + "vector": [24.81197, 3.1622, -6.80423] + }, + "1.0": { + "vector": [25.01229, 7.69749, -4.68915] + }, + "1.48": { + "vector": [24.81197, 3.1622, -6.80423] + }, + "1.8": { + "vector": [25.01229, 7.69749, -4.68915] + } + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [15, 0, 0] + }, + "0.56": { + "vector": [20.01754, 2.34914, 0.85553] + }, + "0.92": { + "vector": [15.04507, -1.3275, -0.48507] + }, + "1.48": { + "vector": [20.07031, -4.69776, -1.71394] + }, + "1.8": { + "vector": [15, 0, 0] + } + } + } + } + }, + "flamethrower": { + "loop": true, + "animation_length": 1.76, + "bones": { + "rShoulder": { + "rotation": { + "0.0": { + "vector": [-10.32304, 44.70786, 22.04742] + }, + "0.88": { + "vector": [-31.90332, 23.29728, -10.1545] + }, + "1.76": { + "vector": [-10.32304, 44.70786, 22.04742] + } + } + }, + "base": { + "rotation": { + "vector": [0, -7.5, 0] + }, + "position": { + "0.0": { + "vector": [0, 0, 2] + }, + "0.04": { + "vector": [0, 0.05, 2.3] + }, + "0.24": { + "vector": [0, 0.47, 2.46] + }, + "0.52": { + "vector": [0, 1, 1] + }, + "1.04": { + "vector": [0, 0.67, -2] + }, + "1.76": { + "vector": [0, 0, 2] + } + } + }, + "chest": { + "rotation": { + "0.0": { + "vector": [0, -17.5, 0] + }, + "0.52": { + "vector": [0, -30, 0] + }, + "1.08": { + "vector": [0, -20, 0] + }, + "1.56": { + "vector": [0, -15, 0] + }, + "1.76": { + "vector": [0, -17.5, 0] + } + }, + "position": { + "vector": [-3, 0, -3.25] + } + }, + "head": { + "rotation": { + "vector": [0, 20, 0] + }, + "position": { + "vector": [1, 0, 0] + } + }, + "lShoulder": { + "rotation": { + "vector": [25, -5, 0] + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25] + }, + "0.08": { + "vector": [-2, 0, 1.25] + }, + "0.12": { + "vector": [-0.5, 0, 1.25] + }, + "0.16": { + "vector": [0, 0, -0.75] + }, + "0.2": { + "vector": [0, 0, 1.25] + }, + "0.24": { + "vector": [-2, 0, 1.25] + }, + "0.28": { + "vector": [-0.5, 0, 1.25] + }, + "0.32": { + "vector": [0, 0, -0.75] + }, + "0.36": { + "vector": [0, 0, 1.25] + }, + "0.4": { + "vector": [-2, 0, 1.25] + }, + "0.44": { + "vector": [-0.5, 0, 1.25] + }, + "0.48": { + "vector": [0, 0, -0.75] + }, + "0.52": { + "vector": [0, 0, 1.25] + }, + "0.56": { + "vector": [-2, 0, 1.25] + }, + "0.6": { + "vector": [-0.5, 0, 1.25] + }, + "0.64": { + "vector": [0, 0, -0.75] + }, + "0.68": { + "vector": [0, 0, 1.25] + }, + "0.72": { + "vector": [-2, 0, 1.25] + }, + "0.76": { + "vector": [-0.5, 0, 1.25] + }, + "0.8": { + "vector": [0, 0, -0.75] + }, + "0.84": { + "vector": [0, 0, 1.25] + }, + "0.88": { + "vector": [-2, 0, 1.25] + }, + "0.92": { + "vector": [-0.5, 0, 1.25] + }, + "0.96": { + "vector": [0, 0, -0.75] + }, + "1.0": { + "vector": [0, 0, 1.25] + }, + "1.04": { + "vector": [-2, 0, 1.25] + }, + "1.08": { + "vector": [-0.5, 0, 1.25] + }, + "1.12": { + "vector": [0, 0, -0.75] + }, + "1.16": { + "vector": [0, 0, 1.25] + }, + "1.2": { + "vector": [-2, 0, 1.25] + }, + "1.24": { + "vector": [-0.5, 0, 1.25] + }, + "1.28": { + "vector": [0, 0, -0.75] + }, + "1.32": { + "vector": [0, 0, 1.25] + }, + "1.36": { + "vector": [-2, 0, 1.25] + }, + "1.4": { + "vector": [-0.5, 0, 1.25] + }, + "1.44": { + "vector": [0, 0, -0.75] + }, + "1.48": { + "vector": [0, 0, 1.25] + }, + "1.52": { + "vector": [-2, 0, 1.25] + }, + "1.56": { + "vector": [-0.5, 0, 1.25] + }, + "1.6": { + "vector": [0, 0, -0.75] + }, + "1.64": { + "vector": [0, 0, 1.25] + }, + "1.68": { + "vector": [-2, 0, 1.25] + }, + "1.72": { + "vector": [-0.5, 0, 1.25] + }, + "1.76": { + "vector": [0, 0, -0.75] + } + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [-12.48848, 0.54094, 9.94081] + }, + "1.04": { + "vector": [-23.63948, 2.83053, 8.93777] + }, + "1.76": { + "vector": [-12.48848, 0.54094, 9.94081] + } + }, + "position": { + "vector": [0, 1, 0] + } + }, + "lowJaw": { + "position": { + "vector": [0, -2, 0] + } + }, + "rArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, 5] + }, + "0.4": { + "vector": [0, 0, 0] + }, + "0.84": { + "vector": [4.81096, -6.97913, -7.21254] + }, + "1.32": { + "vector": [5.02885, -7.50642, -9.51579] + }, + "1.6": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, 5] + } + } + }, + "trigger": { + "rotation": { + "0.0": { + "vector": [-10, 0, 0] + }, + "0.56": { + "vector": [-13.5, 0, 0] + }, + "0.76": { + "vector": [-14.82, 0, 0] + }, + "0.88": { + "vector": [-15.57, 0, 0] + }, + "1.12": { + "vector": [-16.75, 0, 0] + }, + "1.28": { + "vector": [-17.75, 0, 0] + }, + "1.76": { + "vector": [-9.75, 0, 0] + } + } + }, + "bone7": { + "rotation": { + "0.0": { + "vector": [-5, 0, 0] + }, + "0.36": { + "vector": [-6.12, 0, 0] + }, + "0.8": { + "vector": [-7.5, 0, 0] + }, + "1.28": { + "vector": [-8.75, 0, 0] + }, + "1.76": { + "vector": [-5, 0, 0] + } + } + }, + "bigGun": { + "rotation": { + "0.0": { + "vector": [0, 0, 0.5] + }, + "0.04": { + "vector": [0, 0, -0.25] + }, + "0.08": { + "vector": [-0.75, 0, -0.25] + }, + "0.12": { + "vector": [0, 0, -0.25] + }, + "0.16": { + "vector": [0, 0, 0.5] + }, + "0.2": { + "vector": [0, 0, -0.25] + }, + "0.24": { + "vector": [-0.75, 0, -0.25] + }, + "0.28": { + "vector": [0, 0, -0.25] + }, + "0.32": { + "vector": [0, 0, 0.5] + }, + "0.36": { + "vector": [0, 0, -0.25] + }, + "0.4": { + "vector": [-0.75, 0, -0.25] + }, + "0.44": { + "vector": [0, 0, -0.25] + }, + "0.48": { + "vector": [0, 0, 0.5] + }, + "0.52": { + "vector": [0, 0, -0.25] + }, + "0.56": { + "vector": [-0.75, 0, -0.25] + }, + "0.6": { + "vector": [0, 0, -0.25] + }, + "0.64": { + "vector": [0, 0, 0.5] + }, + "0.68": { + "vector": [0, 0, -0.25] + }, + "0.72": { + "vector": [-0.75, 0, -0.25] + }, + "0.76": { + "vector": [0, 0, -0.25] + }, + "0.8": { + "vector": [0, 0, 0.5] + }, + "0.84": { + "vector": [0, 0, -0.25] + }, + "0.88": { + "vector": [-0.75, 0, -0.25] + }, + "0.92": { + "vector": [0, 0, -0.25] + }, + "0.96": { + "vector": [0, 0, 0.5] + }, + "1.0": { + "vector": [0, 0, -0.25] + }, + "1.04": { + "vector": [-0.75, 0, -0.25] + }, + "1.08": { + "vector": [0, 0, -0.25] + }, + "1.12": { + "vector": [0, 0, 0.5] + }, + "1.16": { + "vector": [0, 0, -0.25] + }, + "1.2": { + "vector": [-0.75, 0, -0.25] + }, + "1.24": { + "vector": [0, 0, -0.25] + }, + "1.28": { + "vector": [0, 0, 0.5] + }, + "1.32": { + "vector": [0, 0, -0.25] + }, + "1.36": { + "vector": [-0.75, 0, -0.25] + }, + "1.4": { + "vector": [0, 0, -0.25] + }, + "1.44": { + "vector": [0, 0, 0.5] + }, + "1.48": { + "vector": [0, 0, -0.25] + }, + "1.52": { + "vector": [-0.75, 0, -0.25] + }, + "1.56": { + "vector": [0, 0, -0.25] + }, + "1.6": { + "vector": [0, 0, 0.5] + }, + "1.64": { + "vector": [0, 0, -0.25] + }, + "1.68": { + "vector": [-0.75, 0, -0.25] + }, + "1.72": { + "vector": [0, 0, -0.25] + } + } + }, + "propulsion1": { + "rotation": { + "0.0": { + "vector": [60, 0, 0] + }, + "0.6": { + "vector": [17.5, 0, 0] + }, + "0.88": { + "vector": [18.83, 0, 0] + }, + "1.16": { + "vector": [33.75, 0, 0] + }, + "1.48": { + "vector": [51.33, 0, 0] + }, + "1.76": { + "vector": [60, 0, 0] + } + }, + "position": { + "vector": [0, 7, 0] + } + }, + "propulsion2": { + "rotation": { + "0.0": { + "vector": [55, 0, 0] + }, + "0.6": { + "vector": [17.5, 0, 0] + }, + "1.16": { + "vector": [33.75, 0, 0] + }, + "1.76": { + "vector": [55, 0, 0] + } + }, + "position": { + "vector": [0, 7, 0] + } + }, + "propulsion3": { + "rotation": { + "vector": [12.5, 0, 0] + } + }, + "propulsion4": { + "rotation": { + "vector": [15, 0, 0] + } + } + } + }, + "chainsaw": { + "loop": true, + "animation_length": 1.76, + "bones": { + "bone": { + "scale": { + "vector": [0, 0, 0] + } + }, + "base": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.24": { + "vector": [0, -2.5, 0] + }, + "1.76": { + "vector": [0, -22.5, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 5] + }, + "0.24": { + "vector": [0, 2, -9] + }, + "0.8": { + "vector": [0, -3.18, -4.79] + }, + "1.08": { + "vector": [0, -4.27, -1.94] + }, + "1.32": { + "vector": [0, -4.46, 0.51] + }, + "1.52": { + "vector": [0, -2.93, 3.3] + }, + "1.76": { + "vector": [0, 0, 5] + } + } + }, + "body": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.36": { + "vector": [0, 5, 0] + }, + "1.36": { + "vector": [0, -10, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "chest": { + "rotation": { + "0.0": { + "vector": [10, 0, 0] + }, + "0.32": { + "vector": [11.24314, 27.0478, 5.16524] + }, + "1.76": { + "vector": [10, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, -2] + }, + "0.32": { + "vector": [0, 0, -3] + }, + "1.76": { + "vector": [0, 0, -2] + } + } + }, + "head": { + "rotation": { + "0.0": { + "vector": [-5.1972, 17.46065, -360.90906] + }, + "0.32": { + "vector": [-6.23682, -37.30758, -355.55617] + }, + "1.12": { + "vector": [-4.97617, 5.00946, -359.78134] + }, + "1.76": { + "vector": [-5.1972, 17.46065, -360.90906] + } + }, + "position": { + "0.0": { + "vector": [0, 0, -2] + }, + "0.32": { + "vector": [-2, 0, -2] + }, + "1.12": { + "vector": [-1, 0, -2] + }, + "1.76": { + "vector": [0, 0, -2] + } + } + }, + "lowJaw": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.24": { + "vector": [10, 0, 0] + }, + "1.76": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.24": { + "vector": [0, -1, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "rShoulder": { + "rotation": { + "0.0": { + "vector": [-15, 0, 17.5] + }, + "0.24": { + "vector": [36.54514, -9.06524, 29.5012] + }, + "1.76": { + "vector": [-15, 0, 17.5] + } + } + }, + "rArm2": { + "rotation": { + "vector": [2.5, -15, 0] + }, + "position": { + "vector": [-1, 0, 0] + } + }, + "lShoulder": { + "rotation": { + "0.0": { + "vector": [49.8924, -3.82821, 3.21873] + }, + "0.28": { + "vector": [-40.1076, -3.82821, 3.21873] + }, + "0.68": { + "vector": [-55.6431, 7.13136, -10.29284] + }, + "1.12": { + "vector": [-10.1076, -3.82821, 3.21873] + }, + "1.48": { + "vector": [4.8924, -3.82821, 3.21873] + }, + "1.76": { + "vector": [49.8924, -3.82821, 3.21873] + } + }, + "position": { + "0.28": { + "vector": [0, -2, 1] + }, + "0.68": { + "vector": [0, -4, -2] + }, + "1.12": { + "vector": [0, -2, 1] + }, + "1.48": { + "vector": [0, -2, 1] + } + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.08": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.12": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.16": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "0.2": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.24": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.28": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.32": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "0.36": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.4": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.44": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.48": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "0.52": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.56": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.6": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.64": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "0.68": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.72": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.76": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.8": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "0.84": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.88": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.92": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.96": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "1.0": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "1.04": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "1.08": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "1.12": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "1.16": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "1.2": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "1.24": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "1.28": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "1.32": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "1.36": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "1.4": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "1.44": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "1.48": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "1.52": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "1.56": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "1.6": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "1.64": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "1.68": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "1.72": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "1.76": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + } + } + }, + "lArm3": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [-20.39807, 11.91276, -3.81397] + }, + "0.16": { + "vector": [28.58219, 14.34511, -8.30016] + }, + "0.88": { + "vector": [-15.19432, 13.43122, -2.91042] + }, + "1.0": { + "vector": [-16.15392, 13.22416, -3.03363] + }, + "1.28": { + "vector": [-10.05966, 12.74101, -3.32112] + }, + "1.36": { + "vector": [-9.28273, 12.60297, -3.40327] + }, + "1.76": { + "vector": [-20.39807, 11.91276, -3.81397] + } + } + }, + "propulsion1": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.16": { + "vector": [-32.5, 0, 0] + }, + "0.88": { + "vector": [32.5, 0, 0] + }, + "1.28": { + "vector": [-5, 0, 0] + }, + "1.76": { + "vector": [22.5, 0, 0] + } + } + }, + "propulsion2": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.16": { + "vector": [-32.5, 0, 0] + }, + "0.88": { + "vector": [32.5, 0, 0] + }, + "1.28": { + "vector": [-5, 0, 0] + }, + "1.76": { + "vector": [22.5, 0, 0] + } + } + }, + "propulsion3": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.28": { + "vector": [22.5, 0, 0] + }, + "0.84": { + "vector": [-32.5, 0, 0] + }, + "1.36": { + "vector": [-35, 0, 0] + }, + "1.76": { + "vector": [-22.5, 0, 0] + } + } + }, + "propulsion4": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.28": { + "vector": [17.5, 0, 0] + }, + "0.84": { + "vector": [-27.5, 0, 0] + }, + "1.36": { + "vector": [-35, 0, 0] + }, + "1.76": { + "vector": [-22.5, 0, 0] + } + } + } + } + }, + "rockets": { + "loop": true, + "animation_length": 1.44, + "bones": { + "base": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [0, -7, 12] + }, + "0.56": { + "vector": [0, -9, 5.75] + }, + "0.92": { + "vector": [0, -8.5, -0.5] + }, + "1.28": { + "vector": [0, -4.36, -2.55] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [15, 0, 0] + }, + "0.32": { + "vector": [20.5, 0, 0] + }, + "0.56": { + "vector": [14.32, 0, 0] + }, + "1.08": { + "vector": [-10.34, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.2": { + "vector": [0, 0, -5] + }, + "1.36": { + "vector": [0, 0, -2.09] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "lMissleLaunch": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.16": { + "vector": [-15, 0, 0] + }, + "0.6": { + "vector": [-3, 0, 0] + }, + "0.72": { + "vector": [0, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 2, -2] + }, + "0.16": { + "vector": [0, -3, 3] + }, + "0.24": { + "vector": [0, -3, 3] + }, + "0.6": { + "vector": [0, 4, -4] + }, + "0.72": { + "vector": [0, 2, -2] + }, + "1.44": { + "vector": [0, 2, -2] + } + } + }, + "rMissleLaunch2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.16": { + "vector": [-15, 0, 0] + }, + "0.6": { + "vector": [-5.5, 0, 0] + }, + "0.72": { + "vector": [0, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 2, -2] + }, + "0.16": { + "vector": [0, -3, 3] + }, + "0.24": { + "vector": [0, -3, 3] + }, + "0.6": { + "vector": [0, 4, -4] + }, + "0.72": { + "vector": [0, 2, -2] + }, + "1.44": { + "vector": [0, 2, -2] + } + } + }, + "neck": { + "rotation": { + "vector": [-12.5, 0, 0] + }, + "position": { + "0.0": { + "vector": [0, -2, 0] + }, + "0.2": { + "vector": [0, -2, 0] + }, + "1.44": { + "vector": [0, -2, 0] + } + } + }, + "head": { + "rotation": { + "0.0": { + "vector": [27.5, 0, 0] + }, + "0.2": { + "vector": [5.7, 0, 0] + }, + "1.2": { + "vector": [30, 0, 0] + }, + "1.44": { + "vector": [27.5, 0, 0] + } + }, + "position": { + "0.2": { + "vector": [0, 1, -2] + }, + "1.2": { + "vector": [0, 1, -2.25] + } + } + }, + "lowJaw": { + "rotation": { + "vector": [10, 0, 0] + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.68": { + "vector": [0, -1, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "rArm2": { + "rotation": { + "vector": [0, 0, -2.5] + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25] + }, + "0.08": { + "vector": [-2, 0, 1.25] + }, + "0.12": { + "vector": [-0.5, 0, 1.25] + }, + "0.16": { + "vector": [0, 0, -0.75] + }, + "0.2": { + "vector": [0, 0, 1.25] + }, + "0.24": { + "vector": [-2, 0, 1.25] + }, + "0.28": { + "vector": [-0.5, 0, 1.25] + }, + "0.32": { + "vector": [0, 0, -0.75] + }, + "0.36": { + "vector": [0, 0, 1.25] + }, + "0.4": { + "vector": [-2, 0, 1.25] + }, + "0.44": { + "vector": [-0.5, 0, 1.25] + }, + "0.48": { + "vector": [0, 0, -0.75] + }, + "0.52": { + "vector": [0, 0, 1.25] + }, + "0.56": { + "vector": [-2, 0, 1.25] + }, + "0.6": { + "vector": [-0.5, 0, 1.25] + }, + "0.64": { + "vector": [0, 0, -0.75] + }, + "0.68": { + "vector": [0, 0, 1.25] + }, + "0.72": { + "vector": [-2, 0, 1.25] + }, + "0.76": { + "vector": [-0.5, 0, 1.25] + }, + "0.8": { + "vector": [0, 0, -0.75] + }, + "0.84": { + "vector": [0, 0, 1.25] + }, + "0.88": { + "vector": [-2, 0, 1.25] + }, + "0.92": { + "vector": [-0.5, 0, 1.25] + }, + "0.96": { + "vector": [0, 0, -0.75] + }, + "1.0": { + "vector": [0, 0, 1.25] + }, + "1.04": { + "vector": [-2, 0, 1.25] + }, + "1.08": { + "vector": [-0.5, 0, 1.25] + }, + "1.12": { + "vector": [0, 0, -0.75] + }, + "1.16": { + "vector": [0, 0, 1.25] + }, + "1.2": { + "vector": [-2, 0, 1.25] + }, + "1.24": { + "vector": [-0.5, 0, 1.25] + }, + "1.28": { + "vector": [0, 0, -0.75] + }, + "1.32": { + "vector": [0, 0, 1.25] + }, + "1.36": { + "vector": [-2, 0, 1.25] + }, + "1.4": { + "vector": [-0.5, 0, 1.25] + }, + "1.44": { + "vector": [0, 0, -0.75] + } + } + }, + "propulsion1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [-20, 0, 0] + }, + "0.4": { + "vector": [-25, 0, 0] + }, + "1.16": { + "vector": [10, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "propulsion2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [-20, 0, 0] + }, + "0.36": { + "vector": [-23.62, 0, 0] + }, + "1.16": { + "vector": [10, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "propulsion3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.24": { + "vector": [-20, 0, 0] + }, + "0.44": { + "vector": [-20, 0, 0] + }, + "0.84": { + "vector": [7.5, 0, 0] + }, + "1.2": { + "vector": [-17.5, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "propulsion4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.24": { + "vector": [-20, 0, 0] + }, + "0.44": { + "vector": [-20, 0, 0] + }, + "0.84": { + "vector": [7.5, 0, 0] + }, + "1.2": { + "vector": [-17.5, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "body": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.2": { + "vector": [0, 0, -5] + }, + "1.36": { + "vector": [0, 0, -2.09] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "chest": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.24": { + "vector": [20, 0, 0] + }, + "0.48": { + "vector": [-20.31, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.24": { + "vector": [0, 0, -5] + }, + "0.48": { + "vector": [0, -4, 0.63] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "rShoulder": { + "rotation": { + "0.0": { + "vector": [20, 0, 25] + }, + "0.24": { + "vector": [-12.33756, -10.68806, 28.14783] + }, + "0.52": { + "vector": [24.25098, 26.17588, 16.14687] + }, + "1.44": { + "vector": [20, 0, 25] + } + } + }, + "lShoulder": { + "rotation": { + "0.0": { + "vector": [15, 0, 0] + }, + "0.24": { + "vector": [-35.6484, 10.21235, -7.24677] + }, + "0.52": { + "vector": [5.50884, -14.30659, -1.44989] + }, + "1.44": { + "vector": [15, 0, 0] + } + } + } + } + }, + "death": { + "animation_length": 2.2, + "bones": { + "lowJaw": { + "rotation": { + "vector": [12.5, 0, 0] + }, + "position": { + "vector": [0, -0.9, 0.32] + } + }, + "body": { + "rotation": { + "1.12": { + "vector": [0, 0, 0] + }, + "1.44": { + "vector": [14.78, 0, 0] + }, + "1.56": { + "vector": [38.02, 0, 0] + }, + "1.6": { + "vector": [64.79, 0, 0] + }, + "1.64": { + "vector": [82.5, 0, 0] + } + }, + "position": { + "0.08": { + "vector": [0, -6.08, -9.31] + }, + "0.2": { + "vector": [0, -3.96, -11.5] + }, + "0.96": { + "vector": [0, 15.7, -17.08] + }, + "1.12": { + "vector": [0, -15.24, -21.15] + }, + "1.44": { + "vector": [0, -15.24, -21.15] + }, + "2.0": { + "vector": [0, -20, -46] + }, + "2.2": { + "vector": [0, -20, -46] + } + }, + "scale": { + "1.12": { + "vector": [1, 1, 1] + }, + "2.0": { + "vector": [1, 1, 1] + }, + "2.2": { + "vector": [0, 0.1, 0] + } + } + }, + "chest": { + "rotation": { + "0.36": { + "vector": [-7.5, 0, 0] + }, + "1.36": { + "vector": [-19.38, 0, 0] + }, + "1.64": { + "vector": [-10, 0, 0] + } + }, + "position": { + "0.36": { + "vector": [0, 0, 1] + }, + "1.36": { + "vector": [0, -3, 2.75] + }, + "1.64": { + "vector": [0, 0, 1] + } + } + }, + "head": { + "rotation": { + "0.96": { + "vector": [-25, 0, 0] + }, + "1.28": { + "vector": [-20.00075, 38.2555, -12.70047] + }, + "1.36": { + "vector": [-29.39567, 39.06543, -13.38968] + }, + "1.72": { + "vector": [-25.01852, 44.68059, -18.16791] + }, + "1.84": { + "vector": [16.38795, 47.80879, 37.05489] + } + }, + "position": { + "vector": [0, -3, -1] + } + }, + "rShoulder": { + "rotation": { + "0.48": { + "vector": [0, 32.5, 0] + }, + "0.96": { + "vector": [0, 32.5, 0] + }, + "1.32": { + "vector": [-4.375, 20, 0] + }, + "1.64": { + "vector": [40.30522, 0.78366, 14.98913] + }, + "1.72": { + "vector": [19.44478, -1.35296, 14.23226] + } + } + }, + "rArm1": { + "rotation": { + "vector": [20, 0, 0] + } + }, + "rArm2": { + "rotation": { + "0.24": { + "vector": [30, 0, 0] + }, + "0.72": { + "vector": [-5, 0, 0] + }, + "0.96": { + "vector": [-5, 0, 0] + }, + "1.16": { + "vector": [10, 0, 0] + } + } + }, + "lShoulder": { + "rotation": { + "0.32": { + "vector": [-87.5, 0, 0] + }, + "0.96": { + "vector": [-87.5, 0, 0] + }, + "1.32": { + "vector": [2.5, 0, 0] + }, + "1.64": { + "vector": [67.5, 0, 0] + }, + "1.72": { + "vector": [50, 0, 0] + } + }, + "position": { + "0.32": { + "vector": [0, -8, 3] + }, + "0.96": { + "vector": [0, -8, 3] + }, + "1.32": { + "vector": [0, -1, -2] + } + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [-2, 0, 1.25] + }, + "0.04": { + "vector": [-0.5, 0, 1.25] + }, + "0.08": { + "vector": [0, 0, -0.75] + }, + "0.12": { + "vector": [0, 0, 1.25] + }, + "0.16": { + "vector": [-2, 0, 1.25] + }, + "0.2": { + "vector": [-0.5, 0, 1.25] + }, + "0.24": { + "vector": [0, 0, -0.75] + }, + "0.28": { + "vector": [0, 0, 1.25] + }, + "0.32": { + "vector": [-2, 0, 1.25] + }, + "0.36": { + "vector": [-0.5, 0, 1.25] + }, + "0.4": { + "vector": [0, 0, -0.75] + }, + "0.44": { + "vector": [0, 0, 1.25] + }, + "0.48": { + "vector": [-2, 0, 1.25] + }, + "0.52": { + "vector": [-0.5, 0, 1.25] + }, + "0.56": { + "vector": [0, 0, -0.75] + }, + "0.6": { + "vector": [0, 0, 1.25] + }, + "0.64": { + "vector": [-2, 0, 1.25] + }, + "0.68": { + "vector": [-0.5, 0, 1.25] + }, + "0.72": { + "vector": [0, 0, -0.75] + }, + "0.76": { + "vector": [0, 0, 1.25] + }, + "0.8": { + "vector": [-2, 0, 1.25] + }, + "0.84": { + "vector": [-0.5, 0, 1.25] + }, + "0.88": { + "vector": [0, 0, -0.75] + } + } + }, + "sled": { + "rotation": { + "vector": [180, 0, 0] + }, + "position": { + "vector": [0, 0, 52] + }, + "scale": { + "vector": [0, 0, 1] + } + } + } + }, + "sled_death": { + "animation_length": 0.52, + "bones": { + "lowJaw": { + "rotation": { + "vector": [0, 0, 0] + }, + "position": { + "vector": [0, 0.1, 0.325] + } + }, + "body": { + "rotation": { + "vector": [0, 0, 0] + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [0, 16, -0.19] + }, + "0.24": { + "vector": [0, 12.69, -2.49] + }, + "0.32": { + "vector": [0, 5.86, -5.09] + }, + "0.52": { + "vector": [0, -3.85, -6.93] + } + }, + "scale": { + "vector": [1, 1, 1] + } + }, + "chest": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.32": { + "vector": [12.5, 0, 0] + } + }, + "position": { + "vector": [0, 0, -3] + } + }, + "head": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.4": { + "vector": [17.5, 0, 0] + } + }, + "position": { + "vector": [0, 0, -1] + } + }, + "rShoulder": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "rArm1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.28": { + "vector": [7.5, 0, 0] + } + } + }, + "rArm2": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "lShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.32": { + "vector": [15, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -1, 3] + }, + "0.32": { + "vector": [0, -1.55, 3] + } + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25] + }, + "0.08": { + "vector": [-2, 0, 1.25] + }, + "0.12": { + "vector": [-0.5, 0, 1.25] + }, + "0.16": { + "vector": [0, 0, -0.75] + }, + "0.2": { + "vector": [0, 0, 1.25] + }, + "0.24": { + "vector": [-2, 0, 1.25] + }, + "0.28": { + "vector": [-0.5, 0, 1.25] + }, + "0.32": { + "vector": [0, 0, -0.75] + }, + "0.36": { + "vector": [0, 0, 1.25] + }, + "0.4": { + "vector": [-2, 0, 1.25] + }, + "0.44": { + "vector": [-0.5, 0, 1.25] + }, + "0.48": { + "vector": [0, 0, -0.75] + }, + "0.52": { + "vector": [0, 0, 1.25] + } + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.16": { + "vector": [45, 0, 0] + }, + "0.28": { + "vector": [90, 0, 0] + }, + "0.48": { + "vector": [135, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.16": { + "vector": [0, 5.86, 9.77] + }, + "0.28": { + "vector": [0, 10, 26] + }, + "0.48": { + "vector": [0, 6.26, 40.01] + } + }, + "scale": { + "0.0": { + "vector": [1, 1, 1] + }, + "0.28": { + "vector": [1, 1, 1] + } + } + } + } + } + }, + "azurelib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/entity/doomhunter.geo.json b/common/src/main/resources/assets/azurelib/geo/entity/doomhunter.geo.json new file mode 100644 index 000000000..e537c5e1b --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/entity/doomhunter.geo.json @@ -0,0 +1,1295 @@ +{ + "format_version": "1.21.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 512, + "texture_height": 512, + "visible_bounds_width": 11, + "visible_bounds_height": 10, + "visible_bounds_offset": [0, 4, 0] + }, + "bones": [ + { + "name": "base", + "pivot": [0, 32, 0] + }, + { + "name": "body", + "parent": "base", + "pivot": [0, 16, -2], + "cubes": [ + { + "origin": [-6.5, 27.01142, -2.26147], + "size": [15, 29, 15], + "pivot": [0, 30, 5], + "rotation": [5, 0, 0], + "uv": { + "north": {"uv": [180, 183], "uv_size": [15, 29]}, + "east": {"uv": [165, 183], "uv_size": [15, 29]}, + "south": {"uv": [210, 183], "uv_size": [15, 29]}, + "west": {"uv": [195, 183], "uv_size": [15, 29]}, + "up": {"uv": [180, 168], "uv_size": [15, 15]}, + "down": {"uv": [195, 183], "uv_size": [15, -15]} + } + } + ] + }, + { + "name": "chest", + "parent": "body", + "pivot": [0, 56, 10], + "cubes": [ + { + "origin": [-14, 55.95722, -7.34737], + "size": [31, 20, 19], + "pivot": [0, 56, 8], + "rotation": [7.5, 0, 0], + "uv": { + "north": {"uv": [131, 129], "uv_size": [31, 20]}, + "east": {"uv": [112, 129], "uv_size": [19, 20]}, + "south": {"uv": [181, 129], "uv_size": [31, 20]}, + "west": {"uv": [162, 129], "uv_size": [19, 20]}, + "up": {"uv": [131, 110], "uv_size": [31, 19]}, + "down": {"uv": [162, 129], "uv_size": [31, -19]} + } + }, + { + "origin": [-12, 41, -6.5], + "size": [26, 15, 17], + "pivot": [0, 60, 7], + "rotation": [7.5, 0, 0], + "uv": { + "north": {"uv": [183, 55], "uv_size": [26, 15]}, + "east": {"uv": [166, 55], "uv_size": [17, 15]}, + "south": {"uv": [226, 55], "uv_size": [26, 15]}, + "west": {"uv": [209, 55], "uv_size": [17, 15]}, + "up": {"uv": [183, 38], "uv_size": [26, 17]}, + "down": {"uv": [209, 55], "uv_size": [26, -17]} + } + }, + { + "origin": [-15.25, 57, -11], + "size": [15, 17, 10], + "pivot": [0, 64, -7], + "rotation": [5, 7.5, 0], + "uv": { + "north": {"uv": [176, 80], "uv_size": [15, 17]}, + "east": {"uv": [166, 80], "uv_size": [10, 17]}, + "south": {"uv": [201, 80], "uv_size": [15, 17]}, + "west": {"uv": [191, 80], "uv_size": [10, 17]}, + "up": {"uv": [176, 70], "uv_size": [15, 10]}, + "down": {"uv": [191, 80], "uv_size": [15, -10]} + } + }, + { + "origin": [2.25, 57, -11.75], + "size": [16, 17, 10], + "pivot": [0, 64, -7], + "rotation": [5, -7.5, 0], + "uv": { + "north": {"uv": [220, 166], "uv_size": [16, 17]}, + "east": {"uv": [210, 166], "uv_size": [10, 17]}, + "south": {"uv": [246, 166], "uv_size": [16, 17]}, + "west": {"uv": [236, 166], "uv_size": [10, 17]}, + "up": {"uv": [220, 156], "uv_size": [16, 10]}, + "down": {"uv": [236, 166], "uv_size": [16, -10]} + } + } + ] + }, + { + "name": "neck", + "parent": "chest", + "pivot": [0, 76, 7], + "cubes": [ + { + "origin": [-5, 73.99239, -2.82569], + "size": [12, 11, 12], + "pivot": [0, 74, 7], + "rotation": [20, 0, 0], + "uv": { + "north": {"uv": [112, 195], "uv_size": [12, 11]}, + "east": {"uv": [100, 195], "uv_size": [12, 11]}, + "south": {"uv": [136, 195], "uv_size": [12, 11]}, + "west": {"uv": [124, 195], "uv_size": [12, 11]}, + "up": {"uv": [112, 183], "uv_size": [12, 12]}, + "down": {"uv": [124, 195], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "head", + "parent": "neck", + "pivot": [0.5, 84, 3], + "cubes": [ + { + "origin": [-6.5, 81, -6], + "size": [15, 13, 13], + "pivot": [0.5, 84, 3], + "rotation": [2.5, 0, 0], + "uv": { + "north": {"uv": [200, 13], "uv_size": [15, 13]}, + "east": {"uv": [187, 13], "uv_size": [13, 13]}, + "south": {"uv": [228, 13], "uv_size": [15, 13]}, + "west": {"uv": [215, 13], "uv_size": [13, 13]}, + "up": {"uv": [200, 0], "uv_size": [15, 13]}, + "down": {"uv": [215, 13], "uv_size": [15, -13]} + } + } + ] + }, + { + "name": "topJaw", + "parent": "head", + "pivot": [0.5, 85, -6], + "cubes": [ + { + "origin": [-4.5, 83, -10], + "size": [11, 4, 4], + "uv": { + "north": {"uv": [124, 49], "uv_size": [11, 4]}, + "east": {"uv": [120, 49], "uv_size": [4, 4]}, + "south": {"uv": [139, 49], "uv_size": [11, 4]}, + "west": {"uv": [135, 49], "uv_size": [4, 4]}, + "up": {"uv": [124, 45], "uv_size": [11, 4]}, + "down": {"uv": [135, 49], "uv_size": [11, -4]} + } + } + ] + }, + { + "name": "eye", + "parent": "head", + "pivot": [0.5, 89, -6], + "cubes": [ + { + "origin": [-3.5, 86, -9], + "size": [9, 6, 5], + "pivot": [0.5, 89, -6], + "rotation": [7.5, 0, 0], + "uv": { + "north": {"uv": [5, 75], "uv_size": [9, 6]}, + "east": {"uv": [0, 75], "uv_size": [5, 6]}, + "south": {"uv": [19, 75], "uv_size": [9, 6]}, + "west": {"uv": [14, 75], "uv_size": [5, 6]}, + "up": {"uv": [5, 70], "uv_size": [9, 5]}, + "down": {"uv": [14, 75], "uv_size": [9, -5]} + } + }, + { + "origin": [-0.5, 86.5, -9.5], + "size": [3, 3, 1], + "uv": { + "north": {"uv": [1, 46], "uv_size": [3, 3]}, + "east": {"uv": [0, 46], "uv_size": [1, 3]}, + "south": {"uv": [5, 46], "uv_size": [3, 3]}, + "west": {"uv": [4, 46], "uv_size": [1, 3]}, + "up": {"uv": [1, 45], "uv_size": [3, 1]}, + "down": {"uv": [4, 46], "uv_size": [3, -1]} + } + } + ] + }, + { + "name": "lowJaw", + "parent": "head", + "pivot": [0.5, 82, -3], + "cubes": [ + { + "origin": [-3.5, 80, -10], + "size": [9, 3, 4], + "uv": { + "north": {"uv": [4, 133], "uv_size": [9, 3]}, + "east": {"uv": [0, 133], "uv_size": [4, 3]}, + "south": {"uv": [17, 133], "uv_size": [9, 3]}, + "west": {"uv": [13, 133], "uv_size": [4, 3]}, + "up": {"uv": [4, 129], "uv_size": [9, 4]}, + "down": {"uv": [13, 133], "uv_size": [9, -4]} + } + } + ] + }, + { + "name": "lHorn", + "parent": "head", + "pivot": [5.6, 85.3, 1], + "rotation": [-2.38443, -0.75155, -122.48436], + "cubes": [ + { + "origin": [1.6, 77.3, -2], + "size": [6, 7, 6], + "uv": { + "north": {"uv": [134, 6], "uv_size": [6, 7]}, + "east": {"uv": [128, 6], "uv_size": [6, 7]}, + "south": {"uv": [146, 6], "uv_size": [6, 7]}, + "west": {"uv": [140, 6], "uv_size": [6, 7]}, + "up": {"uv": [134, 0], "uv_size": [6, 6]}, + "down": {"uv": [140, 6], "uv_size": [6, -6]} + } + } + ] + }, + { + "name": "bone2", + "parent": "lHorn", + "pivot": [4.6, 78.3, 1], + "rotation": [0, 0, -15], + "cubes": [ + { + "origin": [2.1, 72.3, -1.5], + "size": [5, 7, 5], + "pivot": [4.6, 78.3, 1], + "rotation": [-20, 0, -7.5], + "uv": { + "north": {"uv": [163, 165], "uv_size": [5, 6]}, + "east": {"uv": [158, 165], "uv_size": [5, 6]}, + "south": {"uv": [168, 154], "uv_size": [5, 7]}, + "west": {"uv": [168, 165], "uv_size": [5, 6]}, + "up": {"uv": [163, 160], "uv_size": [5, 5]}, + "down": {"uv": [168, 165], "uv_size": [5, -5]} + } + } + ] + }, + { + "name": "bone3", + "parent": "bone2", + "pivot": [4.6, 72.3, 1], + "cubes": [ + { + "origin": [3.6, 65.3, -3], + "size": [4, 7, 4], + "pivot": [4.6, 72.3, 1], + "rotation": [-30, 0, -22.5], + "uv": { + "north": {"uv": [154, 49], "uv_size": [4, 7]}, + "east": {"uv": [150, 49], "uv_size": [4, 7]}, + "south": {"uv": [162, 49], "uv_size": [4, 7]}, + "west": {"uv": [158, 49], "uv_size": [4, 7]}, + "up": {"uv": [154, 45], "uv_size": [4, 4]}, + "down": {"uv": [158, 49], "uv_size": [4, -4]} + } + } + ] + }, + { + "name": "bone4", + "parent": "bone3", + "pivot": [5.4, 64.3, 1.25], + "rotation": [0, 0, -17.5], + "cubes": [ + { + "origin": [7.9, 57.3, -5.5], + "size": [3, 7, 3], + "pivot": [5.4, 64.3, 1.25], + "rotation": [-22.5, 0, -27.5], + "uv": { + "north": {"uv": [29, 132], "uv_size": [3, 7]}, + "east": {"uv": [26, 132], "uv_size": [3, 7]}, + "south": {"uv": [35, 132], "uv_size": [3, 7]}, + "west": {"uv": [32, 132], "uv_size": [3, 7]}, + "up": {"uv": [29, 129], "uv_size": [3, 3]}, + "down": {"uv": [32, 132], "uv_size": [3, -3]} + } + } + ] + }, + { + "name": "bone5", + "parent": "bone4", + "pivot": [5.4, 57.3, 1.25], + "cubes": [ + { + "origin": [11.4, 50.3, -7.25], + "size": [2, 7, 2], + "pivot": [5.4, 57.3, 1.25], + "rotation": [-30, 0, -27.5], + "uv": { + "north": {"uv": [27, 2], "uv_size": [2, 7]}, + "east": {"uv": [25, 2], "uv_size": [2, 7]}, + "south": {"uv": [31, 2], "uv_size": [2, 7]}, + "west": {"uv": [29, 2], "uv_size": [2, 7]}, + "up": {"uv": [27, 0], "uv_size": [2, 2]}, + "down": {"uv": [29, 2], "uv_size": [2, -2]} + } + } + ] + }, + { + "name": "lHorn2", + "parent": "head", + "pivot": [-5.5, 84, 1], + "rotation": [0, 0, 122.5], + "cubes": [ + { + "origin": [-9.5, 77, -2], + "size": [6, 7, 6], + "uv": { + "north": {"uv": [77, 132], "uv_size": [6, 7]}, + "east": {"uv": [71, 132], "uv_size": [6, 7]}, + "south": {"uv": [89, 132], "uv_size": [6, 7]}, + "west": {"uv": [83, 132], "uv_size": [6, 7]}, + "up": {"uv": [77, 126], "uv_size": [6, 6]}, + "down": {"uv": [83, 132], "uv_size": [6, -6]} + } + } + ] + }, + { + "name": "bone10", + "parent": "lHorn2", + "pivot": [-6.5, 77, 1], + "rotation": [0, 0, 15], + "cubes": [ + { + "origin": [-9, 72, -1.5], + "size": [5, 7, 5], + "pivot": [-6.5, 77, 1], + "rotation": [-20, 0, 7.5], + "uv": { + "north": {"uv": [163, 154], "uv_size": [5, 6]}, + "east": {"uv": [158, 154], "uv_size": [5, 6]}, + "south": {"uv": [168, 154], "uv_size": [5, 7]}, + "west": {"uv": [168, 154], "uv_size": [5, 6]}, + "up": {"uv": [163, 149], "uv_size": [5, 5]}, + "down": {"uv": [168, 154], "uv_size": [5, -5]} + } + } + ] + }, + { + "name": "bone11", + "parent": "bone10", + "pivot": [-6.5, 77, 1], + "cubes": [ + { + "origin": [-9.5, 65, -3], + "size": [4, 7, 4], + "pivot": [-6.5, 71, 1], + "rotation": [-30, 0, 22.5], + "uv": { + "north": {"uv": [99, 130], "uv_size": [4, 7]}, + "east": {"uv": [95, 130], "uv_size": [4, 7]}, + "south": {"uv": [107, 130], "uv_size": [4, 7]}, + "west": {"uv": [103, 130], "uv_size": [4, 7]}, + "up": {"uv": [99, 126], "uv_size": [4, 4]}, + "down": {"uv": [103, 130], "uv_size": [4, -4]} + } + } + ] + }, + { + "name": "bone12", + "parent": "bone11", + "pivot": [-3.5, 76, 1.25], + "rotation": [0, 0, 17.5], + "cubes": [ + { + "origin": [-9, 57, -5.5], + "size": [3, 7, 3], + "pivot": [-3.5, 63, 1.25], + "rotation": [-22.5, 0, 27.5], + "uv": { + "north": {"uv": [101, 48], "uv_size": [3, 7]}, + "east": {"uv": [98, 48], "uv_size": [3, 7]}, + "south": {"uv": [107, 48], "uv_size": [3, 7]}, + "west": {"uv": [104, 48], "uv_size": [3, 7]}, + "up": {"uv": [101, 45], "uv_size": [3, 3]}, + "down": {"uv": [104, 48], "uv_size": [3, -3]} + } + } + ] + }, + { + "name": "bone13", + "parent": "bone12", + "pivot": [-3.5, 76, 1.25], + "cubes": [ + { + "origin": [-11.5, 50, -7.25], + "size": [2, 7, 2], + "pivot": [-3.5, 56, 1.25], + "rotation": [-30, 0, 27.5], + "uv": { + "north": {"uv": [2, 2], "uv_size": [2, 7]}, + "east": {"uv": [0, 2], "uv_size": [2, 7]}, + "south": {"uv": [6, 2], "uv_size": [2, 7]}, + "west": {"uv": [4, 2], "uv_size": [2, 7]}, + "up": {"uv": [2, 0], "uv_size": [2, 2]}, + "down": {"uv": [4, 2], "uv_size": [2, -2]} + } + } + ] + }, + { + "name": "rShoulder", + "parent": "chest", + "pivot": [-12, 72, 1], + "rotation": [0, 0, 20], + "cubes": [ + { + "origin": [-21, 66, -5], + "size": [11, 11, 12], + "pivot": [-12, 72, 1], + "rotation": [7.5, 0, 0], + "uv": { + "north": {"uv": [233, 82], "uv_size": [11, 11]}, + "east": {"uv": [221, 82], "uv_size": [12, 11]}, + "south": {"uv": [256, 82], "uv_size": [11, 11]}, + "west": {"uv": [244, 82], "uv_size": [12, 11]}, + "up": {"uv": [233, 70], "uv_size": [11, 12]}, + "down": {"uv": [244, 82], "uv_size": [11, -12]} + } + } + ] + }, + { + "name": "rArm1", + "parent": "rShoulder", + "pivot": [-16, 68, 1], + "rotation": [-17.5, 0, -5], + "cubes": [ + { + "origin": [-20, 50.5, -4.75], + "size": [9, 18, 11], + "uv": { + "north": {"uv": [230, 212], "uv_size": [9, 18]}, + "east": {"uv": [219, 212], "uv_size": [11, 18]}, + "south": {"uv": [250, 212], "uv_size": [9, 18]}, + "west": {"uv": [239, 212], "uv_size": [11, 18]}, + "up": {"uv": [230, 201], "uv_size": [9, 11]}, + "down": {"uv": [239, 212], "uv_size": [9, -11]} + } + } + ] + }, + { + "name": "rArm2", + "parent": "rArm1", + "pivot": [-16.5, 51, 6.5], + "rotation": [-20, 0, -17.5], + "cubes": [ + { + "origin": [-19.5, 23, -3], + "size": [8, 28, 9], + "pivot": [-16.5, 51, 6.5], + "rotation": [-17.5, 0, 0], + "uv": { + "north": {"uv": [9, 9], "uv_size": [8, 28]}, + "east": {"uv": [0, 9], "uv_size": [9, 28]}, + "south": {"uv": [26, 9], "uv_size": [8, 28]}, + "west": {"uv": [17, 9], "uv_size": [9, 28]}, + "up": {"uv": [9, 0], "uv_size": [8, 9]}, + "down": {"uv": [17, 9], "uv_size": [8, -9]} + } + }, + { + "origin": [-33, 38.16202, -8.98168], + "size": [4, 18, 0], + "pivot": [-14, 51.5, -10.5], + "rotation": [64.1278, 70.65922, 67.2587], + "uv": { + "north": {"uv": [288, 204], "uv_size": [4, 18]}, + "east": {"uv": [0, 0], "uv_size": [0, 18]}, + "south": {"uv": [292, 204], "uv_size": [-4, 18]}, + "west": {"uv": [0, 0], "uv_size": [0, 18]}, + "up": {"uv": [4, 0], "uv_size": [-4, 0]}, + "down": {"uv": [4, 0], "uv_size": [-4, 0]} + } + } + ] + }, + { + "name": "bigGun", + "parent": "rArm2", + "pivot": [-16.5, 38, 0.5], + "cubes": [ + { + "origin": [-20.5, 22, 0.5], + "size": [10, 25, 11], + "pivot": [-16.5, 38, 0.5], + "rotation": [-17.5, 0, 0], + "uv": { + "north": {"uv": [100, 227], "uv_size": [10, 25]}, + "east": {"uv": [89, 227], "uv_size": [11, 25]}, + "south": {"uv": [121, 227], "uv_size": [10, 25]}, + "west": {"uv": [110, 227], "uv_size": [11, 25]}, + "up": {"uv": [100, 216], "uv_size": [10, 11]}, + "down": {"uv": [110, 227], "uv_size": [10, -11]} + } + }, + { + "origin": [-20, 7, 1], + "size": [9, 15, 10], + "pivot": [-16.5, 38, 0.5], + "rotation": [-17.5, 0, 0], + "uv": { + "north": {"uv": [10, 55], "uv_size": [9, 15]}, + "east": {"uv": [0, 55], "uv_size": [10, 15]}, + "south": {"uv": [29, 55], "uv_size": [9, 15]}, + "west": {"uv": [19, 55], "uv_size": [10, 15]}, + "up": {"uv": [10, 45], "uv_size": [9, 10]}, + "down": {"uv": [19, 55], "uv_size": [9, -10]} + } + } + ] + }, + { + "name": "trigger", + "parent": "bigGun", + "pivot": [-15.75, 21, -1.5], + "cubes": [ + { + "origin": [-17.5, 17, -15.5], + "size": [5, 5, 12], + "pivot": [-15.75, 21, -1.5], + "rotation": [-12.5, 0, 0], + "uv": { + "north": {"uv": [110, 57], "uv_size": [5, 5]}, + "east": {"uv": [98, 57], "uv_size": [12, 5]}, + "south": {"uv": [127, 57], "uv_size": [5, 5]}, + "west": {"uv": [115, 57], "uv_size": [12, 5]}, + "up": {"uv": [110, 45], "uv_size": [5, 12]}, + "down": {"uv": [115, 57], "uv_size": [5, -12]} + } + }, + { + "origin": [-15.5, 4, -12.5], + "size": [1, 18, 3], + "pivot": [-15.75, 21, -1.5], + "rotation": [7.5, 0, 0], + "uv": { + "north": {"uv": [157, 186], "uv_size": [1, 18]}, + "east": {"uv": [154, 186], "uv_size": [3, 18]}, + "south": {"uv": [161, 186], "uv_size": [1, 18]}, + "west": {"uv": [158, 186], "uv_size": [3, 18]}, + "up": {"uv": [157, 183], "uv_size": [1, 3]}, + "down": {"uv": [158, 186], "uv_size": [1, -3]} + } + } + ] + }, + { + "name": "bone6", + "parent": "bigGun", + "pivot": [-16.5, 38, 0.5] + }, + { + "name": "bone7", + "parent": "bone6", + "pivot": [-16.5, 38, 0.5], + "cubes": [ + { + "origin": [-19.5, 0, -6.5], + "size": [8, 8, 8], + "pivot": [-15.75, 21, -1.5], + "rotation": [-12.5, 0, 0], + "uv": { + "north": {"uv": [106, 70], "uv_size": [8, 8]}, + "east": {"uv": [98, 70], "uv_size": [8, 8]}, + "south": {"uv": [122, 70], "uv_size": [8, 8]}, + "west": {"uv": [114, 70], "uv_size": [8, 8]}, + "up": {"uv": [106, 62], "uv_size": [8, 8]}, + "down": {"uv": [114, 70], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone8", + "parent": "bone6", + "pivot": [-16.5, 38, 0.5], + "cubes": [ + { + "origin": [-19.5, 0, 4.5], + "size": [8, 7, 3], + "pivot": [-16.5, 38, 0.5], + "rotation": [-10, 0, 0], + "uv": { + "north": {"uv": [74, 101], "uv_size": [8, 7]}, + "east": {"uv": [71, 101], "uv_size": [3, 7]}, + "south": {"uv": [85, 101], "uv_size": [8, 7]}, + "west": {"uv": [82, 101], "uv_size": [3, 7]}, + "up": {"uv": [74, 98], "uv_size": [8, 3]}, + "down": {"uv": [82, 101], "uv_size": [8, -3]} + } + } + ] + }, + { + "name": "lShoulder", + "parent": "chest", + "pivot": [16, 73, 3], + "cubes": [ + { + "origin": [17, 59, -7], + "size": [8, 17, 15], + "uv": { + "north": {"uv": [58, 231], "uv_size": [8, 17]}, + "east": {"uv": [43, 231], "uv_size": [15, 17]}, + "south": {"uv": [81, 231], "uv_size": [8, 17]}, + "west": {"uv": [66, 231], "uv_size": [15, 17]}, + "up": {"uv": [58, 216], "uv_size": [8, 15]}, + "down": {"uv": [66, 231], "uv_size": [8, -15]} + } + } + ] + }, + { + "name": "lArm1", + "parent": "lShoulder", + "pivot": [25, 67.5, 0.5], + "cubes": [ + { + "origin": [24, 62.5, -3.5], + "size": [13, 9, 8], + "uv": { + "north": {"uv": [233, 191], "uv_size": [13, 9]}, + "east": {"uv": [225, 191], "uv_size": [8, 9]}, + "south": {"uv": [254, 191], "uv_size": [13, 9]}, + "west": {"uv": [246, 191], "uv_size": [8, 9]}, + "up": {"uv": [233, 183], "uv_size": [13, 8]}, + "down": {"uv": [246, 191], "uv_size": [13, -8]} + } + } + ] + }, + { + "name": "lArm2", + "parent": "lArm1", + "pivot": [35, 67.5, 0.5], + "cubes": [ + { + "origin": [32, 55.5, -5.5], + "size": [17, 22, 12], + "pivot": [35, 67.5, 0.5], + "rotation": [0, 0, -12.5], + "uv": { + "north": {"uv": [12, 201], "uv_size": [17, 22]}, + "east": {"uv": [0, 201], "uv_size": [12, 22]}, + "south": {"uv": [41, 201], "uv_size": [17, 22]}, + "west": {"uv": [29, 201], "uv_size": [12, 22]}, + "up": {"uv": [12, 189], "uv_size": [17, 12]}, + "down": {"uv": [29, 201], "uv_size": [17, -12]} + } + } + ] + }, + { + "name": "lArm3", + "parent": "lArm2", + "pivot": [44, 57.5, 0.5], + "cubes": [ + { + "origin": [36, 37.5, -3.5], + "size": [12, 23, 8], + "pivot": [44, 57.5, 0.5], + "rotation": [-15, 0, 0], + "uv": { + "north": {"uv": [8, 106], "uv_size": [12, 23]}, + "east": {"uv": [0, 106], "uv_size": [8, 23]}, + "south": {"uv": [28, 106], "uv_size": [12, 23]}, + "west": {"uv": [20, 106], "uv_size": [8, 23]}, + "up": {"uv": [8, 98], "uv_size": [12, 8]}, + "down": {"uv": [20, 106], "uv_size": [12, -8]} + } + }, + { + "origin": [31, 39.5, -3.5], + "size": [4, 18, 0], + "pivot": [35, 48.5, -2.5], + "rotation": [-25, 0, 0], + "uv": { + "north": {"uv": [288, 204], "uv_size": [4, 18]}, + "east": {"uv": [0, 0], "uv_size": [0, 18]}, + "south": {"uv": [292, 204], "uv_size": [-4, 18]}, + "west": {"uv": [0, 0], "uv_size": [0, 18]}, + "up": {"uv": [4, 0], "uv_size": [-4, 0]}, + "down": {"uv": [4, 0], "uv_size": [-4, 0]} + } + } + ] + }, + { + "name": "sawBase", + "parent": "lArm3", + "pivot": [42, 41.5, -4.5], + "cubes": [ + { + "origin": [35, 27.5, -10.5], + "size": [14, 17, 13], + "pivot": [42, 41.5, -4.5], + "rotation": [-47.5, 0, 0], + "uv": { + "north": {"uv": [178, 225], "uv_size": [14, 17]}, + "east": {"uv": [165, 225], "uv_size": [13, 17]}, + "south": {"uv": [205, 225], "uv_size": [14, 17]}, + "west": {"uv": [192, 225], "uv_size": [13, 17]}, + "up": {"uv": [178, 212], "uv_size": [14, 13]}, + "down": {"uv": [192, 225], "uv_size": [14, -13]} + } + } + ] + }, + { + "name": "sawBlades", + "parent": "sawBase", + "pivot": [42, 31.5, -14.5], + "cubes": [ + { + "origin": [45, 35.5, -42.5], + "size": [2, 11, 24], + "pivot": [42, 41.5, -4.5], + "rotation": [40, 0, 0], + "uv": { + "north": {"uv": [217, 110], "uv_size": [2, 11]}, + "east": {"uv": [126, 212], "uv_size": [24, 11]}, + "south": {"uv": [243, 110], "uv_size": [2, 11]}, + "west": {"uv": [150, 212], "uv_size": [-24, 11]}, + "up": {"uv": [217, 86], "uv_size": [2, 24]}, + "down": {"uv": [219, 110], "uv_size": [2, -24]} + } + }, + { + "origin": [37, 35.5, -42.5], + "size": [2, 11, 24], + "pivot": [42, 41.5, -4.5], + "rotation": [40, 0, 0], + "uv": { + "north": {"uv": [150, 212], "uv_size": [2, 11]}, + "east": {"uv": [126, 212], "uv_size": [24, 11]}, + "south": {"uv": [176, 212], "uv_size": [2, 11]}, + "west": {"uv": [150, 212], "uv_size": [-24, 11]}, + "up": {"uv": [150, 188], "uv_size": [2, 24]}, + "down": {"uv": [152, 212], "uv_size": [2, -24]} + } + }, + { + "origin": [38, 32.5, -45.5], + "size": [0, 16, 26], + "pivot": [42, 41.5, -4.5], + "rotation": [40, 0, 0], + "uv": { + "north": {"uv": [81, 151], "uv_size": [0, 16]}, + "east": {"uv": [55, 151], "uv_size": [26, 16]}, + "south": {"uv": [107, 151], "uv_size": [0, 16]}, + "west": {"uv": [81, 151], "uv_size": [26, 16]}, + "up": {"uv": [81, 125], "uv_size": [0, 26]}, + "down": {"uv": [81, 151], "uv_size": [0, -26]} + } + }, + { + "origin": [46, 32.5, -45.5], + "size": [0, 16, 26], + "pivot": [42, 41.5, -4.5], + "rotation": [40, 0, 0], + "uv": { + "north": {"uv": [97, 110], "uv_size": [0, 16]}, + "east": {"uv": [71, 110], "uv_size": [26, 16]}, + "south": {"uv": [123, 110], "uv_size": [0, 16]}, + "west": {"uv": [97, 110], "uv_size": [26, 16]}, + "up": {"uv": [97, 84], "uv_size": [0, 26]}, + "down": {"uv": [97, 110], "uv_size": [0, -26]} + } + } + ] + }, + { + "name": "propulsion6", + "parent": "chest", + "pivot": [1, 43, 9.3], + "rotation": [85, 0, 0], + "cubes": [ + { + "origin": [-5, 32, 8.3], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [230, 241], "uv_size": [11, 12]}, + "east": {"uv": [219, 241], "uv_size": [11, 12]}, + "south": {"uv": [252, 241], "uv_size": [11, 12]}, + "west": {"uv": [241, 241], "uv_size": [11, 12]}, + "up": {"uv": [230, 230], "uv_size": [11, 11]}, + "down": {"uv": [241, 241], "uv_size": [11, -11]} + } + }, + { + "origin": [0.5, 16, 8.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + }, + { + "origin": [-4.6, 16, 13.5], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + } + ] + }, + { + "name": "propulsion5", + "parent": "body", + "pivot": [4.5, 26, 2.3], + "rotation": [7.5, 0, 0], + "cubes": [ + { + "origin": [-4.5, 15, 1.3], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [239, 132], "uv_size": [11, 12]}, + "east": {"uv": [228, 132], "uv_size": [11, 12]}, + "south": {"uv": [261, 132], "uv_size": [11, 12]}, + "west": {"uv": [250, 132], "uv_size": [11, 12]}, + "up": {"uv": [239, 121], "uv_size": [11, 11]}, + "down": {"uv": [254, 26], "uv_size": [11, -11]} + } + } + ] + }, + { + "name": "bone", + "parent": "propulsion5", + "pivot": [4.7, 26, 2.3], + "cubes": [ + { + "origin": [-3.9, -1, 6.5], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + }, + { + "origin": [1.2, -1, 1.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + } + ] + }, + { + "name": "sled", + "parent": "base", + "pivot": [0, 31, 4], + "cubes": [ + { + "origin": [-22.04043, 28.75979, -15], + "size": [15, 12, 41], + "pivot": [32, 22, 0], + "rotation": [0, 0, -17.5], + "uv": { + "north": {"uv": [136, 98], "uv_size": [15, 12]}, + "east": {"uv": [95, 98], "uv_size": [41, 12]}, + "south": {"uv": [192, 98], "uv_size": [15, 12]}, + "west": {"uv": [151, 98], "uv_size": [41, 12]}, + "up": {"uv": [136, 57], "uv_size": [15, 41]}, + "down": {"uv": [151, 98], "uv_size": [15, -41]} + } + }, + { + "origin": [-15, 14, -13], + "size": [30, 15, 38], + "pivot": [0.5, 21, 0], + "rotation": [10, 0, 0], + "uv": { + "north": {"uv": [38, 83], "uv_size": [30, 15]}, + "east": {"uv": [0, 83], "uv_size": [38, 15]}, + "south": {"uv": [106, 83], "uv_size": [30, 15]}, + "west": {"uv": [68, 83], "uv_size": [38, 15]}, + "up": {"uv": [38, 45], "uv_size": [30, 38]}, + "down": {"uv": [68, 83], "uv_size": [30, -38]} + } + }, + { + "origin": [-22, 12, -12.5], + "size": [45, 7, 38], + "uv": { + "north": {"uv": [38, 38], "uv_size": [45, 7]}, + "east": {"uv": [0, 38], "uv_size": [38, 7]}, + "south": {"uv": [121, 38], "uv_size": [45, 7]}, + "west": {"uv": [83, 38], "uv_size": [38, 7]}, + "up": {"uv": [38, 0], "uv_size": [45, 38]}, + "down": {"uv": [83, 38], "uv_size": [45, -38]} + } + }, + { + "origin": [12, 17, -15], + "size": [15, 12, 41], + "pivot": [9, 29, 0], + "rotation": [0, 0, 17.5], + "uv": { + "north": {"uv": [41, 139], "uv_size": [15, 12]}, + "east": {"uv": [0, 139], "uv_size": [41, 12]}, + "south": {"uv": [97, 139], "uv_size": [15, 12]}, + "west": {"uv": [56, 139], "uv_size": [41, 12]}, + "up": {"uv": [41, 98], "uv_size": [15, 41]}, + "down": {"uv": [56, 139], "uv_size": [15, -41]} + } + }, + { + "origin": [-39, 14.5, -9], + "size": [13, 9, 29], + "pivot": [-26, 24, 0], + "rotation": [0, 0, -47.5], + "uv": { + "north": {"uv": [29, 180], "uv_size": [13, 9]}, + "east": {"uv": [0, 180], "uv_size": [29, 9]}, + "south": {"uv": [71, 180], "uv_size": [13, 9]}, + "west": {"uv": [42, 180], "uv_size": [29, 9]}, + "up": {"uv": [29, 151], "uv_size": [13, 29]}, + "down": {"uv": [42, 180], "uv_size": [13, -29]} + } + }, + { + "origin": [25.5, 15.5, -9], + "size": [15, 9, 29], + "pivot": [25, 24, 0], + "rotation": [0, 0, 47.5], + "uv": { + "north": {"uv": [157, 29], "uv_size": [15, 9]}, + "east": {"uv": [128, 29], "uv_size": [29, 9]}, + "south": {"uv": [201, 29], "uv_size": [15, 9]}, + "west": {"uv": [172, 29], "uv_size": [29, 9]}, + "up": {"uv": [157, 0], "uv_size": [15, 29]}, + "down": {"uv": [172, 29], "uv_size": [15, -29]} + } + }, + { + "origin": [-11, 20, -23], + "size": [23, 12, 22], + "pivot": [0, 32, 0], + "rotation": [17.5, 0, 0], + "uv": { + "north": {"uv": [112, 171], "uv_size": [23, 12]}, + "east": {"uv": [90, 171], "uv_size": [22, 12]}, + "south": {"uv": [157, 171], "uv_size": [23, 12]}, + "west": {"uv": [135, 171], "uv_size": [22, 12]}, + "up": {"uv": [112, 149], "uv_size": [23, 22]}, + "down": {"uv": [135, 171], "uv_size": [23, -22]} + } + } + ] + }, + { + "name": "lGun", + "parent": "sled", + "pivot": [18, 12, 1], + "cubes": [ + { + "origin": [15, 5, -3], + "size": [6, 7, 6], + "uv": { + "north": {"uv": [6, 157], "uv_size": [6, 7]}, + "east": {"uv": [0, 157], "uv_size": [6, 7]}, + "south": {"uv": [18, 157], "uv_size": [6, 7]}, + "west": {"uv": [12, 157], "uv_size": [6, 7]}, + "up": {"uv": [6, 151], "uv_size": [6, 6]}, + "down": {"uv": [12, 157], "uv_size": [6, -6]} + } + } + ] + }, + { + "name": "lGunBarrel", + "parent": "lGun", + "pivot": [18, 9, 0.25], + "cubes": [ + { + "origin": [14, 3, -24.75], + "size": [8, 7, 26], + "uv": { + "north": {"uv": [212, 149], "uv_size": [8, 7]}, + "east": {"uv": [186, 149], "uv_size": [26, 7]}, + "south": {"uv": [246, 149], "uv_size": [8, 7]}, + "west": {"uv": [220, 149], "uv_size": [26, 7]}, + "up": {"uv": [212, 123], "uv_size": [8, 26]}, + "down": {"uv": [220, 149], "uv_size": [8, -26]} + } + } + ] + }, + { + "name": "rGun2", + "parent": "sled", + "pivot": [-18, 12, 1], + "cubes": [ + { + "origin": [-21, 5, -3], + "size": [6, 7, 6], + "uv": { + "north": {"uv": [134, 19], "uv_size": [6, 7]}, + "east": {"uv": [128, 19], "uv_size": [6, 7]}, + "south": {"uv": [146, 19], "uv_size": [6, 7]}, + "west": {"uv": [140, 19], "uv_size": [6, 7]}, + "up": {"uv": [134, 13], "uv_size": [6, 6]}, + "down": {"uv": [140, 19], "uv_size": [6, -6]} + } + } + ] + }, + { + "name": "rGunBarrel2", + "parent": "rGun2", + "pivot": [-18, 9, 0.25], + "cubes": [ + { + "origin": [-22, 3, -24.75], + "size": [8, 7, 26], + "uv": { + "north": {"uv": [84, 209], "uv_size": [8, 7]}, + "east": {"uv": [58, 209], "uv_size": [26, 7]}, + "south": {"uv": [118, 209], "uv_size": [8, 7]}, + "west": {"uv": [92, 209], "uv_size": [26, 7]}, + "up": {"uv": [84, 183], "uv_size": [8, 26]}, + "down": {"uv": [92, 209], "uv_size": [8, -26]} + } + } + ] + }, + { + "name": "propulsion1", + "parent": "sled", + "pivot": [-11, 12, -7], + "rotation": [-20, 0, 0], + "cubes": [ + { + "origin": [-13, 1, -17], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [11, 248], "uv_size": [11, 12]}, + "east": {"uv": [0, 248], "uv_size": [11, 12]}, + "south": {"uv": [33, 248], "uv_size": [11, 12]}, + "west": {"uv": [22, 248], "uv_size": [11, 12]}, + "up": {"uv": [11, 237], "uv_size": [11, 11]}, + "down": {"uv": [22, 248], "uv_size": [11, -11]} + } + }, + { + "origin": [-12.6, -15, -11.9], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + }, + { + "origin": [-7.5, -15, -16.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + } + ] + }, + { + "name": "propulsion2", + "parent": "sled", + "pivot": [4, 12, -7], + "rotation": [-20, 0, 0], + "cubes": [ + { + "origin": [2, 1, -17], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [243, 26], "uv_size": [11, 12]}, + "east": {"uv": [232, 26], "uv_size": [11, 12]}, + "south": {"uv": [265, 26], "uv_size": [11, 12]}, + "west": {"uv": [254, 26], "uv_size": [11, 12]}, + "up": {"uv": [243, 15], "uv_size": [11, 11]}, + "down": {"uv": [254, 26], "uv_size": [11, -11]} + } + }, + { + "origin": [7.5, -15, -16.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + }, + { + "origin": [2.4, -15, -11.9], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + } + ] + }, + { + "name": "propulsion3", + "parent": "sled", + "pivot": [10, 12, 14.3], + "rotation": [20, 0, 0], + "cubes": [ + { + "origin": [1, 1, 13.3], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [142, 242], "uv_size": [11, 12]}, + "east": {"uv": [131, 242], "uv_size": [11, 12]}, + "south": {"uv": [164, 242], "uv_size": [11, 12]}, + "west": {"uv": [153, 242], "uv_size": [11, 12]}, + "up": {"uv": [142, 231], "uv_size": [11, 11]}, + "down": {"uv": [153, 242], "uv_size": [11, -11]} + } + }, + { + "origin": [6.5, -15, 13.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + }, + { + "origin": [1.4, -15, 18.5], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + } + ] + }, + { + "name": "propulsion4", + "parent": "sled", + "pivot": [-5, 12, 14.3], + "rotation": [20, 0, 0], + "cubes": [ + { + "origin": [-14, 1, 13.3], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [230, 241], "uv_size": [11, 12]}, + "east": {"uv": [219, 241], "uv_size": [11, 12]}, + "south": {"uv": [252, 241], "uv_size": [11, 12]}, + "west": {"uv": [241, 241], "uv_size": [11, 12]}, + "up": {"uv": [230, 230], "uv_size": [11, 11]}, + "down": {"uv": [241, 241], "uv_size": [11, -11]} + } + }, + { + "origin": [-8.5, -15, 13.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + }, + { + "origin": [-13.6, -15, 18.5], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + } + ] + }, + { + "name": "lMissleLaunch", + "parent": "sled", + "pivot": [15, 26, 0], + "cubes": [ + { + "origin": [12, 20, -14], + "size": [6, 7, 15], + "pivot": [15, 26, 0], + "rotation": [-40, 0, 0], + "uv": { + "north": {"uv": [260, 108], "uv_size": [6, 7]}, + "east": {"uv": [245, 108], "uv_size": [15, 7]}, + "south": {"uv": [281, 108], "uv_size": [6, 7]}, + "west": {"uv": [266, 108], "uv_size": [15, 7]}, + "up": {"uv": [260, 93], "uv_size": [6, 15]}, + "down": {"uv": [266, 108], "uv_size": [6, -15]} + } + } + ] + }, + { + "name": "rMissleLaunch2", + "parent": "sled", + "pivot": [-14, 26, 0], + "cubes": [ + { + "origin": [-17, 20, -14], + "size": [6, 7, 15], + "pivot": [-14, 26, 0], + "rotation": [-40, 0, 0], + "uv": { + "north": {"uv": [175, 257], "uv_size": [6, 7]}, + "east": {"uv": [160, 257], "uv_size": [15, 7]}, + "south": {"uv": [196, 257], "uv_size": [6, 7]}, + "west": {"uv": [181, 257], "uv_size": [15, 7]}, + "up": {"uv": [175, 242], "uv_size": [6, 15]}, + "down": {"uv": [181, 257], "uv_size": [6, -15]} + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png b/common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png new file mode 100644 index 0000000000000000000000000000000000000000..b59ba8b11a26fb27dbdcf959446c7e0cb5dc06e4 GIT binary patch literal 387006 zcmYhiWmJ^!_dR^g3|*ptl!PLZlF~I82nr0{r7+SZ3>||gC=wzqt>n-xJqm*4&>*cS zF|>65$Itiqt@W&VF|*dZx$bkHv(Gtu@9T}0=0j=<7773WwVLXE9RQ$&pR|CCgz!Zq zW6TBsCs4butmk8~*6iDqj`S5eU87Zn+GKqHPFqfUjr0DwdG>^~v&YpEztomkd2hHtGk9)+xeh$>w4v&`1Ol`!>J?oVdS2x}5 zfXw=D^2M39v3eGixubBY*jdTed?(Cb zaa?w*w^n53v+s7`M8kRBA#;*p%kElC{n^A)#HLT}qa<0+I@~vZDIHv-v-kR>zJK)b z1})4QE7;+ayt2w$UpAA z3wi2_P8+zjsX3vA!1xv0T8+_B&1SF9WzOqnp7PU;!Dq*koXn3sG({i0kPrzb4l@#H znR-qfsjnmj(BcTidh@=aAO4a#qUYX|wR8aOoe3DNVOyH168Q=bPSR2GEIwIiH2UB$ zJ*z$<@hIqj=gy~RDv(`C-=9=s$KHCaaf#}p{g3S{{kcZ|H1Dp|Ul(!)Ggl$-A7>W_ znHP=z4(&PaAKIC`AVeT>JMSu9^fIzN@ktejX@8I)9U_5_x8VL$!M=JbV8sSPDX4Ta z8AJ@4BjY!&$yqPH!@x-QYg+4WX)r(E{4vuwImDcHE@wZ*2e6IQD~xl#sx5BWR7nSC zvEdvnViyfVFldM%q`>d(-!t_P^^l)BR$2HQ(!q^M*MP#kiAn!Y6CA0WLLwL9hE4nd zdx%zA#pCc``tFV3?Xh4lMAR~Az8WH+SN8^!Yh0g23fXa8WIGqrl--QjvzPwGZ*j?7 z-+HCfqjP2QlW*imZnEVJCv^FEbLMB=gR*?x?)p7>UfEd8y$C)tz19SP!tYyIlflY^o9aG#0G7oOUhv481GM)Yb!Rcn!M27p9t&xrJxFS@j1@j zv)OCr*}HFhGke)D)`_(uS7S-XYh95*YwvOIfjF@kvC3O0OrJ*~ZLRdE-QR@&xYNda zbK+{oWUWkwj}OI12kh)cpVFC=f8ebBkeq^vf;+P=8}%=33b=?BB0o)+jl5m8Z!Xn? z0>CBiD=3|J+VZP>tcF?n>T3sNp{X3jl^t8Fg2H zn6S$+k}_Aio?LXoRo|3B`%~~Eu*K{EBJ#f+c79E3^*CyLye^LSgIJxRnqea(@RZMi z7VpUBF))CyUMB)ZmzWZO5kSkp`NJqB!B}N$|4DKbSk>Yi@1p-szf3~>@v_wqwM!q( z{UGQrL}r~x^xI)20Fjc7&)sMvD|d*b2U&{dDTVmAgZ&xoHNwbc{rNBZj!Q33PylQ6 zVdu6~K+A~Yr&2~>r#~)-o{t{7JV1{du>KWr%jcXQxstQ)2Ed}qJvjbkePynp;~5x; zy3KzO%lD3NK!Bn;3aqaD4ZpLspho;9z^#xnj^yymN~Q|h0fyGV)jm=3 zqj+kGSHsqht*gy|QA#*sd(5g=PT9d2AD;rHEqtz!P#GKrLswRaE%A(5&fU^xa}3V4 zO+U^EB+a-zE$AB&ewkA_6)F^vcR34VBI`Uw%>^&z$PYC0Nn)Tf;)C-vYLI|*t=o0~ z-hkbs5Z>8w)gbvV1FzpGBWPh*7#LfAv*-TwhDW|d+=1OgTIIV>M5DHK0bI&os9*g2 zM%CD`(rS_#S@#I(Bu`2#28`Upl0Yjvg3n}aRlx_Nlh8a3y#FkO0$@hOm@c7vU_fJv zh7ni^od(XcdJ2 z>9#lFE(ogRU#}<^+nuVhWKfDwzDq!a3Be$)Pf}KDvpglY=ON^W*Za!%dJ7wx07Phj z;8f>iTCmRo&!ctm;u@vpJ7$|`dQgsw#pTd|g5g?SkQEC=^YwO>pk@N+bw7jGWAq?^ z`R@QV6SI6(UW2z|JYf)T6ZMffa2U4#o(hp^ikVlc^ax=y*}9sg`lW^E`D`AZr!kv{YYB5_?HiL_j`Y)`$X`rK4CLh$^5yHM zwi|CZJyNqdDE>TFP{a!A8@e}#2OO1{yuDuWqhYBh3z6GL_AZ*AlpU>l6;>~RRi ztP9Qk3!WCmXZLem<8w?TsP`>wq?gop$zhVtg=rLm?&Ly3L?XY-`c7X}r3Le?QFK`V z96$^@hSGGwd>Y-e>U)s!>?gWlV1>t2c1?XnohRlb3Pd-O-0@R)- zPPb_ih&;ElISy|kl6MV_?;pMe`>Q!@(CZqtAGWjHR9>Ay4=&@s@1mOGM?TIinmvSK zQH3|*;}L&TC7sIp0#pQO2m>A0vG%J6VHm2bn?kT-w{$z(sVxg0XJ^*kTx&0}*-?Lz zPyD|g{i)l!p=&T|jyl0i;=H6=>!&6Eoymqzc`;e>d^{00o!s&6Q&Pv6Rrq1)+D+1G1 z#=_g@1RS&(|BezT?w}zK13*313rH3*D?mmlIsZVgiUXN1$Q_9a@Q_QO;6ZbSPVr-N zeR=dxc^X`4Rw*OaDA}W1MAI1vR^?Np6TLA|5c))nb5jNaCSE?)gWPdGskfBPPw#tg z?Yn(yzx+r+VZp#BI~djP*NQ0_H^f9SdXgqtD1sM2@f|I>gH2Tc7m z@28$o>_E#u`b)h0+NCCpoX11ppD^)^V2Es?A-FHyc@JF!*=hpaAMw6^Cob>I zPipwV9(2GHE06pc+=`PS2E~L{w!(qVB8+2JYLf3QDco}3LwtFH6}=UOYl(r?FHEKP zJ>8R!?BDh*NZ?b5d}ltHt&W|$mjuw)2hOKXylb1eBbNLouDqSo>(&1v&#+rufJueG zrM%uxKg@$)XwQoP^spRrm00i|Jyxvvl~Oku6gyuMh0Zu%C#RHzj-mPfkbH;BOTJNW zg@S?H%%y;_5#@@{Ci_XoC!I@cKF|rp!x_?$IIFl?06vpxHD`WmNp*p~oJ~#bLLJmrO>%PQY<7uVs7#(z-olK&y>(9l30c;$uhCln#G0DJCQCuyD zNxj=^imXUxe}IM2$nxMGW2^QNAvBcIP22K|xOxK!Pz7#-_g>X9u!DgHX5i^4)pce= zvCBw23DDR53Ny#iaH_x$6pT(g#8z*#xaOZ02NToo($07MDFk+W8@XfL@TOx-rKW)1IxS(tz)s{~pVR|E zk7sGYLNV|!0*2a!Q9S5@MZfP&?Ge!pUwFv10ak^v`PtKK$38|Ntw$`l7c zb9Yva!?EH$WRg@cLrUopCGX!Q@rpfNen7ow4U_$`iOfc)R*%BrRQk@aH9IoLK-~BE zF9kK!tL0|QGMl-R4y+@i1!xP_lc{PCeO3@nEjtWnK)%!Z`PIKLEP?m&Xx|ldMScB} zu`Pw3b`~|zx|~XL6Q~}o=APtU=a4GWE3m50y?z}(M1!9Hk_YQJtCR*;fzRDD%iDcdROEB>i;Y1S6xc5 zd0qYRC>d9aDG7rpWX?asa9w(%mrAzVI1^o_e{e{DA7Qd+!l!oX#JJE9L!{F%yL_n_|cnx!F zLC{ImTH=rwLi|rh!-vW|Hg4Xt$QNdv%6%$NyY^$C`ZVKj^}sRG`Jr{m%tr=&wXxTF zy4-Z=vBI~$d}NRJ9CL*%rb*K8@$e;uKmIhW_-~aEr?{3#{q9$==Taf`7hf6e569_X zlXIA0&SXVY*ppG(0@MtsSMMve9D(-yAqF{1DMjh)ks)2Ii zE3OvE_2NryGs@X^%hYzsLCX%6`M>wX1i{Aykcmedy^yK4wfU92u-&3ZPb z%O$^gKmF;k={ook2SnPRr#BorD?{O&)LGaA35KBh;<=xtb@;lZ z&3_}bXAIOu2#5sf6N?lJ-vqlyq)g@HFD6JXMyUs$Q5MHhawgCiMRm}FoSP7fm-YOA zb0fQ(p0kpo15F2BJl`X-YW@i>n?KC=c=nY^!(P3jao_dZu1V*!cRTni^uCEJwF(_2 z{5!|@4K%*voOy@ik4tEjIU!N&G@a4SktMW@(y!SU_zsiSE#F!L8~Q z8=;04F-l)QAD>w^J^_EZxt|%Yo$)rk>DF6SEy4RUMVO-9v4%BMNbC^*s4EFTdBqcE z#VjRWttm=$c5ord{BDX;RyQTslZXbP$+Vn$xv-5(&)F0y7ol5!3u0c$2zY$rP2SnR zdG)H5@m9k7fh_YB)gLczo|t<;?8G=-OTA{19xDE>>C(mvH>?IlYZOm3`@BB`I5&v* zTlW7Zmd=waWANU3Rm=&6$*}b?mIx=jK+9lpUyBszLM-$$cqg;aD&}dj=V)X#qD_lE z<~1yXqzZt8C(_^T(2@QYq#&zg&v;+cWyS}tpKlzQUHXjgUlOY`fW407x+VSCh?@D_ z%^Fm;;l3XC2O1;lfo`)I5hXFfCK$_ovIBf?_~sj1;g8xJ7& zOse|KRXkI4WLT|=JWxxO4NIE6CI*%}gyK)W(=#zs+-E?O$UM0(9z|B*e)a`xPgHOO z`+hpQ6@!P8@M|N0V9XQUW>qv^ptSeSgR4EC6-bJm<%ns=aPkS%ZpD2mF4p^=sj?|? ziG{QT2iMGdTSFF6nu?6iOQ zFjC`5w1sac(^`55!G3p|_KjB$anZ_hhN1hJ0@Y!s^SfoevPc*Z1}v0c@k$JrHD*Xh zOSXz)HaOmUOdm(&UtMK>n_bGFpBLHPO*Px(@5L@j`%bK`Lc}(`Y;@ZIlGiYFWq);L z8%0$Vx~PETN&f+QCaG-C`6~v1oW_!zSy(|~oMNkQf|i{cgYRV~IQ&rK_Z;;^EnHy&)_Li@MNU=2KO~VOvN#vqk54eg-^^FcGN{jEFy=gKioN+Sv>wn<}D;aVY}jsS9E1j+#w8chHpB1JXiD~ zmJKq(y9v*&e@Pnz^hxeB6kI8CXp~*8TbM%SZ}{VK1yvDsi=&PvGzY&UkL(5CR33cS z+MAAOAoE>}+6Paw3bg>beh$@QOV4p>ME8 z>cgx1eiqBE(Nge~aL7tF71yxX8OvBMQYxA4i*tgq9W!sSqrk7D*?iA+{j9#mm`ay{ zoE4JT|5%Mk%YS9l0P_{n{%|`c^QTbGhHBz{Pri?twZ~=)9to=q$E%A?Oyv)j){bgD z%)J!6`kP#>E4)4WuPvzNAf?)8C_s~HIFeIpFV2?L@7Bbyzi?+4usU^V_eG{aKPiV? z2XG!OTaVqZ*?D(!{NC<#47_&55B*l7?v}KleVo2kBB0B>U4-9v=zl17yOA8MHEKO< z(C23URaN0mt%n&|{}+Y937fyk|H6Hy7E()%j!<5WxUVbZ;m7}LNo?j>!c=m8lJM$y zsv%wQMS~>GWWLx7^`6Y;we+D%)?Q7zN1`rhYW-qz50O>OK*tC2p@!M)K;h065{+XI z*6ylq0xiHqO;PO(M11%K?Hr!!m%3|A|J6wxpZUNzuGN{|!1I;=pUDs2^FQmhNW5# znf(156V@5L`^xBTW|GC0mYgP#)a_Z;5&hQl+T7c^ZsScxnHQVYd(1+;tNj2AE662J zE`(D0Wv=Qpto`sr-RYffUOyMHo=vHcRTNe@v0h)whCJ;y8x$NqT%G$Yy&pwMp5i7N z!KEnv5T>QpxA!(IQ4155sxL)#p;3m+u4b|WO^1& zlLyB({b{c0r;uuhGHcY8*PAQ=le92$wyvjGZg!nerJTCJpE*UTP?;9HNd%D;VBUZFs&Zj^r}lK86K9nWv45WRtf{STgs$`Pft<2Klem+7NGJgi!DDh za5cNXaX7z69Xp^ZpXsE3)Vl-O;_#MNx68_$6lB7M zXfuHbK6gE!LoT)3r$C9tkq5qr=n3kB7D{qC5KXMRR}y7y)F!U}!o=Bcr$bAxp#ftL zB4DMg^YF~J>9lwY8?)iOq+E_{_1<{zwjbf~Rl#w?CGOXYo>_XAmVJ!ZkT=ewV$KU^u6-J0geN&{#r!!$iM=opSLY77&;z?i(!Bf2g<^I(DvhJj#UUi-vo@B=YV*?_}*=| zJ&pk0|3svq_4Q4`j?Y4A!P~hN>^H$dS-tq_x7OL|TQe7jSl9MAB_|@c3rnF3li~}+ z#o?u&&8=sH$s6@9Q{NcXId1e}Sw@y)c!G(c#jx@L>NjXxnASmfh+m;JRYv>wN$?+R ze9)2@?<3$*!ACe3K=<=L?XZoI_J0Di;s%MAtpogJhrc=O-evfPZz{z7c~%xQ}93#tREGMZ^i77+wfATAf$gx4ySsdWFny{#}0I z@3lcT{H)LZ-|5VWK=?7n;l%P{QQTRWrH4^R-ea3}FPd*f!R_We@D zzsSrdFu(wWaAdT9v>=g*6HGxD`|U9@g_pAuz`SBl!%v2JZrCH_%CL>1epjdnVr=l- ziAZ&1$4tG(IlVWEFR35nt?(be{GFcn6Wp1wREu1a6Mp+UpRT|^Vw>tS87SVAObOP_ zbWsVcVkSc^7_@F!L_HQpE0f5K&;jH~TwHVkj1??C%DQ}OnLr< z=pWQrCqYH&-T3k8b#}XlH}u0{&DQy5byX~$1L3L-{7Vu$>q(l#&;+GiExO2BWt1tLaJA9M4n~9 zJx-lFWH3sA0n3x{MC0D)$*mIo-!(eWFt3`R8H3Xzh&lazy{OI;_I!?rA;zw%x!t_1$6mrov2cO2O>owHGZ9t<5Ok>)mn6yciV08YSG0uonwVlSE(j5MrukJnmsgTea2K{ zBAIYAEb&8dJs4!Ai)~?R_Y#;d>Fnv#%6qP=cH46*YY>zEw)6qDsjg{1X37u=23k+t zGmP`FuXVDD06O)W=fG8U>?3mo(kQpYR{2FnuT$in?2QW_6M@s8MRyy-`q4bG%YQyQ zP^nDX2L!7a=e(Y~CGhkbI6jR#8e0if@7{mHP4YpY{CoawnJdeKpT4P(R9^-R@gJ#EE|QYc(@(Sg3bPfulFU;}JBL2(2*ZHg z!h_C{H?y_R2+AK!w}R=;iN5Z>VxW1N#fXqFPRBy>;aY45$Q>2(J`29X9`YR~Y-4t;uQzS)pv)gfk&wneuJ2tM14)l=3 z>ogR8&vgE5fm6MV;$6`?fvq}cwOS6{;Pz#{o%-&42D;NLMjUNMai1I{Z89&o(|x^& zugG%IGqLQ#zp3kK|LFJOfl_)}d(TjlgP)<;6;`r>@dXD?PO-;n`+P%&gH0;Ouo<7{ zJknr?N1;XtCUyB*d9VmY*`*#%dSKMC9>^nIuHv9EWg>FlS_ARBgzDPv*3HL>KP!WY zuX(YSTU;GE8{WdHq*lXU@P~~|i)JK<26% zO5If3lv1o348j+u#paumM7)?4=pzZ}lR^#DiIA2zZ-rIj<29$=zj54ej{nnW(jnmS zvK^ci{6=qbB1VuMq5OMy6`&yE!a0lA@ecx>1<-KB6y6`nt;b(KP@k^{t+ia;e(wy# z=)V6GI5}PyK<7K0A2feh4o{Uq^m@_#m6T$=GHN2s5vEFU%bK|&!c!b z#_(C4=Gj0TOe)aL%dxBH?)(zv#c5acUJG)YNmX1wH>Mv z(H(=qH;Zz<^gqmn*_>}?if~De$JOrJQd5mC>&<8kc3_B{>>OG9Cu^5JXGn!iiUBJv z{a6Tm_Vk}xY6j+gA#UOb=0oG=J5nmQ2DEQw2NseU#H|~#iA50f2)P_+cHK<3_i4=!VGMLjh7quuIph}&trL2`rL-HFB(PNv`{ zOYp*|c7HN7TbFhoa^LY&RxNRN{FX5{$Z)=kxjpIo{_>uReQP_h-S2Obr~StUuB9Hs zakAa(U2I5)(}!BWe2oiAEf5Qs)jA!vqPeB%!wot#e|aTd+Hu4#3Q~Vw4E>%OOz8Mn zT7VX&ub9VuH#iYV>7dEmVUcI9VA%Ep3 zDzt3yr|e?ppwC_zTK=1{pPcR%J45E&7e))Jm^nXhG|@b_Ej1LFi6i`xr>(0$IodD6 z;mQwn03`rpyY)IBU$_e@By{NnYSrClPFtFCrPkSd>AIj*aFcXL`_>~ac)z*w3rw0z zW1#--N%-=d7^*SB2QM(9#@w1%FZ(fl^q@)@@#?4A?_&2SlF;7&dy=gDaIw5Tjc|29 zH3|cFID01e4tBr9 z55$6p7#z?)3jjSRFimAlG)CYJUd~mQgyHo!Ns5cQ9}I{+QJ68^B*W#w=lmtks|HC+ z{O-fp73$G(W#ks!s3J=4{g`SF6kpFJnx3IO#_tpFZ=Iu zeZC(btv1H&7u%jxo_9+olS}zk*F{d?V^KdP@061gHMwCOCK90R%`A1%)L4mE)Yu0c zzQ~bPrRI8uXt`|K3r!|6Vfk?irIsh0X$DVWB4%80#m0DnJko*@ct1;lah(+FyDsa) zfDS*u@uiKGq1$8?fd%d8E>9y;51pA-DVI1=hHK06TgKv)zZx;Ef>yQF!$(=|JfBaXZ2F2$e0L520uVnGNQt#An-&SfrzD!n1dH*4>D*2vzi|Cg;VPyU8 zcc-)DJviM$EN;x54bxstGkN`-kt6M8{l<*+Pi!LUdaraLttoXf7eGR99bBw7@-{g1dx>(3`^w=)|KDqJIGZ!>iS zI_jdu*y!d)b>`wsmN(llbH%$wkGiokw&dtQkG}`%AzVq&Qj6q4$a>d(<{ZYXFq@m7 z%APtPZ4iaGiVx`mbKYOrU1T(5Q30c{@m2SW-!DoK)GtH6w==fV=bwD}!4Xj5wj@w| z>i&h&>T4DZe)8+Ai|&%9g--Rts4UahjuX;WhO>>S~{`a z9qWyWlJ=UZ)wj63w%MGo?$Sr_eX6HQ@bsoj2@6^@-Bc$S!+Mj&h1X^)O3p3{om1Ng z+ir9pyYFE(T5>9Ln)$+eXunEnVmemi0S|6|q0EeF-BZNUEV=3+JAf zZ%Mb5ll%DXd|66Lm-fJ8g-hiIx~5D>zyOE6Jr@MyGYz|>@4VU~XA^DX03f!dKKlNJ z02))$EafzPc*r?CU3*(hSu8jnHMIYa!xjZuoTNM4bcW9~wdlru$R^&A5z!oKZlNV? z!9bVr4T77CNr~P~O4N@8`zVD+9&aXiRhEt7Pq%HDV%9gp6c*1o!}?dsx~nWQ~W4V8j>>ji1B@oyePqVE!#$*IS^LFJqF zMYOOrelwCx-y3U|`(HLx!6Ca5BTg1%sZBL(MkAwb%cOZq*>r$eJP{lUXbD3IRqVe% zV@be2dvUy5b&4OvW{Yk0XD}L!aABX!#J5}B%w<}z?dcWx@BFGzkTL0V-1*+wX%8dY zrVW{(t!8R1WzC`8;SC1)@2Jnj0W1Q)$uYD(UIH1ja3-R-J_t8cG`{e(SK$2luMuuJnvL{^Y*M1o!`}D#iVYDd~)0t)y zAnp7(hc7(%CdhP1`$5 zsUI2SCnFTndC_!O-=#~VxHs}^m@;q!L7}kEOuQ*%1_)2(7YP$_`_7=X$>HDoMJ<(` z?1}aujpWOiIm2CT>E}*@*CfLnVQ^a8HZV0!k^G4<@#-IqsWDS!WDY45 z;E7wSURNyw#cw|mOJSf|QV(5MKWfjbzDV9~e6>i>O(M-Hs<|L{<=?j7WKp0-N*c)E z=YOd&qp+&ZAFo8+qv3?V(_#ch1XV5>^>)NY&!XUIwd z9SEP)^C`?$d;9_rKSesHLJ76FO>j+>iX%w@7$9JXO-4C{6U_T9{{f>UHyQCivv6Y= zNF}S)jFi%N4?WWby&Vti7auNcgPXkA0sFYCyP;P2%pz$}TTHnlTYDIzQ|Vx$7x=Pv zdbP8|dh^d`Yhu95^rF4f&)7~yX<(}5UN6Z+j`PgHeQv;HN)3FEAId2Dm!kP#SWGP! zIq;04-x=mEk7muPi+VEigUs#Jb<6iv3KU8I`U=p?(r=|c>*=ugtt6~ozQl$-Pi?

    |j&vwBU9R(xpFnO*pwHx|0886PFAE9*RWJGwm;q6xD}r+nqulv5Huv zGZD!On`RzVBNBa6e(YxKuYP;D>^U7o4ES6lD_<%S0lt_BS?9T0&!?&Jl28kquq(tk zlg*+-cGRAn6U0s1wm)cshcve!{ZD#iNUiH(?>Nm#RLNOKl8INeSH^y$zM5Srte+Y6 zkM};*ZzI}iA-vge+mMEYk@pRa=d2T$ zUZ?Q-+*sD*c3U&6`BSH}^MphzyQcVTdm@GPIBQ<`)--H2GDKGCLhfRi7<^t5MU`Dc z^4*F;4KUE|(S!L$3{mkU!TAa%l(4ZHIqj&YrL!jSG)Er)rjm(|aDo|Oxc1}oMAOV* zoZWz_pK&o5Ik>-LA^2iMUdzIpsw`uFD#~3q#&Shp@{(&h=0m}!#pPQH#q5^4V#7=W z9lBVSVnecK={u~P_}od0^AM>^*SSk(zih493QI?e37x2q+~OQ9tL1|+736b4LiTPF*-NbbdwJg)U{=urCv>zB}vbYwQ2GS6`S z$4={5souoKSA0m?G?OcAuuS^B)|r7Wid@F;XJW>S+>4fV4$kd{L+h6l-ozzZ*dbZT zURwYb1LpOfNsBX54hN-DF%rvfch<#us!FGLCh0`BJVsCQ&{#PM%YSl^Q{{~W%?Z)l z!#trXGThgBLmy|U$X0hmrb)pdKjqpehwt6Z<)^qa5S$3~6pjLvbgi7UtzNTcMFk}N zO{m*jdq0YzIk-a>NwQYaa%Lgq%lhtn?I5SZnWPI|e`~D7^Qm0lRaO7c!5q@1W#nF) z0(J54SI`cB!VU~UBO@Q_7JYL0JFIJ7=bZGkLqF>aE5{Wup{<@SskAmzB{6?-aoie& zBKxd8Ceu12M)d;o$(Dg=Ebn$g-Jp;h=w@!rV6UC2~zQOjvz#+e`f5hP3;5)H|# z-)$c@wK+dT?1f=CzS~LoKXC{Ua}slmB8J~1}M79tZeniIFXMicdX ziXf|o4CcaF!2lxTsfpMp`p{9;U_Xkor{5>bUO-+@B08NRZ`jH-ndW1e#!VZE`DMo| zkBRPCWv~Oz^2$5AU$0IX_I}Dt$SE)(3X4Rlr;#V_G80-$VQn)J;5v#6B_doi;P2qs z=?qpl+7aK>y@_jAA!sLFsw8lh)9qk>X4+$23A7*8y!e$%KksUB>%(k-$a_~!b^+b2 z1A04F$kVp`)>@>A`jJDvHR3sbs;|LLI!162?!#jw_k-zVWlT?gm+Zii$UMHa)p zK49LX)l)O|i%DMD+{zmusvwkcdVR4I8OpppQkHljcrWm*7v=LFN*z;-51|4d6wl0* zbhBFdMB2${0lcKTdAEV;_-PWdt<5Aa2~WA_L?kmMwU`ibGl_*qf@5T<*&@=^dj?sZ ztD4?B(80=N?`PBqJBf}TtQxK*0y+6LAI80N=w_N~rV)FaM^jQqYW|XdL;5Uv;?<&% zRtN5UltH_*z02|wJ->Ke2)g?@WWW?l!f-d3_tQ=EnKxH~Hr?c(hJQjub1s%v3a)Y9 zM#uhO?9S{j&*J5jKS=)2_?ya6oyqpJXNAkg5cK=@{^9pM4e2XqE-|JL&$3ZI(2g|E zjGWtx;XN!P+jsg08k%#$6=8uL2FIcPi5a|)Az&Z*1*Xptyx&q+{SBv2)xszns6xH_ zm4a|szboj2Oj&L(2#KThwSpjy$c#O^nV8{b4cp?&Pzc~18pkT7Rbj}r4C;g@$Zf#D z@2(}nY0nS@PXl(iX7x%j`^*dIn1-m|^nnwl?2~p2CFF1RLie5#Zu*4$#f=~L2`qK< zM^YGbq2Kq?Sa{geAjjSxYEy{TBmMQx73LmeB@{6P1t6%oyX9Aa zqmA7X&RaES|H6Ouo*7 zq%oq~(DI}V3S=$x)uCf-CGNMKyY1}kHM!uJ2Ra}tX_pgdaV9=Ls752Dor5>0zr1Vx z+%!^WQkw1O>|;JM3|Bnt&yqSUUO|ydSEns_ijhoyb)&HW$B~lq`&M&eeIA<0gCCS^ z_n!c;bI>gg>?%+GW!Kq*{|FjCB%h~m8Gm0Xqlq-b)g~GwgJ59q4 z*x72>j`wcd*#E%JLXqrP#i{b(0#7WGR@+NLwteTpKw+jPPs;I~A2H))_zsB~H+}=f zlYz)k-q6`;5-8rAV76BjN;^DQ|3Rm;>AP{nOI-d(%6Ve8&ML39c2b_O6r6whm*m1N z!N$G8G1-ZtNI@lrp4qo;uIA95NpHV0#s&VWjhD)%4Sw}N2baq~7eZ`&>T<%hF2VdR z>f!v}x1eJBeEX@o{%NWEtx*;7j;MGTrw=E3XL#a*e%+K&cC2P>?{v0{X_?N?1Aw!Y z7zPGxgkc(kq_bZWHM9Ua@Rtf4yXxY^yXgxaht#rWp(KWBngr3GaU=DoW@EP!-j8eE zNzf>BP)2$bJG?!aVUbGsqh*g=(oHO#s9lYZzE(B7ub*>IeHQ_ZC6UY94*?E?InTtR8eHDOuZwRjCL;(^MCUmAm4x9fRcPyg)^GPJc=!% z>JHkdE)mOioR#vPD-?EpMgEXlXJO)~r0eivcQNE_HRuklrrhfM@4~mY+Wr53q_Dpf z8&!VLa#x$3Ga?MhnN4v=Pt?qLGX!0Er-PlW5NbxjyNWK7J{gzq2DAF_E0GL00#Mm#(A6DC2s%APfzj^jG zZR|9TQjjPDawYcpx22L*(y!aPCJ+F6gI0(`g`8MjTEr7en)j_fZ{Y#~yiL*Evb*$S zsWZ{Zqc=0|O1U4(`HA|7v0jgCT{Z8R=yAczO41(=`7S7PvUdB*RpSo{C1vD< z%Pw&1FC-w6T_t#o1e<8f0AEUVbxGk9nWSf;1AvD&FNgTc$THQO0s@Rw$gHH+j#8f! z#Oq<%lghSN*Zrl!0XbIqd^9=)WtlSbRqZ10QoqY>U*p&LK>_>8N{cU0A!Uw3GE zJ?N@e2Xh_;RA9`6Zl9@|M%^u_9=}HG6~OkGnU9OnPbjl+`$t_V%-XS+j15;>7vW;W zkqa@)+{c~onpde6ZTMO_|Jfuxn=k{YkTyFfns6dAU`K8K(vv_rof-H z3L@mF{bp&}?h#_w!=iOj`fKCJl%!~D>ud43PC}30$3IuveadTeynVAQ_690i5>5|; z6f&aO<~ryKK5%rb#$S~+Wb1qcn2ci~DHB39E!z~p=WiXr3gAGN9IN{Vx31M4UXfb> zH~}V|#Ooo=ROtPe1;0$GGfnH(M>A)yX8aiPJ0Fpudq#bFvW`en$QrxI@IP%}BlTvl zvzlLaj=8Eh%#D9hrP#nVWImotrP)UOXrO6B{O2iUVg62Q0s?0iYU zrwZpKQE}pidm*AQP;Q3zmZ&s~VAgrrcamP+d}jLitM2NCi$bG}y#L>DuWObnfA=g? zc6KW$+bV_;3bykd!gFkx5n_TglVYDN(Ub9v{65=Diw-0mn`mw+b>G?_7Px;2?mXW9 zmpFuQ6-e7~)qdo?ntq&zwbS}nP6>dw>gHgwGU7o~1`&Z~ zb5v^NDn6Tid%ZYdIG%EDXRm-p)m$oYeI~9AU$lR_^>;z}%1_3xFLVQjTzsn;3{E%t z2~)lQ_c3?8AP#P^7I|g*tKlfrV?RA;1^YWC zzl2II__-n4eSYLsxM9oEq;jb8bO;5w(3jOt)QD}))q@tE_{lEujbWGv5_>c8SA>b& z`2}uHeX=A5>~2+h+hUJRWPNr@8ZAm}5&w^=w~mYI4Yzpr%rHm_2uKPjk}4%7Inqcs zNGc#*(mjBHA}L49_U{d8t0?7ttmiTyn@l@F$8Q8w(p%KW2>9#~%sJVlGC)AbOY#dT%e^tfb z>cdh4h!-YhL!_e?cpjRJn=jH&;1ik95#4a05vUqb)+crL7LX?3cet;h4j8LIfviDg zlqJllw;Ug3Zaw4PC-1kTOa}#?csR*c6!%TdcXpuau0nSS3I1$+@WlbPKJ0vnY(Tec zSQVeZG`(zQd`?Go#rerwlx(TpF8oDjI4eW{^4-S0^86pQ>@(bHmxuTy)p@G9d(igL zKM}oEyIcT<;PLo9=0*bxS1F!Nk5$* z|4mjaa-Y|$|0K>55lG@4voyo0YWs^tOZ7<2PD8vOiCAEX19-A zu`Dr0W0#57P4P_V2TK>LmpqLq!m$_7F`PR!&Ikj#+ce(ad+R>JD-sZc!NIUZ&#`x5 zngG9FB_u~6F!$=?@4FjrgcK0v_}g8++GcPnTAPj!#Jo$r8i@;hpBz)<7!P}}O&#bKRJnLsb8-(`Am)4}5BLXLMAEDpK- zBNrzbNZfv0Cjvhv*;fmZ#x~ebq7wV|J_0;ESvFO%3x>bB=dQGRG%wobd*wu`eY8Blhh?nIV$0?*Pp%TciS_XJVeJ1Syr}$QsB0H!X|Fn`H}SgbkvLu zN19fcvtFAU8zxD?pK!C>Y#;)j+fj);Z1>v8(%IDQ`~lF50}qx5xScl&2iXDnWIrfG=fAmwU?uN!mjI zxgV_)aIW?w4f(S`^tl292F3#n(zQV-K*dGot$eGb^}_j{8i1^$w5^t%VfR^4+n24s zgwax*T^M??>};Kd-nL$ge2l2Mk)ied*HY7AQI5&*x&~}@5#3rPOwezBAG^NNkLWb} znF86u{d4v&n>|9xhp^Mi?XS8b%nBVJa*gD)j(^`z=Fs=oxHW0vV#mI>pYPM5p{t4? z1gFE0V`bO(cA=$wa4SsBYukz)uT$yAyupQv^dnN+`u)1SqxtL>ht5Z|d)HTo?BSso zSxJp#Y_)$CO4&q~p=zlrKoBmQoA;GZE526eMU8Fkzo4$kRQHv2`>oQ>KwS3vr~ZCq z25vu%PKdv{!30~kt9_f+Jn7^UKI&P!$}g271^5;Y?3Rw>u2gHTl6)UN984r)c$6(~ zS$TZ2?@l5wEYd3u@n%k370#zD0e}Zc#%*D7qhfDOh+9*JUMvg8M-p=wz-9UdqMjXr zFP^}wxM6e?3CudQlR8x8UKsd#d~-Y2U6|g%r9nq$Pj|3jYi$JYv#>0!=Ag0Aie za1sZ}8Wjw{m5WXa>CI zgjC*T7@Mi>fGLF6XvYZcc`8JdHK7^Bw3* zc-L8^Us`3N+cTIVEpxXP9gkK(x$SQjBTK=AZryhEAIU~H6 z%Q_~iIpBQe#(n{c6Qfdwys_7zN5Fxjv6Cm2I*j3s0yer@oip9b7wJmg^>Df&CGhtH zl8>7E$k+`&PL}c7Qmgm7ooXjITQ?{fxUat3zrT0ID|BUKa$rTPCnzDXIE>hp zs=%#m;S#+gh8ATKGUV_DDKyLaqaXT0`)G|TJ6Wc;r^*Gb=W7M^y#Fl(5@!)WkrU4o zNq;NH32&=4xG5JcICxa^0?Lp*zFr?2!I`Fw3!ZR96(r{}XvG7RX0lQ5z*shxQUXsF z3;?hJHW`R{30V^v6H)K1jc<-L-|J)ytOv@9*kErm^Df^6*#L`=`m`5d`x3pKVWZDi ztVlx)pmu#X%DtVTssNIQB|TNdjw5eaZ6*Xux;=3BtncFp(zKwn?)G1C<0A-aWK_}4 z^W7p%CcA4<zqa?g2qf zJHy9IG0~WIty{fU-YlGp@ zl&Sx8;2eKB|FI`P=@mg03DJIxcbkj%=#K{v&}OY+Z3jV4&`v9h88u_r;HGJo04S+L zaZ!V0S5@WX<{wqt3;+@zvW+cumCJ;wP6{N5l3#_s3ixw7C+Nd?U`AHI>ip%R{+3qc zI?iUUDcgVPa3r#I?dA6x*>urgG|hC7z_9(uH<+KQl5nws(31h*xxgq+aVW}a$)C6- z>xI%M@5_@wQ>Ijs1a3C3AakEqkVOPoPgi7?z^Jk0;-0f1P(d6PBN=HZ+ z080^I%_1EMmL3emABBCfC)?l*C_8 zLxy@%pLn9P8^Bwngssk^3`H3IG=LpJhd#TnE#Shf=KvcqN=k1Yi<#cA3R(>?j?H{n z{C==Jflm9=Vk*-eEQYCCkZ!8js!AY`u54BZ=fQ0I1y?&C;D8 zi@UuB#ak9&7I26<&wqr3BFk<_0FE7`2ed7$(jN8{D2)OdWPBW6&g!hGeVqjAtuy#y z_-s5gK*+-eh!~UDZ%n!ARlGDUzICU)LBH$p<@JR%07DUQfR{y;)gki5#NXE^*C>83 z>F@;ZSM{|V&}30h%?ik5&3|!;*qH>L`#@83Uwz556#wxUYQg9dA{bV{UY-jtS<~d!3~09 z5EwV^UqeVFIN;>Jak+#p+)*H@~1*sHWS>)dseZf6Yz~A;A$MY;7z9`-Eu<*#e&X8!|M&h&nUnVIuy_K zZ_<8PGOpwD%x5!CxAmM%kJ^|_Py6b2pt{Kb8E%$NWCZ4;7Y6j$)fT(5kW^SQ`j?25 zGL-NJ+z5gUx<5V(brSqVhR`v3>;cJnO#8fhJ81Ci=0xJlIS9dvqp}d42HZf$$rTfu z=(C$QK`_Anpwl#ym$~(201j#zSWMZtoHFn&V{t}a>pZhZ{f4HCuW(J)d%E&pM6!#7 zLQ+}Dc@$^Q@IL(ZBztm2+Uyq+>HB%0)7&ymQ7q*dFK~7Ft|s^^($4^3hD8VCpiZ)X`h$n~ zBxpssRA3_B=WH2M#;5cYkY!*p)agfs@B;`k45n;~rF~4<3Y4&75nm{?1Cd~Bp*=gw)r0{j~m2jn!hri z3~5%8?EuuHUdNETT}$rSGiTLEK_qISIQSTU+aYP9H6YF*pngw9n=vC)vK8BE#(*ox zrxG$GgH(qhH8&26U4WD^(T(!tn_FhJ>)Y6t78)`bWM85v>h?Kd+K-?PXqp7Xd%v;& z(8xF3au?Fws%`4l$C%JVm%9}H8kRH`iW& zs!K=52z#s9_7^OSNN%&y01N%=% zqb))%h<~-G?|gM;kS&T%{{dXQZ?X(90!_z@PjzDNYg6D{51w}=R$O;U&(kJ3KZ8Un z(4p;$i9l{#h7>Y6T?&v$c!RMeY;#!DRP*t(E$yi_mKiQ^7OFgfiT{2fmjlK62%&$> zIK&&n@07G;;jvvwg}ZPiHr>8geRBGD&JGH2EAWoJuQSML<&Ju=_Bt1Nx>IV)&R}?b zGO&7Xf0tzUMSlqzS^LzV31EFwO3AQ=CTVRGanup1QBbR1fz9x)*H}n+qF$W8nX4!~^#B zLF|RX)0h!_yP8$ULfD`+ZghAO*&S@uTHjagDzx{Rp~p$5rOk#Xul}5vVa-aa(3)-5 zLiP&}<3b++Zyp<7lzi+ZUt~S$1}puyXDCs9_^V=%3hvO~rL~rfSe1lyr9-lwbI; zH-ay>>+W2-&H~6BlO-g5mb4MR9w3gwhvQ-Hnqo-IsPiJgSGd{+2SBRq&b#=6&GQJ{ zR0sEe&J=tXKR~)DRKnWkG<{(c`bE)DvJTQhShC^qcPUuxhevAD=DrIF;z-s$D>VUs zXxcL8HDhXONX2?bwqs?sUU=MtKv!Kj00P`T*BI&Ye#e6AFSsxNWg&zBd<X!CBx=;L^nf&x)prb?3& zSyGTmW#N;3%%FH?^<$P`%Rrc%rl?8gaWIMaRQvmO-8vk(KwPd5MU8mJ;?XQ0hyaHN?EwxDaFs`)K}yh3;p@`7wBSS(C@Y1E z;!tnli#3iNB!U8MC1!TxLZVET;tmR10=F$n`c{|mm3gxGa7tNPB z9nh6FF9`R@8&6yGPLD#nOu83e5HcIDrQFtaZcUltU`$?uky#@V+=e@)#OJWJiB{8l zH_v6?J+7YRYA)`UIY_dKEQ6LMQSbJwJSsQ(r#L*V_Qep{E{qN#X5?syp8K!{M_y2_ zP%c;y!$<)OacsFfUud8$^jDo#_wgOHPbvi(%(;GBWv#RMkKI$}BctfWency0`AH?8 zlyyqIQ~7fkV3gKFcmArK*+j*wS*{ZbgHTfs=eh#_Nz8-5yc~l}APv@J<-YOv zX3wUHDuHk7p1EM!C+URwRkN$khEapdPMFi&A^G=H!t;96+T)g{#WKFY%ZXVE8kVv@ zOYhymZQ2u`+-WfJ_lyf*l-zd{EP_6r4Ox1HshAmxVcuCOvcsYx(tG^L>Usu(DN^zA z9YzsG!5LoA{lVZnt}COczZ|{!$IiT&Ct($ABG2|1$m#6s95)ZQyAlZZo4{5i^+T-y zUZ^tBRf{AUL9Hk?6)+NBMS3>C(VIw|Zk@DV^~U6Hb%oG-u$n^X<2XHqoGJBYRa{P} zW!%3QlRjl)062b?3piFNaK3>9)U8>c6eOV%-d5V0cQ2p)ji$d}sX1BNrkpIVxx7q= zVt|+zSaK=d;9#KF2(L9Mc633$1@!%2ccon)?{Z1)u~T0x>#YJ+VIwMNksHPrn-Y zx9d`Pp;G;Y43XD(&%Xe~b_SVIV}1GJJXg-Oj+}apO zBM4(%)$w^rVjo>qJ-g>Vkw?4Cvkzs?FAnm#xNws~R6P}kH2RsH2iJf+x=GBaEg}=PE#Dv3eaS?5wz9Ludw+` zL1)d#`9~q~dwx0G#QGn#wjkF_g)W8e6@w|X2XD)4?ztK-Q0MpS#`ijDukd*Ic8>j$TuM%t@NT+ zk*YkE&hMA4h+4{8gF1?)HT_XD)$OHLki-=|OnS|*<67D?2-;y5V}+v3!>>0{Ix#aI zh0eq@@y?4X7Jxhk!j{Y@URDyaJog~%U=A8K5*!q;6$}7Rd^oNRFH!eqSju^H9%_IJ zJvXJ-5ektMPA+$Ro&i~~@tPp%QP{9FqPLq zD|XEY@vl~yX3!l&X^qeFwpI4Ogi6q+yiSu68tun9)|lw+$GH`r$j-7!)%NxF)H#tD zplW5g7p*0W#X!HM3&St9UYA=K4krd8B}froios4}gq>QMJDESJ64FQmHZ9_iP@App zgcB&%S-{tC4?C{G&t^pkU|{4L@yMKp_WHwpv=FcBn1|@d({O-YXoBeY0SK0!8O9|A zavo<+zXH$TAH}A*NXqgas6&C}MqRu5$CT%stqc-3PT7*@V-p6%VHn3Z%?SalIL_Po z#Pij%%!{_;{hY9lfe)!>i7ZAe%DtiuR3>s1H>Gw|%F-GD@A?-m4}U=TJYd*!9r-Gj zM@FtP5C>JhAuT$`oV_6~44~N-&FGfR<^ksPZHxwhJn~*>NbHvBVCV=S4A;H(&7;MI zk`u1!QW=<2>8djMuE-6B_RT{9f1t)Nua{AA-9VYj^eVRz3y3*C6mHHv*$_Qb*1d}O z_^eLL%Gdu%kwWH^8fhhnSJgKR8GsyzO2AhMs_a4w&@o`M;O^=&k(5Aj^WXbj16J+r++kSYO6h=tKxB7m$Q}WiVSTRqj;(948 z)xPk8o|vBmKE$=f_;2p>R<;3<*f^mEi`0z$lCDR8NhA|FHRW=4e+c}D##na4TPGG)Vx4`iByzhpQJZ5iB%#scwE!$}GAeIY?=5c#~0S9vOi(*Y# z0d%HH5@m%-7@*<|VoK{u_GJIh3$Q(wg*;S06&t(VoK>l|r3U}>Qy?qAlhNi41%hrX z{gC{8^Pt_&J{3r_a9hYzMy=^;;DTzX%gZbLu>|myzv%5s1z-7x@F&2Y*e4G*gmxmC zLztXmE&hIEn0V1~Z`&bnlq~Dx&@kvK17g2}Vxa!mfiDw(T2yQK7BaJ<3Y@If!l%fqpCo~q-@_h zu|JJ<+*v3k3T81{lPgMYP+DUJKC~VI$PW`oJEQo7*F4y}y4gkEA{k^iqih{{{dpJt z27s|u>tK05$PbnP(x?K+O8e`2N@10G*}KAg_QkZDS?UiT74=09Zc4XeIEt%D;W&I4 z-FG(r8&vQ(z@|$>E{?Tsihui!U|5h@7>Tp@v-?7n!GRNjQhTE%RmpL0plHIO4p4`X(1m8!Kpctg{w>NQ@F*~M5y#(`gEgy*l1I;D zU}41coOB`(rl+p7e5WN{-@WF?^&`@T4?nG=E0tbb-#s#2c%c1dOLdV08+ko!Y++(T z>F$Wt@!0IZ8H9sCzqA;sM=TW zWb}*C;V$2!rzN7CREEImx~5Ff7ayWaTCxDzDLR>+wQcf;oF>Jk+yT4Iwx+y4D_ zh>?KN=S!ZMEHWJOQwt1jCKJ2py~cRr08ED;2J;x+51m&cAxLklyJTRgxSyYTT!$>X!z=qzoxRTzMAwQIAi~6Pv?dO(`=N zd88HWKh>Il62!N|1r|AdN#}?$azvX}2_hWo-GC$aPVa4T{lzuR&jLr#5_v-l%K(5y ztt{vh-bL$bei{lBC|gRt%LZ&E%6f4pLfUK>_yCa zRa<6s)Y5OtAPeu4Z24#@y}V8>>;NvG83X;^ngq*G_k3f;ez;BVxSAv`uA-_u^>PNZ zDW^0R{4(p!cbII7&91-J6$0LH4cGpUrhk~riKr8pWiBO!H<}zMrN--@xhPOP_^xQN z9C$o-+R{6d21GfHy7qv!*3z3T^(ePL;Q!4d&LqRf(E0F^0ZJ!PN47zR*$JW`IJ`LA zkdT_QrT0$}$Iz0~Boi3Ac4hF+PL}{xxH}F~vIP7M!tdw`(-UNDeH!pr7!EhkotO6R zos4;>z07f9w|t(iC*G2W6+Z$?dA~Mc{ra=d=}KoQXx>Tj2F*J!R=?izVk>S?Odeb4 zBI%((m}anm!2`OGrdRAAYSIO%c?@`Y?Op98By=wIbqT3zk|*3x|hdbRk5I&Yl@KXinb#4S!q< za1%!6VGX%PTO$>Gw`%`q76wukWWaKJ=i83t_Wyp~N|m6lBWlVD=kZAYoScFa37u4{ z?Zl|EogH$aeR^otloHYsvO1jo!}q&oI@_H3rwE5Gq5Ub{)XeX1qzkC%{18dqvI2&b zm+sE?2Zk;e2UWVs9uFljwIwJja{WY4ie05uoOLz~i@qGzZl7rUzu1(^QXL?&tbcFh zwv2cXMZ9}o0}v|Ae+t;xSQ^)z&3SEW3|IMee7^{vYUF-3E_!R6vZdLY3ce4Tl^s$6+aSnHTrD+1Gm3 zGo;a7tV%wT%@>1h{F?LM$d~ikx(^B%fT4klOEL|9e>{GqBim+c(X)TkU(TCxfw+4< z>TLvdQ!+?idb-X^?;qfJ5hw#D*vCA&7c}@8X)Py?h@H8l0Mr{Q|7SQ!HS^F3l!I|r$xF=!pfJN%NhRFPZTe>-gB8&G0+$3rckO;2$tXIbl7z=Z+<AfvDSJ3kY*JthJ8>)1YR?9$bMNBru*chMyGOlGTV87%V6$cL}I2)5ds`-6ZYo+ z6K-7o^^Qiw^B3q)Q;Qos?G8C;PQ#V+aqVPA$mDvY4Ulh54kQ`eljq7v^V|G4P2|Vn zNfo-FAYA-hEsYKSt=pUp91D>7(~p;z zs`hD*gSW3Z2l0T7dW%{`P=L%re54QTs^}g`vS#MJMN&FMMXj@pcQ8r+5U^=HOHgWO z`2Tz{MfXzoeQOqyhO*+EDY~$Y_deNdvv9w8vijbbEr&tmvc=cK5bU}{EV{pOgG3a3 zYEgq&gF@v#1!wy~#_~!qs49i3je~a=88SGWJ=P!1TSe2GFR^bO_YEMSd+PG<%f8w# zZ$YLX0oz}#-oFaCuaF|l^!(1rW#Fw9W4qYHiZr-kbp%b%#sSdEr+^FWh&XcRXS_Pn_CAA#&G90G3R)M|u zUch{j8nb`je>IJ^vSF{KpKHW0Pig2iOoo#&An2FE6u@!Kb%B^R)vL1RX9YYDR&r^V z-9W^>+OA0vlU3HCaGTzomLCA{QM}+_&|h;hFwcerZ`I|rm>+mP3Of~uNVtnId*X0^ z1GHiEa7+bWlJCG!{{Ze_e)C7PR-{CZi#Fv(3D|g0WK#o+r=rJG z9d&EAO(coE&0lk*_nSJbN+8bGfI9J|Lr_76z^C1j+bVA;gaXD;>^(l02PEh!AL)!WKkHd zfxgkD(wvg=LQkGkat?Pe(Jg=QOghn-d&pxJ5OV7ru2j(EgEiHK26Mog70wm5OfHc0 z{aKQdDX)j|5gPe~STjb_IDeS?b4MHFR7;1`%xGTT^|2gr@b*mp{;;ecg(-2)cemy5 z%3`81=_;|OiJx{HBVcj1YR&$B#}9y`uQ&(`Sw{Rsw?4f&W}cF7HgQ}fXrFzZ^cQ~w zh3~0b8u>vWAh9py>@j4IZCrNFEU6R+h+jZBicGpDek&pAdT(wGhho4eD{!_!7p+%$ z-wW{UK?TP&+E%(X$CrD<_v?R$3HWNusEtcJHpx01YW$CRU00TKFV?Zb5%+n(o1Yh;wG?ss?& zbUH#8ihwM7NY=w@&pTN$3dg+{M2uN`A1p;z{pF%BVboy=ICSjCKD;ZK%WRv zDLg-}AP}&mfsVxVQOSRK7j%vTo@SlBCHj3DdZirn)c{Bi zo`xZ~N}R71h6xFQpFLP5^MgN6E1668%haajqf?mRA99>d%XB7y>X;bV!#h^} z^PUF>O`K_#6KrOzfi1K@bJS$OYEX5Wfj?iqZVGB6H|9a3S~x()i2R|ug)J@tfVN51 z09xHWYHh$(_7?)Q(?*NLS~9?5pr{6{5opMj>_goq(BjYH0)f(^Dp z`!J!z3$Rj@vbm@lPo;&*dry*9vKw_DKFcnuy9sF} zuAeS3Dx$2%4oVzn3z+9nm^nS*8)oMo_|K4%BkgAnTU_66(+v>C9Wc4ScIcD~Jb!rtBu^YD;p>OD@ z*dG`r;6{^5$N6D~qzoIV7fr`|=j}eFjLNldHXkMML&n5%*Qlk74oZfC zMnxTN{PISTD!l+sol~BfY91VkCKfV7#hJC#rgCO+*CeyQ32qYh~B-{Jifbm9)Fl~4XO-JbL_V&@b zGOEExQ{JK9A*dBaiqydz@HE+=9)w~QW?zrNDJhtbF2cI6&2U0R;8JiPV;1=SdJ5|U z-S?G@>R&ddCMMj{{_W+N4CA(=$Eu>KZ)zlrxf{a`sDXL8%!eyA0*GyCcXklTP$cqD46Z=eB$=w^^)oQ9~RYmZA@#%WeBbb$(PC%hSDwEUw~uN3XOncevyQq9VCnK0%Y)q zXVz*sn-^!#xA|TAlZ#Jm0;bF{#Rbhq;^#5F2GO5Y7M{KNg*GpWu8IV-`Q$3i_MuNy z65#;S-T(Zy*Hx6T#n=w7>8hD8@W*f0j?>gdR93sD5;;|{pZEL19~qB!vKI!3D(P3- zKj4JY-QCWdr9_a1shUuxjH)UUp3D5zA4X>rjF;)YNYRBwYW+}{ONBHwzwVPw%unWk zG)1Z;k@!T)%B7dY0FhHkq0cFKM%@w18A3nrzEjFLp`y}UPlg6Tv7^+ZfmHd(!-Ez1 ztS|w>q-9l3en=n`FFdTW)Hd6O6xeI_EXt)eG(O*T^AZOKo$k;9XNUP>Zp@zyZ~i2; z6cr`~NgSxL1e$JLl)ck~0*^Ys;(T$D&cod{--f%-%KQ2Jyj!}ciZuBYjv18T&@vCD zVg*qhuKeFL<9SsCE<3S0Q7S)^1>QS{Wu%bf5r=;6Ba;tXaF6)&flGL!$U^X^cT}xf z-{7d|#V_=03QL`p*8}=$gfJ|JaIc%I`zT~xJnc$BD1~W_lCf|@uupx4R7xSn#!rH9 zp5!XKn!orC*pwJwC|F68wE^TV$4x*y?Qtv!keU2#W@mC!lLiI&OGK_LXU#h$1Sd(f zS(5ORGwI$&+x_$wy>_`UE$;*OS#moPa#A3z*{a@%bKYXK7t_43Xy2au%3Aab=h)6` zdfL4C@su`hcyUOb#%}n>6p^2&4D?Tk0mlqo@}1KA9nf+~3JR?FpmC;tY?*?TABU~p zgZ!g;X587rtD&4fMOWK*1w;kSgl)=2oK`d?iq^xs-3kSo520z?pHA*MPmf@t)MQyc zYeY8l!1}(ui;g`j{^N^3R?q}Tm+wY9!_W?UQ*u~=AAgvE*W59al{68}GQ|GhHDjw3 zC{AIkc-f&P>FGe(}_!q%XPfj4Tn5t z>43(d*;m8C8s&Ht4f-Xr7a+D#!+Jm!+6WYP){PcsccEXTbLPoKAQB`PQz1v(?jAv%vCg%d@nChT~nW6);lGlQ`zu2PG9$1oMQT!07N2 zE){;anQpDC##skcX1!QOXOt+yi0lLnwCOK666VMJkqRKb0t{n85A_#@= zV%=Fa%YzOD=V49KFunJYdh~2#RS4_7Qwr<*@l}g-fj=oB+bki{uiCGVyrqTvqMg+x zjWn=oI&qJ`i!f_}k$yYtZ8iamP0qI>N=YQLkQlP8^Tf^Kux_uS`mG=0M~9j%OS0dX zN!4@-H29|MhYZfPeacfQYPUHeVp!}=RE*F7(6x2`qn!FS|3UIv`oY!eB@v*k9u7i7 z$@SvGek)1+dhD!0T>vI$y9m;-_bx5PZU}=T)#CWbbQFx5)CSW1Am~n*g^$MDwF1+~aYzHDFL9y!X&EfZLwPhV3 zZI`NZcp>74Srvr8jQq91c9g6i0a%mSX%70ZV@JUYQ) z>uDl4Yl8z}ht;-W)HBmh2`h38QoXeYaW^;a(fQ?%R;e?j5e(XtKX3llPiqhIl!*W@ z_o=DvM%8V#SClexZy3+6j`%crL2V*jJ}6Sl+vG0LGgsfk6%@ri{^(0mHNKOvq1TyU~zu4>>Ys8(dek7fmKcX*r$V(RmXMdx0Y@%#OOn}Jkff+kZ^OCl8H>zp> zCexE$(EqQ}O2=QcH+-$LQ7u#FwrjWXV{EnC;X>BK#l)uDy%Kc8OZ!z}AS9cq4a!^B zV|wsT-4aW)-;(Nrab=4Bdg3punC1a>869o>E=795A(h)64LMdh#+{{j@FY7NK>gp> zRcdwUyRcnl=}b-*(h!knx}A=}%ZDZ2p34>q-$UHCZD{KTVq!YqxYfVXl?{92gmSW= zU7Si}Uc+de(7yaprGYZ>ZA@X!4_&dM(WYVm8%Zn|r47{@ZV!H=%ZE?iGQp5hGoKD+ zz*eWEA7qe$AbJ?VX5jKtadP9+wwStfF2sb{dC&h(3Bg5{BQbiEx`+EoS`~}qi-K}q zT!Epi9U-QzY3gjQ?fCSWjLE~Z{%k78$Jz&I z?%2m3h%}tfZfP=?$7qCx<38$bh`W_xycKD=FeveDn}wcAEin14UdDJ#Y*biW>^Lv$ ztcv{S?}>mC0Y+{qUTE)L#jhfp%t|_5`4OBmqu=H(xYVGFlFVwo4k04$iRBO1$UCXD zI#&sucoJ51)R=yk0U}{pp z$~u<3LivD?)I}45WSf8U>?nnAfvelkc}mPsVFeoiDgU$pV1!I6x1F9%KE6?)s^SxH zh>!*rDdc&>$cAO#7~-Ct738Ul;wVpLJ;!HfcvnG{!&L(Vw1w<^yn^?N7F*2p&P3c# zl1nT`m+umTts7&mm3|*|s7{()2^P6wNL%aNTJVGbHk%&v0xr|ePTS_jn--!eDYLfU zOqX;1@#}Xch9*q6^MsWX(Vf{9IH!;zZjgd*wpL=qhCA+t2d*4JrlgjfJS%&_;M z-meTHl<}YXzkue_n4P!P)0y#Ln(zf|3}(1dQr`CG#R`_Qf(^d^ko0SIIC%Te9OIt@ z|1#Q=TxwI8dA=XBF}RqfrfB)`(exBtCXJW>(X*Qy|1(`QLCj)|HwhrFLPp8rZ|){5 zLI7T!yG-U8!_{d5lw(_?tQfA#oVHv8Wu%72Jg%0YLp=C7~8i)CB zlWhO8e7!7lPvOcXJ-(^2f3S>M03c5xSh4H|)SKaa0Kj>JwmAIS#;g1F>g2HXTVVOj zYn!~M0B8}QQ-0_dX-ReLUF~zD*(1Rcp>WSS{b>JD1rdeK5#pG42peEF}P2CRaov~OWt%~?zn5?UN4T+FDJb{|f;o;3Uz0u#}dTI1{x7#~eG z2VY=sb(=)zhYMc?2q*kOzuxjEg6rq)W#rMP;4kerPs{!QnaPwg{{(~$wOuxyTv**> z^Sm~FvD+kqi=Sk@OlAI5^23a{t_G=d;t1LGA(ujAq>+@hYryU!T03|rBSfVmq`@qa{W4>hMYhDTCfb1Upm-zQ z5CXiYswKMf%1N|7xB3xwN!W1npIL6fiFikg3PdkQUfuiS!6A_cJ^I~v5UMCEUKfMU zr5F8wUH}D58yFg;o={Ww!=n_V-U&56q;9;KZfC`8ZY*X0NL_a_L&nKQgH(F#H=eS^ zoYb*kXGVUiGk%-52j*m<`O{Jp-&?(-55?H@f(>FLxII#v~GvBB-Gz76YHP znAWP^bS$sp1<>Um={vkDA#3Ucg0WyruL;zG8Bt(lwaq5fqmp*mwf95V*3-=5RXBpE zQEFT*f`V$M#Zg#(Dqgv)eUd2GRmJ;Om=5Lo=61rpn3Q=^L`XRbBK9b6MF5lx2pYS#r;Z36_M5N5IgHs=!)aKE`$CSLqi zYB9DeXQQDUw_Ry>5@mytmy-Yv$O{$5aRP^dYT$P?9#xFaPzlD`sl~hxklt}N;Pq2r zdb+vllvy$Pff{*xwnQLpWs|a3JCDBJ2Qls7U;}I*Kuw3UZewXIWWKy&7rYJAX^{@k zx)!?))y^!x(J17ouP_+nL-Ik3#Px-Z7uM@=6tSqpEq7>u1Y+|o6~La_kkV)o{Y(CLbWCGB z%m#?@%de125Z%xn3-EZN%@KO>ur1Ap6hH{ph5L8E#6&ezdx`o3Vfbmoz$O4d@6{3g zVy`3r_`IXU+%k3K|962--~>rgs|1m(B2$hdRU)>Xe46TY)y+CZp6zPgV{E`^)^#(C zPl8_5da{P@fC)hSXVNlynsa*F={f%(>-Ki50lVU@?Mhqk zQnSvJKR4U1WUlk>(hdtJ+wJ{)^UB{H|4#F?hwyBM&`%Vzr?`yQwr7(0mU#qSGNo2! z)&*}S7A`Q`vPIN3*sT`*`P-lUkgWblV@x=v(sd$yLxfF8TqlY5ktbr#jb_I2D)wcb zSGB(9F=Wu-B&8{5MSTDlfFNt&$fgQx&a1CJVf>E(g1>N!pKV)I#(5v8m$lFBlr7S;1oo&+pVUOg z1`pDaKOfZv6zKo1N*P@clE(vS`9gHTJKCJ@lZs;3;=;VX{s7htEZ=~$aHuhm(1#cR z*vi7OC7sr?X(*GvZ+|;x=jHf)mzefuG5OLg#rcGq>!*Z&3+*{V#QrrZz-y6$t>UX# z>h>RDFX`!OueEP9kfBtVH9%MI5Cy24?wsNbRd7C_<5Bp3*n8{0sJ1U|{LC=GAgz?- z5K4#ANDLv3v>=UKBm^X-nE?cqRzQ@N?oe7{XryZZY3Y!X?(gy5`*~j9Kj3*iKiwba za1MLzwbx#I@3q(ay_92Fl6`C`hKYQ#UU1#CD3G44NCzvP))S6|nqXmHo;MzqsIN$;vs!OH4D_m<^cPu5aiL=caBThlC*!LI-Z{rr6pd zH!(`i_bqAGyBCnS&rRepL7vn8rr4@E)2c6f8lTMoPHz8H66J+Y5>$rVLrB>g&0>m? zHi>%NK{16#7O)(WKZB@gFRz)@PcpcwT-sq|Vn=MGsJj~%LQ9Z39eP&2S{jI+xEpF4 z8HnD!P|}pCt7g(Xd>{lN>#eaR1ezHQb|-c^aRZ|XUjfvQcZNcd!f<7r3|UJOIpjB- zqN{igL@_uIOh+1zjXej9akNyg!+?v{?jP#}ELxR&ZMO=Wk_9Q!+u~8zYfFOMzr7vb z;_nMEsjM1QI~8}Mu0Jr9+{tk{OqE~_IxL_@Mi{;kVw3ctwJ;_|a>ZzFo3&+b`x0^J z8AJ;Mmx#>@MT_6$G;aW*kYf#xZ%&$eBdbpjStCCTQAm4yP9Kk*(g6qBF!B}|L5m8$ zj8<`t_mEh$@0Ql)qBu;D5B^*9x@BsW1}bN=X(?Yhv&w0SD?bha0YA z#m2Y=xLVM3yf6-90(2CF6|!JvOb5X2OjKb4_#7wZp4WjLZt8?L$%2p9jz+D`ztwXY zj0mS(rcc5YIrXNfq+W4Q^2U0#4K~M0Bv5aNF8M^F$!SQTSW9FPSAm-DhHh5mhyHsg zim@}Pm(NW+qSUO?-vMrcXxChb+?LOFXl}3emeQebH-bzq+4qoQn+>=i!9i9MXcb=P zb&MB7u@rd;K(~fB=Nc875l`q1F>rh-a~=}DN(Q-c_4U!5&Wu6daLLR!?&e3u5I9b^ zw!UPyeB!Z#WJ7gBdb6(~))=v%)F zIhqC^-E6$3#;^$Nf|bcoTVJD+zPd(ldncf-Vkz6~2?0u(<8w}+K!`;^PgyHFT4=T5 zL|;Yr5h)~!9S-AnP?-q_`$JB&koVzM!|h+Y=16@Z+Q&J>^{F%dQmEE?MEE~=pUGT z?)(VsHNJ;d5Cq{u=@V%8hpK=UGaSf0MS%T56-3BZn~zLO=6o7t2IRh^Aya16=okS! z=+MRhMZM5f=2==Ife+D|9opwT)9=pAK<|07R2O4)Qi_6b*hDlQdP(!GQ3QTD4IGG& zQOnF~+Qq1xlM!X zqPhMBy)!W^%NXW$Rd~G~j}4H1d~9;LD4lu!kPeUxKR@UKbCyo3qsA#epN2GsHb_7=9j&E?~l0odWS8iBqFTL5uk znXq^3I2h;TK2*_y9)18v7f9VU46z@fvE!}ui8cl*x#T+oKXsPqn>rNf0c7 zT06lx2qXu4HE#OP)X&y|M@rSM86vOwi8KU>712~zi(c4oB&^N|s9Mcj!Mn?+S`_s} znPC(UhZK<^O-{Gl&hH8Ih;9B-0{Uz++LX~my)F0GZTimlPM@*>VOCAFz>SGfSsAhd zB87JSs_nx4CmTyD4v>qkCpP*TBd03Q1F(SeIb>jAJ$QpNMnYVx;l>+zF4Jv`LR%b+ zBVg-kaiEl`8CR^BazX;d2*o}EcrI4=t6a=j1!Q1c&=|rG8TOAF1rFQk%`^5!MTGJG z60|~4PDd-{7T6%U+@0B|@&)mq-Ujuw3r&x)5fU-HdXA2-TMd5;fIQhUC!0?Iq5Ig= z-0}nQ(hTH^3r0KpS`>BsjuA3n|J)TadU-~}C62dd5*nO40ka9GgI$% zwSWl^mRSj0mr8rCko)|^Ns}u9B+it-c-U`T8G4#N@f*w0c;{d{tLI*=eJj$7-Wk+j z!K&`kqeZQ(pku9*LRFd6C!cfiS)@W-`aNZwNXty`MU>Tb7o0O^0tL-Hl{YwDVNi5@ zL+Vem0sp*};VWI{y-(bzfY8tLSyRAApm+6ft6tF}0Nz^;86?Z5=-|q8iRL%Y+rfI$ z4!AeTfR(EFWwH#IO9QnPwb}bkIs+aAZRJ@vc4)E3MFjWT)M)njZ!Zfv>MhGpd|1t4 zSIVAd%zLBs=yEQH#F2F>q{&%Ofd|5PKPxNn(t3_O-FDRGTW2f!48-=C`$(bL4?l6A zdeIB)4jo*SB(i~3_lBKYYtNo~*DZ{5pzfKL5PP@)LKI(byd=gkP3SNN_I+g~s>uy| z;q+wqNd4_mygX8rWVgZblXs5{9O~*y!*K+nBn+h7=aO+W5dzG;-ZyCRK5hH>L?3(e z$G^4)6V6ObMQ@@_E^B>Ux2$|8US=(N@7i1BEk`X{BzVzi$ryt`WF$24exoj{%w>dR z?Sa==mWpjbtaVwc3CGVIS64;!y_*&ff$sT7H9`{U0nv6v5X0Wm7sq|@UeZ8uW8fb0 zZE8!-z#1+RQrb91R9hgcQ*<(x$M4`mf3JpxS;@5JM>@}S+6B!Y z;b=|b>*;4z(YsEOm22d;8b3`l#Fr=8|8>G$a`NmUiLfAsMS1DCx9)<1g6)ZwosUsHbnUm!pM}jF&qyRWZRKnP z#8+Ls7Re~d*7Q~_x9VhQZ&o8s?Q2^3xG?+eMbU3tn6zK%1Blj06@h%Q-RO7|lbpO( z>E+-#sbsxHe?%`zCB$^)6Zt4$>y%0v=qq{592y^WkD;o5ow{>7Xq6ZJ;TGn51O`sF zHU*F2pU&&oOOUR!W_Ik3Av-?5CrPiEQU>WNe)IOZ{W4QpJ|0qLU(7sfzz$FbVnT-i zx8?P)#_1APK_N9l{1GN$v?FO3G?ocw`D+wk5Y{IT-1Dy~cRkhY(_IBs3Pzh{d$%GZX z$97LfvRBx=*k&6Qz(?E?yi+GrGO+i=5d^3goX2eeF#Zw=Z~=?9`L^19_sHk*H?aP| zwO-RlgL5T1oC#pM+}(PQ>1vTKJae4siNjQ5rkH(S*uvHM@f2TN%lUjTDc|;FRq@R+ zI#CA>mG-Eo>%-aYb=bo2>}&zl(kA)~q&xH9_B^)y)n{ZEFqCaY8TV-7*F)P3-lV_Lry6WB8T{Fy|+9)#R?J1Vvv< z7#z=T?SJ(jmkhAo+ZexacNs09Z2!5;bsea4B2#vJ^>k~JH5|X`T1)?6cKDis+p_`D zMrz)eA$AZWABNB5SLStrA5GcQb5Z!Xn6qcX^kS=1+Nk)#pk&g}k?vR04}&68Pm{e{ zrT+f4?`1N2_mTSJzjZ$HOWE4(?Pf;DO_3cBwU}pEl__y^&KpW1-TI>lM3x}z0IRs3G=~F43}%%1!DwjV2r?pSzwh1aM!pjsda6+ z^xF3J%i;Ey%X&AaW36Q@P$IE7xEv+?Ou}EfL^)_Tu=If2c2BN!7{lE&nXy{AA$y@peNy4(YVHJ#?F2`aC~6Ao&X&cg&t7@oWZSX)cexYgVwVxyDV-sETD6ce_1l1R#eLmyA&Rq6+k4GG=J$hyJe zwSjc5IoVLQj%KCXJ|TK&lN@-J`!JVQ&rZro%0`P(D#8KJW%@_>3Gxu&SD@HAEbS6Xg5bK$+urVc#&phASc{da^Y={AY6SLASny3G}_m!mwrNk z-uh}4bfKH+aPP!Ab*#%OeUE1nlC_e26Za5?G-AXH8Mq4sUp!6egsbyI@#*m+N|3gT zVV!9?8OgH77~PSW*XN~sA;zBcyKh_g`Or45Tau2$Xn+#h_JnF%C2np zK}&%;AMCOB)t^z8@{c9pdGwH)Kc05!JT7SPgP%4mGfIVsc1t~NVh0}YYQ_yPadlpB zW*g6{b7Bli%ye%PF1kHE?1G^KxLEi?}Y1HRYaRG+)Y z;X?tatMe1aYT)H;bps2fyXY(bW?41T0tbpH@s*nHBa79`V``?;-D^)YF)~cgl^$_` zML1830E56NIp9wvvuPK309LnMV>LM46KpJG2dSN%L2};>l%F{qiuP$B7U)W9@s7Y; zkc%P6ven9f^OEozEWU}_oj7LV*{(S+8K$z(zq52452cf9v`H~H z+Owhqrl3?br+=4ul7n{?yrc?O=4X6o;@T3 z4{cfCMt-j2roD4-4nfOI3t3S{mt5sDE1zClJtWna220ZnVWMXN2Y!PqBI@4aU=vAn zhye62V-0BHv(z-Yz@MyxtN@3Eb$j%AK3R^s`Kp_g?WfFw*k!qg$*h3Sk>oHx41#Px zaMjfGL7TI;e(Kq(Ca?mz$zQxzI?aziEQFia*NCkquj<>MuS)HlN-fGn;_n7g*XP~r z-|bOyKo>A%@6Od7CdG#{RpOeTPg-O5QD<%D`gUYE7UTU7!p5&ok_yEjt0~7pvqXxg zHmRq-!i12)=pCN(-#z>(Gfz1xZ*W}CyB;YR-4ShjSsIEWo2@}CF=GZKH-ACdaTIxxr1QUnOU^!- zRg-$XAtQ!TtKwipf?;uSuD_b!Pza(#pr&%^t~g6-6@2#-jdE@w4mUNQl(3pcWaZ3v zkd>PI$eiixz+O#IIxu(5sDB!vT?d`qr8LF3a80qS-ygdYaEuW_0w&nCTc5Rd-lY4F!n z2Jvg31cAuOfHs%$+E3?_Osq&-pg=la`q-s1ZSq`cGVYv-_%secKEGA^x@U{Z%MJ}k z|4H#z2r_~k;u+dP2k}t3_rSBe7u-G6(d`Ap;Ia@f`b^;gS~ju~@Ah3Ehyv-2xQ7pJ zL}m}hIg#lfBDT!dB-S78|#v&dmnD|9fB5ye)wn+|z-^)56NWw`Ek7%g?N z-<=npcCw2fuGG^NEtnmHBHE*1OpKhvJnu`a#QMX}4Vw1)+Lx`_6zjB{H&*e`@7Io(aFOo!O3KcF{`u|B+<5`%j5L0(4;szF{`!~j;fQsOnR{?tX8~( zosTBS*f765DL?D9XWY23&c<&~9p>17*U89>!`&zKYa`~8Il+L>-0U{7z4V7%W5^f? zrl;P~SZ9J;9qI2VZyuzTM-!M4xIGFjKeVSt8XhT4S zaA?AqWUcO9mBa(DP3`f+ZG*I_2WWQ6?Sw33h|J@SnuQIf$-r+tQkT9vjo-YA+_Tkj zp%PgK3z$mRb{+_ZtEuGIpF5QPdQvK%s6X8&fV;2Yr+tB7fGlVW(G(tfinLbWZbtmK z3zn9cZnI0Spm9|7qxGX3PXIGX)Az5B*4E!i`UXi~vf1TJ4(*tm@-(@$i*glXYBtUq z3{p*r-_p*m)3iG`xy&)0M$Ne@zTju_euo$OLGN^DqSCkD*Lo%q+y4806f{U^=;eIX z^V01fRD;|=BHA-xdkQoQ^_HG-M*%2dB+@2em)4Rr-EDv#RU4$f)v$l+_lgylwr5hO zq+_%Zk=ocrxm}qZW{|e-f50r=DiuS$(rTl4-$8f9?@X-sEm6Hip{#3;oUsa>6oRae z+<;5dzKD`A;uMrLewE&s!15-VCQP)XKl3wV#*yW6>D5JaTqozwq%d8_Cq>kWpRzal zCLf5^-Z#z8LGR&Y+(j!a23JcCe>!d!SS{?i4;=~nBV)ni4vY2%4}IL+)BziQ(@IhV z9eAJ`yI^GHmGja)kT z_+emjO?-148xosC#y)al_7IK>;r=G0%TBCJ!D{vdGb}rNDcS{+A1& z@LMRVj_-PMxft~VTo3AJnTbZJ+KV|a`>#Z@w{nSF{f26I!1(fA(!eo(FlteU$1CSM z31eTls=Bf^-ze(T#q%l>+-?<(kMwhw8P%6E*ykh$j!Kx<4sVArg9oxUB*{TNu0|m~ zGdBJQ>G#{&Xco%_v!+x}Ou6n9APg<)$#kKJGnDNSh^jjyZyb=>EV>{cc%(2HFeyOL6NC5whT3WVW8=UDb z(3++wcUtwkA0l_i2B$~H^m$?T)7r5TFn@cL(ea@QMIHk>hV}crU`f>NQvri#GBArc zXc!m-J6#k()|b+vPl)DpL(w&zu?UqfECgCDWLx|?-iaF<_~v9hM|W;k358N1E#0+o4mFoH$UK< zkLmq8R4^p(ncXyAvJmLCm+nO~iWi^O>}d8ii*0Nq09`6^Pl(YA<=4GolNEP?fOSv~ zBrGQpaP}avETx8t?YN{RaLZyDcX@!i?jfB0yfKCqFsDCz zSb48Y@K;@^3Xl%bk~0>iN*se>_)*{l!eaq4D=wS_*)|@%KH$`sg2@n|6;E}AW#l1X zgxHUSc}fA`Q1^&7cZA2tc=n^u_6uXi(F*p?Ie0-_Z9^yxB`8@>gbT3tC{H2K`|d-e z-8>tu<3|2#ikG7+wrrS_i2YZuVz~XMbMHPB<`yR&64;=9Ww9mmW&@puUk!|skK+*1W2G2=xf3Z;vx8cfKd>Z;j5$(lT+~T4Mmala~iD649AnEUn zN*qkTEAay!Dw!71PUyPQ(#Jc>rT3tq%6&o5oCB8|8FWx_Ej{w4cKPFvvdC;W;Idp` z@>VtqK#;D6+5;I6tl5CffI_y^Z!(-ik@k$7yrnX}2|0fPPI^?B>4lC01$MPE> zxM^*#7D3wSC|yiznzyH0=w(Z_;Q*|;c5dM|CU16+NuAO}OPBmQ{1$rNS4%h?ujNRq z{C;#$qndv3+4~#zIAAO|^QP84=bMgq2Upg5(ngX6NJreVi}>EtH__a^4YL5vR}C25 zmemZ>^Bi9z2!1)9U5S@Y$N%zp7+xWp&JQgcEKy+thzf9Ii@8unYhM=+pl|pU$k1`` z(tRKm!qB!GNk_PBK>nA^9jQs>MQP%-*f0%EO9o-wAzCv>+QfyW-0oiqK!hr&4`gyL zt&X^lw=KsK2f`ywrcT*jy7+~m$6+vkz;n)@so_`SBEjb2rp9e+(xrP4Vc0XO{% zBWMB6L$9R!><^Ka$w_h|ZjEi}qCP$>!)>uthpBb&4!`_UvAH@SGuW1vp{7$0*Ye)Y z5%3Vn#YsL^@s2~d@-tK9!=$;=kw4d@Pv8d{fTA^MCm(EKH0Bl_{JQn?r|%UcY)Lad zGaiRdfdpps+cKi@#f5&6IDlpG*ae4fHQ`gZE>x%OzxYUb`Iy^@z{anOU> zW95%2dma~YRBcT>arjY@KXKaCie06AEqTZLy4&~oKzMGd_j|x_9&vc6Xp~|hZG$H6 zgAIGt!k47VOs1wTnkYhAQC6o9myuzjO zmic>%kDSa3bO1w`2$)qsj5G;s|DwW26VBxEUVWV_P5PXT+TNd$cSv_21_b2ZBh%9T zWb*Tf+x?9ESu2GWJA;I-gJJa%07VDnZ1W32l-tYasi=fiX|F{4^G%En3{3AVj(vQO z9^FA0ln`M4s?VCa!79M@_be~Fa2k;Yt2_ZGTB>v>by+yE3{aw;XR&qTcb7W5^?uhXu^fD4v0qi~tO` z7K852|7`Fr9Pnj2m;HT};M7!FdOG{;(NXN(e)EVsA;R55U2!KRQ#y{r!`nFCw+VDL zA4RM}cb}9H-vursN=9e{*X7eosWT>lvcg4ojbTcPjp(7DUi_&9mm<0CY#m(*l{eoZYa5#-f^quosLLIO)gic7*7U77m%XP5o)35QDCsIm?YMbLnXBbKY@SdY|!k zy9mqy3pfuAZO7U2v>=s64!K43;`DV3L%y8hJ0C?nvh1BcP8r6I+(_fI<|@iWp(G{5 zd`Po`&hzFT%=|d$ni8>Al>g45tRrW`j7tFr`0_58*P71S)mHMZ7cWEZf@!QYDm*Hj zT?zI@%39cCnRpRKrQ*NzRQOObj@^e;n1jZN8CTXpyuds5Ph^Nc%#GA={roASSL(Wx z>U-c}2Kepe*5fXeH=AhKm(hXAUT2%#Yy=HzpId6 zrbDg)KTb~zhpZZKCk#5Y`=tHR*+_|4iNehB)$Nd&582DlZ#(|!-t_hMbYtiNhy*UO$r%n5nkLWySV^0823oGT1y zEmk^ptxTQD96#?WG{&c;ZhQ-V4mqQg@OZqT{V`GwIYdmxeXR^$sDc)S1V&Axjk)Y` z$Q&PM_#^ooryEt`8E_z$^_!Cdkxi9*O>(B0a1u z{6s&c)L6u2M;eURbdT&gO@-P`J0;B;lp8z2I-)Vjyy&~nw^hn6j@0bjV_zxY3JVdW zsE}!aV>|;4;l~83xZ^lj)u=kEPgSUwer2uJkNwJRVYZT__(iJD{I!}0H2m*tzF(=P zu~c)&>UHf=y#rRg#9i=11YZ1h7}#zY>M)yG$Edkjy1=bOZX%o1T7;nFrkK2P)KC>vR+X2Mj$6 zhMM^ETrtYtCqH7a28-PFkH*BW6m0ze3;$rMpXh6P3 zD+lj_h$0;@Q>av3D_VMWSu=o^0Sn0)1A{E1%erEjj)7yDF9~L$hHbHfrh-t0hZtCT zCXNi}Oa~RZDx2xKf90$JCF%f#dMoR$nquw?F-)!SqE$ZKb9xPqT&o-gW?`sYM-S>c z0u4UUeT62#P!NAevj69|qJ<&+BS1u`k^t)P&kKqcVPI!IW;DC%f(t768v`dIgxo?~ zGOxS-^8zS3IrJ`|D`e`_F@iV8iM|7Pa~R{I-CFhJdn_#khJdO)qB3q z|2?4i)9}OKzMjK#-YVLs5;O4vIx;N!1=)Y1>sFhg+ZL1Xr*$~M7i7b zzji4>E&$=^+={&eshQuR3v2S9t5W0z-~ddfB(wXv^#0q#{!crP!2_NJOd<-ryA_8Z zM(>fPbg2r^Ne@1p?6L($eGzdkWu+9{?_RJ5v_5cQSQ-Kd9P}98s*wsfJn1m)U z4*`CX(xIiYk@%3jTWiYK!}t4gNH232nhW_kqr?_77Etx;FK8?AbR}e_9sc>!FbnRU z3RpZO4J7>x3dKhjc&&XEIR!c!KmSi8K};}!Is!kbikNEs!ln9OWvG&`2|?!V8Ld2B zPMLyI3@A2+&X{O}CB6t`?>F~}{5{74qY#63P|T%Y-u?~`_GA#SIE-#m1voD9&yW?;2|sRr{!rZU6Ehn9$oz{?=KWi3ja8b^nJMd2f$*fyx@BIvcr#SFp~>R^~Fk^nQ>=PNq# zXAB3uVG?Sv32PR9Rrs3{5<7(yeo=J&V?dHJxAX=iz? z45R1dpSA`1;D*k9QD&ns1uV**J6*+Bpl`p$QS_g|c?jAlCKd*yy-`xF*=!K0f`t2R z)cF1@Mjz-LCB=QTF}ZqI9x%(q)xasIe+G#`9`vkykinm&Q~L&vvYj~*-=6>Tmv9K^ zE^9LEQ-eke%Mcedh?w_sl)(^*t#``y{ZU zl08%>B(?oDwNA*dL!_Ex9hIT=LOmUk??N0{{R4 zs3^$lk*|(UkXc}Z=Lv{m#=v{2|41s8_wo;pz{cs@(T3_)bOM48ew~}*;k4IGT3_mQ{^Ht6`}l&i z>1=PQfPC3P_>&HkTRgmZYM{p~1l}DT#D+_=Z#yYr`N~E;e883!+iRHeNH@t%j(n2# zDeh-d7Bc>ZIey4I*VUWKuW|>0_)K|Md@@f@lLu;!=lh=o67mw3$nN)prR8R8a6^3u zLjx(St`>)j@A(Zl;%2Qd?*#G~;%L2&NxKamB#A)i5jx2AkI3buXDjAjzWQ?o9$)z# zO#UQh6(+D$03HLV-wjQA*`>33SxFc>H3}UM4ohWnU{s3Nv19~ru6Lhy zr#}n;VJM^9F%t}^={>CT)?{U&;n!yxJN(--FV7vZg0{c`E!&I!+0RZTTIUacYFb7& z?Lj#^JoXRAj~G7zLYFr$r@`!t5IGB#5mi#|Zv%~sHqZ19qdT^LlsD9%&S$V;uL}`Q z#BHlGhk?gOX9-3cIgg`V(rO;%@xi=Cp)o{lSk9?YMVxyjN4b+=s^SFgg0#%lV=FGj zj0&9j%YaBAzoRpZi5gd?d~j!wB&!NI>wCaNj47NuS-}YPz00Eh1MGSy6;hX>{HHb!@@IQOfT>dcqiuYm z4^wdl`lB3av;a8Q0qh9b#mL|a>a0t1eA1@k5Q@B>^1;s|M&H;IGaH1@+sgx!OAN07 z1yUL;pa4aSAh|;cMS!6%O?`e96_A!Ee{>66*iz^jYyL%Kqr@-uwq z`EZhB*8xk|gq~6q;4EVrlD|#OYHlKB|AcEWsY{+mw2EM0iVSUMzYk(GE{)D3s>}dP zL9r+BouQHyLt*vt<^uh#h$j0dc;6o|LD5x1WHINLE{9B}RvJL)UYP4`(5fSD1cIy~ zCJl~ado8Jfvwn*}{r)YKS-if1(k%$a4Gy7+)Fubd5Rl8I6jF#59dHm_h`NI_7%{|Zp+$^* zDC7VWD>zQ+0VBLfvOJ=T8XZ{yCXsnKV4-PIVm4{q;bg%K7UO z7o#GY%~7>x_md*J4tw8r){+MDt_$ssh8NPSEzAWTA1X4LSi7*vR%HK9Zy{)gz#DG z(+W%&EDleX6N<5r)M(Met*?9k`PXPcn&XguE;N^o;-h7?RO;$Q$ma(VnJ9tQZNM z!fTT!2;3of3@xBY5Mc&L(17XyZ@hj9uK3DOF26Ga5NbrQxT#b~C>)m6{6V<_oS}Kd zK&N)~R~8%x7kLQgNR%2H5*UsJ+Uh|T-cahteeGFQ z;?-P@yEUvfN76^Z1>d+yyj2gW=k~-s{$vhRNY^WVH#KICI&*smBz58JH$FRT#rka% z99(|(tBoeT-&0&z&~)y9x>!Xe|MV;U+4XU3f^2Y&HD->k)qe3o&vWCnYT`sQ&%akT zmY9hBv-0-+o7YfBKzr3^4y9;#N8g7?6FO zlivp>;2&uh`g}%DSxoRlXxu5ItB4Yh4N~14KvJLX!1+#TX&6tXehpJoEJAlGd&*i_ zM%gSfU)JwX9l}`ikOkvdS$8&jTKl5E$(v^0)8df zLn}&auCu3hp7Z)qagl&Qbk;K$!f>cQF3$=d&RJPn7xn(`4}`ZBV_dceiOyW^alfK| zTl|AL7RpawIJcHTVt~Vm{#DV{`agb$`VT5G!u7-CH>Iz6lkAZBFpkPjrk)@wWCJnF zy*C>@qb`_tu%(vHvD;UNI4|tgkSb^&NLCbsqG{~xN`MehaFs?1>8gd~M2Jt-L8`u= z*DaEiBr@o4xIE$@==e&5lkP-9{N6wwK90?Ohp$`mI<0nRKJ|#xQ&MD=P1vBIyydIc z#+{YYKcpDMASuR3FoqtAel|jaNVQkg1P-BHAe5dcF841M5O#kAx`e!k4JA4mYNoo9 z=u;x4?vnIkYK%~YxD8FN2%tSNf`{B8t-}Q%t*vOCMHrNf)MSAQ+2oDdiMKg^^z|>( ze6K4Z_ho6R#m8B4*Y-(=-nz4TPiiIe)8+F-$Bq+3rA#azCV&O+5_9!8w7VTg5twcRaqDlgok00lbG3Ch5m!A)87`=@M8^gp{9@ZyY4-KNFOdI_PJ;KGfS zP{yrrcfIl4M?l0fQDQ=3u%3VZV5_Qya>eyVqN&u2x2`6nYfn#;3i=D?#VHSpY*n8_ z1tLV>_6R^@Ut=IJpwRQiGs>$CPPCH(A!?eH0F90of!3WxbMs8V6>xHr=@2-3ZSsHJ zjR$}P6{r2%JvP_{`yb{uTjr5&Ew>OKns+##l9A$UD80!vky0s3t49De%38WIN-0V9 zak)n5=>f07daz2(8>+*+T?0CpWcXn-9{Ml#JEJ|t3F0nXlQ|6zn~%W@=-F>my!WB| zis_z%q^~@?{rQ(~&=4TGh-U~`-y+RQTHKr5X$gQcIgnN%gX;L|P(8?!mOJMeGG&aV z>NHE zxT$9^C$}|yo+5e_SYi=#rA(6`%A2bn1@d;;0$flG$G2~>+5;O^#EC)xCl=M@?drG; zUiKbkJ9a{JgJ}UtEncLq(Ji!hlZ`2O^{5QUoL-+TC+HI!FroZFGJydQ zY!PpfTZkZ4{Jh6hbZMuQ-u$X2Qi~cN(SgksC^o(%CfurOiQCZ2GdvVPRLBbhv12Rx zq%#JxxPgsFW!CMM&&TzlX~#%_@kecDjoWz@$S$2T113;OwZy2U4FiLi*u_crbkc6T zq2cE-^)DXSEP|N{5|+s<0OvxwqpCMSR?($f7VFI@J%7%h163mAfGyxWBp*^m$q7xj z1Gg22A}->J7GM5g%tP0fuj=t&PuE6FYUaVxJaumzVI~oWrLZ7IsGm!A6=2JmDq)mB zM$$9cWT(8a9+W7ph?Au+42xs5l+1U$3&E&ftz|~@mDDUGxxMn)klq1ni%Us;!CbW; za1vwWLZG44XrqHd%$Ruo{>`+^Ih6W?hbPZ|>eG+w}E zM4=;ZF%TPw!p~l@>tBp-YjD$@(0T^HPYgnQ=-JRPL?~48 z!Ba$fO-tf|NHBQUmS(h`$*(PlJV$G6it0^53ogX(-t%`NLp&#w}nsUqs{I*9R zLJOiGFNI!J_6y#yhTHeG3e}eeB@eiI3zH7p>tXa#Po^Rq_33~y;$*w@FyBF~pDp!z zt*X;KU;?3qg!#5pCAqB}n3oVk#?Jt%cj?7OjXCY_J?nTv%7}U)HU*{n zP{X@sZQr)V=BvC1d=5UaC}yf(O5XmVlXmZwu(AMdrSvM50bgmVEZOGh2#$AGOe!+( z(C+f0S297$MQ^7%qeY7PQnMO5k)sFBsP6%9zj-KHXu;k)p$CCo)puysj|u#89>fma zw}OFn5uobU88e{4hi-Kz(1XTE5Nl~dVSEKov9g~=MMz!cX47LMPhIaZDjz+yH3}H; zHnKgdt0x>9x3p|8&azb~P`VR~u2Knq$w|-?Pglv8Uqd_@DjQ{z%CFe}0!%!xfYUqE zBCyvSe3g`1#lKbK8#*p?mu0%-_?Y%>X&w^?PL2`B%#4m4X5b;HTSW1-P5lCvhGJUl zCL`D(W8{EjQkw|>E3MH*bYOTv!6MB)+P^l$<^%Tm6wL9@pGbdFE7$S8+5bJ+UqQys zg~cj)(PN0(itUkOtI$))xqGf4jH4I?NrIg^w|XrkcboTYFT%>iN?* zjJNC$Xtr2|6kMmB?5)(uD@|)16Y50NSv&R_SXaSW7KTY40oI|)9szpSZlE{3%|yEZhA-K8Yf4iAbx|gkj7yq|K1l(^XrY`*)1GL1AB|g@ zF>2X&I8~qIbYA3DubUM}E{*WwT$WgG(6ra4AG%Hjf-?UgPdMFvyGaGWDknc%T*U$$ zPd;mvsuj|V#uvVZS8{qbUOJvRf_PRi?M6PG`i5ahE$zX>@T<|GCfg{+xQs-cNa}PO zT!iL~B@!fB`_kXZm&mLaXX85vPpu_+s7-b{(xqG3)9b43%#Bj zeJFmVT;3i396GoXxgexyai0t%8OIDZP2*YYdj}w6se$3=^bovz%(Au;BwqLDCCVrz z2@xJqXF?TELg@6H9XwU7$O#^^nTrz>|HkIWv8sg49r6HDL>$<$iS0TOR#ZWn;gdxc z%OMG2sh<8y&qf$Xur}(mR=*(S$X+R~9eZo!zJmv!Y4`4zeB%ABovf>8(|oLDG~{`3 zAVl!00GX@b6pE`zdk3N(eZC<~HgE&uMniI+7O|LG%?y?~^Z%gBU2RFEHDXWYkyrR6 z3Q$)|s>Q|lTU9(*)_)gX86(jsn$zCsYG0@jjq@0%Lc&0_A{t8Qh75-Pe3EqJoSOCP zq0j~^0bwwgmDDirimlM3H@6NuKU z0WGSs!6mx-tw1IAL)rAGbmJKL@&8BES@=cu1YG~_vb1!Eut-QrNGq{~q;#n?h|-NT zEFy?Bf*{@9Atj}hin632EzKe+u)wnLUVqQ$dEWnE_U_!dGiT2Ep8Rvc^^}nbVCU$2 z8LqNn6u6IT@#}`_C+es!R3OwUE6eoUQ%n{JytfU(cW_o@>56={WaBP)2yu9g*cV3- zg^{IX-aFTg4CEqB=BgLGviCOFB!+8Sa3MBa?Ob(!qhy^HYLnJp1qtzLJLQQhRb#g& zem?t9S-0cd{7OxMb1;)9kU{TJ$!VT4u~@E60&W>zBZoU z88qcZ<VKq>7yxc~1C}CIt2E2AT35R1^7IA|)J{~+(rD;vwf|k7z z{hH*4T}ED%YXfUkJ!iY?U7{M!NLSYf2HlwUu2Y`zw7`U*zTV;`hFAZjg?fLg@)lt7 zCht0RN!j|L*nH&VO+F=+^jjB>RVWF0sdmePPMelkh*|RwzNHtZ0;jiIGEjDcr#3Aa zzCKjLHsv4R0mZj&{!E^q*Ub&s%AhpeFRC7bSs!*sFNks0QxbjW0A`Vr!b3*VljhNr zMwQcz#e0@eE4n)r{Bg zFcI*O9=`R=0Z*zAd7yG&&NrgP_|1m-hL3SS$~P!W+s&>bz(&-xaH}lvs8&lEzNR&($8IL_{*aPbZn#gI^`3|6bDd z_WJzxD2evLlhw5JrcO4Kk29|&_a5?@_I7;I_^|MZTr%g)oXF%t1zrh!IUrXqQlY14 zfSD|DNkUd+ui{x$KLzFlo~u7;2Njvg_7Vc8#yF9YC*am|JegsacYeB(;NDZGIe;3n z@K6@k0W3@PN7rp*ro$Ib2iO*947+Dtqcw!IzlCT;{OkvKaY-3Gjrpiw!UOjE7J0Qd z#4s*BrH?*bIU0Kf%kO=++Kqor5MAN@AXaG=wdA93EGfkLtV)o@#Vi^S3APA zVJCJ9KhNgQm#(L;`O{KOEtHNO=W47f-@1SbBf2is3cP!XVoOo#)2PzS`<$`s>KzKW zB9hdKU@IR9kj(aSu3`7%@it)KlV^l<4)b2VA3|jPXiddoR>#PqnaN;O0|QEu|V4ve;&rkij4KJs&+}*ff}bGN#lUWNL(YEGw_7GGX+%JM@hoD#XeqDKcP}Ouvn0uV2~357#9_bY749U84#d0ff_|vbQYM+4>H^ ztv4zb*-b{+9V@zvGge*h{w|P8CObCxl=kEi-snd9A93(mHb1b2lK~oliJ`1i4%Fv8 z44ISfOlP&+xinbT`8AWpzCtVA%{#8ja`OC#Zg;!+VV$t)m!{28sgSETt-+<5gw*-4 z8!w4gmE#dQc$AUd)R5HJ8u0M9=r^G~FsCb1a_G)N*6Y$EnOb=*eA*&;7GlH<)C&_I(?NdDOTz_{6wk($Q!Ur;G!W$PI{(=I_i2bg?1Y$-G18J{AI~4#Pyq{G z(PfjrgHoK?@Pl9+ru3#*rymNnfn$UJbavCv?ATSk3%kskrmqVbNkhxz@wsL8 zxGqlP6ohMI;K?@F$8HH*^@&+|*Mv2j&)f>Ztd03Qu`cFo{oWL=gP?ED0LlP{XodJx z**rRV4+hUlWd3>RU8x*!Z{y8?8|6je9`Il=w?|0`FyMzS{5ovt;}dWx9!qaE-e$wKT~yCLKa2U zrV(G~gLW7K2SXinzY*!}D_{Z?jN=D9vvdXAdJZqpad-)di$QZTEU{U2AZ6ve`3~VF z4%9U0{%ILq*u$Xjua5%i`1W?+%Y zkKrKZeOV`0-(!I-Cw_ZTRM%e{Dx?u5gAaVKrqR%6!ijmK4SzHZh-zyk+0&oW5=K6T$V}4!m^NJ<)?@-nKvp1J^}RoN4RIHPZE(2f747o3 z@~Aj*mr40@3t*2Ob3Bb%f!*jM0KC&q2DTE~x8h~uY~lQ>sjOU$Pc8H+Is#{}UJS~N z)DDB&tL+E*B>35}f$4!v6}_k~bHieI)ZkR(juMI5Fgn#;675WVrQR3q&U{Wb2N6e) zt0Pyd8C-WT>$NbAg{wj{>z;LTXZ|JsU&86k$j5h;DS&v_-oQyBy{{v}m#2O~@|ZRh zUb+FH%5NDBy#?=EA>96a(G!C!sD9lGxSH!n(I@L38 zw$3)@-(s$9r1&Eo?`7yo=JQbD$dBDo`{K0(gZaNGLdqL(tJ>SKu}vz*AdyJm6Rfd8 z9zMokDumSCdnG~ko4K!5@)OGk*o|FgTu0G`DP9Nf8;8n7)DHRq^P9ZU>Db505X0yS zz16PBS*Sy-uFygN>b|?G@?Pb^AZu)8@OP%1pycnKp^fr)@GzN1huN)DtTSC7sjv2b z`3D*d)VYpb4PdjK$KSl~i6xQ`T`Vs3T*p8EkQ|qI}pk^S@qz$$AOQxAsft z^eo`v9(LxA7}V~8bvXh%(`PUqhVX9$@Dtkv;j`>2Lo_$5)zgc+S``>$N|m>i zc-2Xdnz;e0zz=w%(!dy{2kXfo@~%1Y-~?LzX`w2?6JVD@!(_e%PSCNd7*0DJ&2JkR zRt`AD^s9432KxFA@1}L|CbW0*3Xr&ybebQl-VCx(OyLr7sY{3;S*LY`L(clOmh|W- z;=?UP^HWz!`NKAB!VFbo)Rnbg&$6qy)Dx zO6e?1jDC{gU8(6KL-g*w59PJb^he+VhaGm7C;p}+ZyAXkCQm?(l0>Wev|`+Js#Em> z&&|9&g%xo|qpLmKtIb6y$o}${u_`U4CQ!Jn6LMQ7TGa`+5&txLFq7|HD~ZQ)^0?rG z@ZqC(9{tmZ1ebB}#b>VtOw$S!~G=epaV@ z?Nrf3T=BqaEN7*-K9T87^Y~`bJ>~BC?%LW;1J&2&Q!A0bBq{Yq82QE+S1p{aCziq^i8Y;74SOTq`%_ za6FrE3j|CGfuVv{_zFE>HLpKaMTk4FAEEOOCN8mb6XkMhwvfPOt>(y8Z61&|hYVa#MH)wS&rtr~iBee`gJ1q5%ensIp+jhDqtjXyJ&yRjUd&$C} z^Rj3Ek=F!!U5?DU>;3fL?ak>CR%~41@+Rr^)6HINx9=fibcS2WvgO=vY9)@lU?Mhv zX&6rDaQjKu5Z#Mx!!bNWUR5bai`oY~+A9UW(MtZ0wap(o9jwb$%g}ByvYuM-sFsA^ z)pnsjvyOQ5%m^rNxEa3(&elOm67d!&?gY-1Mwre9LL9pp1CR+M#CNoe>jP(W=J8ao z)B%DIc*{=F%s~09uL6tjc8rJlNec&H+T*_PJ&I;{A=4nWPUb|0uKJ@JuLdH(d9Fq) zhBNKm+VcB|7{a|-!cSIm!o-Tc`?Ikax`?+(TE#d?5+}2KCE`3|yrf3$FY6DwQ=h4H z=?A8?am9DOf4!6;znA4a=TnjZ-u)&7IbEt5ygh0h?FzJr-?0pvMEB!DTH-+?k2_%X&L9EKigb@lH%%K`q9cOWr*jR-JhWR8-23%e6bzuVCV$Wmj!q)z*o`hBWSKQu_>VH`ZBLp5v5H*dqgj-xasiCGkAJe6op-4)*NHvoC28F<@?Y zFn8cY^j!W6p(_JECwjM=&&LZWkqB*&7LmLD1%{7z<@DHzlFsT#fA{_u$_*j_6H^pR zhi3Hc`lANUiyijr44I2!?sfEaw%2;tgND;)@7SE_u%d6Fs5@cj5!F#_;9&b*2K&` zrtKFr#TO<9F0TxQYAX!6^>z5!fV~udfRy=pIr zkkVIfmAmSM?(zOc5@Ce*ZW}U-eqhjZrAKv}d$2zWd2qM4Tx01%A6n1#eRVT!jHaV!JjmHPME~=h22OS7K^1 z9(TKFczzFf&Jg6*-FO$)Pv2{iZuMC9z@y?yIM0R@JPWnivRKQT0h+*M%^kY5$EIlg z$R&46vZ<;?vMtk;SZmtP9UX~_RD4;`9E{T?LlMQ`E^&^6rkma6)z%#9bnp(5>uV=2 zqu4@knLrMao-}8&-j(3wkEW{DlrVA+yvcMbQ{{>&b4_EW5KMC3w(a9FD;WZ@-?41x zMeqddm)S!`X6XkogWt%hdI2?ARbzJ+79=W75)i%|cy5ZlpjebMWDPZ{xRP_wI6Six z8}Ji)Y~WJc0C`_W1s@XHjLEoV~x%y_>Fz}AoBIL z2-$3L&~-&1w!-jhcneD@Z@_na?gExCa|SqE_Re(ld+8_{ArsHDyD0s6Z)XRQS031=V*`7U)06VxpKA?yDsw75v5@^QpmGpymmAHol*vpccvM@nisQb z^Z(x^v$%w9U9vF$aPp0R?q8D(92Iik&p3?mD|XR+K`u#q0IslN6?Qrpvry30Ho7tC zmll6@F#FM2ZC`9}^?qK@U+)rZv@j?p-HSz}0WLB%sY+Pk_;Lb8kKL1L6Wz@5=8!jK zqwdOpSJBU6CXo3enkx9Mh7%|%$5gq`drrz#<+foC;-C=M;_Kh=5lsdn1$Z)NI&wZ|4 z`L}uj0rf$1)5xwboytEpn9yG5--O2n?IA(jFuqGq_oPnt&h_L5VqI<-2XGfa;{7(W zG7-U!M_!rDN$?DZ##_)j%#1XeD3V6il9XTXtP|mCflrPq3O`LM)zBJ?< zEiwO?8Fy*$1TrXu2roVMNt7NXFd-)jjU@~h zge+IaSB3e=44SxWisjuwGQOlgY4yd6`yFV^Nm)}0KDpNcMknadbA_vwCKCos$a72@ zgYca@=co+2Wo&MF@YV0l#3~{3-lINEVdS_ZQXiVkMi4O_>SlF#Fg_(_BJaR*2}b|IzasKY@OpVlm2z7|p)Ma|v=ozL6xlJqcTTUoQOAP7ERY}C z0UeBX6+O^)3R0A#xTx?Whxp?Z2eyU7S(ap`NJ5`IE4>9A{{=~2D*&rLHInn&E?yf% zz5;>>Mhe92XoBUaU@;0cd{)VoWcie!RpK9o&hvaz;W1UNu+>rfqKWEF2;$livwR2n)t~qyovL*K<<d(!pEw=^!oL|jyqR!V@a+?Wu>{=@B5DdXP zluHv#bRzq;BdJEfjiGKTkRS4hdx9uw;g#sJgxT{V9xqZPN}UaK%#BQmUHE%Brr_Bs z8x$!=U*Z0$T@~H}oQ}(at}_>5`HAev6z1>;alP3H#8z2{_ybJomRWT-wxXF=_yW@! z(l7*w-y;yUwNY3tN}fJ0e|%~YQg2t>s{a#vMcVqqB~*VKU(fAY!NXLa)#z#&Ho#o7wL)r8hv}$6DtK&a{uNy1*52ATmt$S{+%zi*!)C z2~p3fO7gNPoEvE;*VB|)(9F&ABNEbU5JD%@VCP|mLW4Uhjb zTlvD!60AhK^MGKbq0#e;!DllNoiS}xZksChEl@)?bhB{CL@3C18aI?}N$Y2!utV}_ z4>-QOOiu6w$O~ihWfd+*GgfMMVxZ?X%Kk%s&xhNZd}iL)fwHMN7jWo;-z-X(MvuY% zn_ayGa1xKnp?6+B_-mFjk!$$@LtXfk7Ob4@V|M^w?}uF-4z$ub)J^_Y1$!C)fkcvl zg4}^mT+DK07~5*E;!gwb?v5jp1|u}Z$z`Ge4J9)uWf$OJEh$*eS8h-c^A3n_v?Sx2 zpij3s>2a0uZDHh9cI7uvQ>M{+3vk=|24J}X-aK>|_#J&dLJolITjwfmZap}+t;4p~ zku_uvLX&-pLy~TIGi3F<-~H}!)}K*r-6ZHYw!E>RMYQr0fmSyujkn*%w7g8nBqkw` z&;04bRmB!tsm!=v_U+B#jN0Spvuyv+CLF zOOSjxsV3(@__Qpq^SNB0)|9cY*+jRqk!<|hYjI{`$|b`Fz$Y)e$~Fy!xc9dPZ=Fo} zOJxpT{3YW@+`M@O~AktyrH6zo}dR2l#J}`C_661d~7aEbYClBW+ID{c~(*)(Tf9VH(QQh zo|Pi{Y7g$4f7u#bE?eQ4%ODQ$D&bv}>zRK3d?#L=Hc8>sk#X&5u7&rDe|LA3;Q>9_ zs#7nB*y0rsu6Sr?nh3-k-NfIFw68%GDZh?0(z0R_MI8Q(!fTPym+%6J@PGMKoR?ci zRD|Yl_g>p=3b|;i1AZG`{e!}j?#lgSlO8c%O3e4iH^;T8yN665H%~#WCv1Qk8lO%g9-m)k-$>3) z#E0pX^o9SRxE|lW4sOa;vIABaay^1|AR=`}w^?F} zVc=8VzcZ5%EYK2gd13VKZ|L#4E)!X4hb4mmux(g*ZY229{Juwz>&*(ECwn63A7ni% z#?uK#3ck*TKO~1l4x_PWfm~wo5Ib4?V~)Vc(JUohJe3af#l+5&DewH^srxX?%WRT_ zqL%^*Z)Ra@-=<`JVR+lAPes`0QlCg%{|C0$%y)j=j#N-rzM*c*NCTiK_a1RVHcqd9 zjrGVnw|B&9G{pmWa5=u=F>XzxQ zNn}v9@!##xip_({oM>Ow0$oTvcJkFSn>kcs+(!J_(~nF3^Z^vb+D_4d( z0M=>^!2?k%;azhim$d? z1znE*dv?EO6C*24J)>vpLn=i2_RT0-rkw>y zl=q9xnkSiygnY~QlxLKw1I1#}Sg?R6w8W`D*7CFDHq*<4hg1M{RkRJii)Xei-(?}sgVqN|G%2?LS!<1<`a6&> z>o>U}jGMaT%t%^@o`ig)!j+em!bvuN0Go>sn5G$#fg}-t7g_gj5S?sEA_H$Mi;=T^ zj?CBWAOpEJBN?k5alKnqTTGCZNZqhq-e&(bXBQpwuNCf66Qz5H86?7!Z$$d|56&{4 zlNOtRl{55}md&>>+M416UFuuR;=U^o?r?8s%o7;1t&s2aV$%iwjWKOsbOT3Ba7ppULZUNWCV zOfI*~g_MA*zrqW>%x2oK0G~~Kkf^K&?ZKf`@;xoM8%@7gg|Wxh^4G9} zkCCeR?63`gh==`GD7q73@J@vSa!0M^_lZ&WHZUN+qI?Z1b{z?v63bt^6`URL$lMzG!dw`T**3i`mne zV;x_l!X__#;2)l>$z>qM7PPYtfG=fCPNJ-Nh^6Nj!_KN4d4)>ElT|UMFBc~X3~aHw2aEy!W`ETIu);FCaVsl zMz7DyaoS|)E?NbQxO}lPuPAaq>5f9j|MpGR!8>2RAF;UH#8#*Exd8JR1^0yu-`HHn z&$si$x=!m>kIG`pjm21g*2p1&d|U+0ql?A32+Np zN^%b~!L(K^FZbuRaV(;A}<@a&iD(KCg& z5FO70MO7K}N%!z6Q2{NA$-J*!SE20d>hdjiv#(Oh?^}T_-JBs<8~$C2 zH=){l^iuma_uy)#;gHm3f{)I6&Qp$G&*U959mj!kvR(npi^i20f$jh#8FCQ=CNY{m zZO8Yn!AHxx`*N3gv*tGNy}$_Uv&@7q#t=FMicHhU(dVHr7QXZ8=JAowhCRgnR{K$S z)SL6bbHeXGN!UCi2i}9z1r(OG;4C)n>EcoYRMtAzG)ie%T@43T%6eaN8T-n z?+{~|x;o8o1EpV4<{$Wk)oi^24BxLOG}m&9@cl{ZzN3*LNd{byzEgnVOndylvYv!> zE^T1$f5W^U1}RL|93Oc|A}z>B^0%on%w8rZTyOjzRqiWEgX4tSLN zL8R6P>2==B;gPD={6v6>p3}op)#rf7Ix$lG@L^!_?rrx;Ap3kA?;QulyoD3c-Bs*= z9=6o5R;plmKjPh0dT8kG_XZSirLls1*(-(Fm!XR4r{GPTF?dGbN z(Yhl^x+rAyiL(X2I#avI`cXzzp1rezUh81o=!I=qmWT3n8+vno{OED+NV>nnl<~C1 z+!sX(r?3INj`e^3AaD8I~T(q@cTj69iW-pcZnGp$;dtJ2#bn9tdhEbM9Wk_ zg`s)U@8kjD!$6)cl5B8+KD&7Q?rQw4UFWjyi;>W;=2qwDAF#PIbqxMzZ@3>UynuXx z5+j`e0~MY@>GJ!HGQM9DNg8>%4&~^SIaY?=b*jb~G1?+|!5b=ym+Ee|vf0MzKL-_v)NY`FpRb2VsEhdWdxo1sBV6iOQ2YeWgm03yYL%FuuL z8vzyLC8x9bmH-9Z-tK_1ABt9O|8d|XRgb>V8>d>ru;;j_AQL&y{ogFCCjG zt5%64+MT3s{%gwoO7s{B(}#xIu-FU$enwG^bMM&8{6+vUtO8phG{{JQ*N-}!BCP)= zX8y8q9~=ln7kd|0rcBq3$y^Q+n+=d`;j$ z#`jxpE_JjxQCFM*n@>NdubsojSHHf;qP$Dd`+euiJwF(oa%ny9%XAbUf0cH07Sw^L8f#CwgtjC5<61@ z28HQYY{5_8~93A%C?MtP1()~`rb6iT9$ck7bIgB$h`=?fT#Vh#Rmqv@c>c$6E zB9ZVi604nffu|d~H$TSN<$!JyI|lroP~8uSCrt_!G;H4f{hcvX#5#ZS-bP8{oV9?` z9|UmK%Lop5{I$4>$X*s8*zY{&%N+h2F7gfxP)X3qcHA{8s+p%p%yn8_&m5KrEYS`4 z=4qK7?ojs5>>sDI8g&4vdZ_d*@;8JtgWNZ zKz1V}I?4gJ7D=!i{xO%Ae738h&KmQ-UV!8B6lNE|jn5T0tqEOOTptp=v)Asp6fOy1 zZxSuvRc8SLA^n`*#<7Zh_Y)$Sd)H-|jr@<)ZPrjsOr@}55{=+e?l2eKW0GY?hhwF* zx|tM_ehqePt!v+=Bu?#Ki}H@ijVWV&Y?6m!)o7{vEF(V@8}4|{v{b;>FY)~-73fb7(2UH!_e9#>afxUD`J%-vZdV|N<+|h; zdbUa+jBKr0Xgz;m?}HpSU9Ln4Rk#3b9j)dI`xK0?P*^r${E5;+=?jS_QHa4J8DDtG zONu=2J$ISm3!}gs`NL*;l3%GT+;d7r-%_(|d^nzFdDjM1v=j^CyxB-)f{m7k?s>Tt zCaaX{+k zIlzUN7*Q*`$9)ta7<L{mZ-)7>*lpXK6PGlf&^WLU zQOR85MK6De>nh`#I8ug;{f%O!`C@E8$71WL^{CYAzf9nCu74F2O8Mn=jfLsEi!UQL z<)HacY=4NTCDCT~b_m{)Bqg`Gn zhbEjd%n)k&54L3?*WU}W*5-4EnF)?trqptsIoqdb{irKu_W7B?GN#*tx*F z{6!D+hV2}gl*!oVGu!A_9BHq8fsBuq0&h$Y(I0Xu z8F0PsomW|TZ%1a+Sh%ugsk1Y%fqW zqJDg2AVIxg`D$x+OUdTT^54nc&zV(<2F?EvPEz&J4%x+8d0Yv^R@GjZcy44g5z74j z>}MIMaKegtuR3hQL^(rw>FYTAlWs10-|GCREO7RH3VF`j7rsF^`=~sV%33G7$gT3a2$H_1Y?u!Z5eJG{GMOoF2^00U98I>8m5hG2 zGCvgCJ7mh+kt^P$8$SEs*X37eln>_3=7VxxVqBLjS=&Q#kS1zOKuNB1lof9B-IOWw zQ?L6`mLz<2kYe2&_N2K@R8A1mYfCg7#YF;#WOKrSsx)EYQ`rN=iIinqVyxqt%)5m1 zI3Bk3;vrPee$DXTGvQCl-;51CO?q z-@DKHpgYa}%*%X~Na+~-EJ!ol^_OOPB-RhP*}9tMZmM)O=)NSac0Y;PDvswp$@V;b zI%DH|nDx{|Voj#>*@7BL=my4Ut|9K{^<{c(<>Yzg(a`3wJErSAVJ>*1FQPiKsTdWYf8&56s$3FhA3_+w z46u$uN3H8FEcbq?{brj}mgyk2UO3H8KhOISO z(;|u6UHca&Ob&#(A5RLywLgjM#x*8@sEDeUp}QJQ`tfY@7OK+x6v0E!bDt~tC#*j@ zUBY2{s)%|wymRFamU|_ftZKXVX4g!}hU;;qfLeuD16lC2!|R}KtWinkkP|C3xKE>r zf8YPlY{+$|^C4^ZYMbA5$Q0TN^VgSUd5x^;svxjVa@RRej}7)Rlc1TRF{r=$*YkeP z5BR;#%vGH0#FVIYLF|}ir|#aBEch<1iT~B$tatcl!Kti$ex^&er8iv#fd^JNVbuYH zU1Q;{zCo4bhoddP97!_J{}kbHn{G4b%Xa8Ny)RZ3M8P9JvqM7{h?~&YIErB1b=~ZM zI}&#Kxzl0j)@zS?Oy2Cv-+#xG`W(d4+cb(43R%Cxi67k1&(V`0_rE>^Jw-eFIFeK-YdfiJ)91?yOg*iM9&1j=ad3- zYb<|gSo+P*%#wO{I4Cg2Mj;*myv^Hbn2OZ6v=DnOEM-U?{f;0g}KZG1a zFWr*pHHLE&A6jWS^STR&Ho6JX>uVD7#cBe`F?=)O>Pc+JMV;C1^p6>>#jDzY!7$M< zye{A@*k^z(<<>ei;lSTaS>6$fc{L5N-C?U+Hd1D&Ea*zQZ2E-RWJ4On4OBXQ`9L*S z7i#)RHQWp=ACMji_~_uyv-Aag!y7n7UIU${KNO4?^o$Qg+bB%`_&`(w827;Dl1jM* zFi>`2VMj7riex4lgs7K5M_eHeyk;FazvY>Ke$Za<>{h=$_8+!{2rO@m;6e&uYq@~W z?1UDVpaU9x9p%2DH%bZ~XuroX($EjQ>%O|{GnI!O;FUozX$L$!>3OnN)(M%UL1KQ( zgicHPkmh%6+C(52AuSbo9qj0VZvBb+t8IH$^bu%&k|GWMM-_Qst;33Be4{&oETk5P zG1n7j0&nrn!6qIOe+j6OvvulgD)=smcrPU$X$cfkVEK^0Z>o4OCh@DK7ZV1JK8**! zdg$;lOOLN5?;zIm&`~*Divnlum4qL1Z@TDaZGSs{zH6Dd92Z_PY&mE`f*SHva4me7 zI3915hYf7m8c|@!6x>D#Eg~x2xW9`v5c!8)MG^pnL?Do2?$@@LYW@-t7apX-nSHr} zbiT+ENCq6Xtbg1=v~mVQCh_SD8Ia6JpWe!DL_K#ywiT*ezplAI!m!OX3xIv8)#ti% zUZE!fkBK0?-}0cD0x#s1WyM?|AO}LzL$kLm6^U{s?9cn)L@Z)z?eoQ)fSFFD<4-{j zqpvXLoBF#6Z!Tz&lb9;))1E;Mb1bgocq_j5Na^1yZhn)GZc5szFsBxkQkpX-gDalidh}(& z!-7*Jgy{Pr6oF}QG8IOqj^%>W37;G^FHc!MU?cwsaiT?Jn<^EABf;ytEsET41m%jB zXX=HNpU+D>R%vgfIN{|d1MOr$_2j12E?{7C&5Qbbd_5$yaNUE+{e>{N0qdu0SG|f= zL8f6r>A!{5A$Hm>_w`xRQyDk8hdVJDzqq`axa`_i-%lmCIfOXameM6|2jMz~RIMGU z-ZOw8hLzh8q@Ft%TVT2|cq(H4gCKfeMi?;HD#7D<>PsA=7xe-dBL${sCvodmSCMFw z8-(9conb=X-3?`;XmXno2yv)vRoqv0SD^d~<%+i!2b;QPf8TdTL3jgj3@cC!5O+)g z2lxWdLAh=RL(3O!Kc(lB3Z-b5kRFoJWn{4mLtk3_&bHjAW_=CI=Yutt%DDwDya&WN z)^=2_&*367;Lvv0Z((iDDF28b^!Y8U4q+sB3s`qyqx5seEU(l7JpuuZ>Xpp97X^Yi z)cKc=Np1+@%i?-25z!eESgr#%747i;;jsri)wbw!e*8!JAYh;Rk5H z{&nLYX$h+e>_s-X>}f^xBJhxNc9Ez@m!daCX#72v*w&AmHpugntqgq94b)sb%E{Fj`@7AIkM@>7x z`~B8q>tAPvUn2>Bdd=%B%Sb?3OL`~Tm?_WZ_hMj7Jyg_qJU>7AQ7*RBK`8+;54yt` zSia6#Q7tjTY|UbXNRR@y!G%}2JjL*qdH3+%RcT|4Xx5|eEV<5gd}bM{Q1E(39_qWU z#f`_@;-(|fxw^BT6>yxqF!0Szm;Yyuk7dJ70?IVcvv|b4d)d^iYm#CfSHaXAY1hY; zZX9-k%`~)}tIV+}d-k1RhKCfsM<)iks|6pqzVgM~05=cppcP-vFhAN6*2k49&b__aNPl&r?8W& z1u3J?V7JDySi95YdlmpQ*QD$$mb-*q-$KMIvGJ}Ykptic*p2FAwRki7u!&ZncMmZs2r z<~p7~0XaRS1iItPCSw!fCReV_KoOUU>(Gi9X#5qFhtffowcbGU7W7uRB%Z`9Je7Gy zQspe1_LVHd6|~7v;lzoOI$nDY&`fj|;%s(6mO``E@A>0^^^VvlHS_EXVHPKX9!OYz z2yQV={l@)xb>Pu;|4EahJryf2Tif7Y!7_XQU3W}P<-umb-ZNPSi>c$zpISLXGAFBv zxXB>*p6$UEJ7-hc{Y8H_mj)M3cg2J_$^G1`_Hdu39$a1 zo}s=LoB_3?nNmEk6Lg;Y%mMZtJ1L64w>fi}mdJyGUrFcVJH5A;a`Y`*Bb0=o!wn zlp>D-CTDae9B{G|!_s19Hvd9efDN@dYa1f#oFvZ(2@Szc6TAQ@v%g=xmYl@MR{jp4 zsJ3Pz7Fm?KXxlV8m#yR9+gc*Od!WVOS{*GwEFiC(-}m=-XAOht*Tm&k&9rBq zw_jhLIqgGD7ANp0Y|?t!vYB-Ba9x~5oTu2jOp&9zk0?nXj2r6Y6a6CV2Bt7AYRNc> z^N^zYR0GO8KbGh~6un>0LJW%r68u6}X3_2s7mEk|ng85oJ}D5=$n4l{2yN#0a*i1a zLezKdzkWu;+EB+RHq-}Gj}9hkRZU`!Gkimiu2h2^>c@ix6MQTHLCcCHOAA3E6?~Ru zkTgGmE7?35XyyY=$m5-HA*P)5Gelexz<$rk&y}0c^DNe`1mOQK04-*H(nT1*d|L+g*q4ou(qd^<@*#Xmkj%OP+L?E3mcn1PbW zwMzSod(ZC`{!dioBmuz*FXgH6Qf&gC{5Z4qc$bBId;Hh;xoR#v zdxSvH%KFr(F1!0TB9SzFNIn4~k{0jpGOKAbZLpqe72Fh}uE;p|jaWOikK~+80r&Hz zW0*t%MIPzUyO`g)b|2o~P>;a(%{ZMTc(4m0S_s1~h5F~O5UTQb%Fr(ge3+s#!n^VT`&2WwtlVnK}Vme{~=%!Pzm$Gjo?5+ zDU)e&r#N^#PaI*45R2DreYA%_LO;d2}iWDL8~b-X)vK=GT4cG|%IW9lv3qWb6WfRQYjG-L?lF7N_yy4R6t+==@3D>o8cb6_xauD{s;TnbLO1) zUVE+A;sqW6bVN(&t(TD0-EJ@Et(-#(BaWRV`J=Tz`)zT2dZ|V zq%<_?KMfi9Wkf0Z^<9p%pOaSqc(*VxK6K#S{WR6xY6O>b!w@@~?nv9#l%pV2a!rOe z7j;?TzId~Lxv-)!L@CM7^IImi!%eZA)_$JOC2>TU)8q4!1?Tcl~*WVdl zOpK=}3RLz6G-)YDOZjemm-WNE?N!hrSVt>;sTx!*}RxTE@zS^9CoY;8oI1n&9q0$0XeeMtBU9V>oK29P4``)>ZM zf#D^#oGh|Cvw7O^v?U6iy<8x9ZEs5~xo3j8&IJ=;?+s0nTb%OuUc5?5brWMj@c%i6QX2cE|#D#RmchV6*Xnk9NB8iVSYg zhIg1!333L#F04V=(qVJ|r-1&`{{8B)e8q^r6@ba?@IX*mT96n92D#S(eI*#H0uAJk z2us^xS24x5+u3rdHFyz-er~;t%fkre=79f-gPTtqQx|I)Wb~lKwinVH`7alqg!7DW z8+=iD>F$4TEWaihSxcZsKm4BS-OKP9Hsm6Io-BO^3qBWRa60K0mjtq7BN+%F=3)l zWg6VXi1jlXTwHK_k?|Lv_*lu!0q!iJ76Sfu$@#ygYVZ(fA<&DiO%0BW>T$R_ZGgQ? zMWQ={->7HejN_vRyi6G#F7E_WL-<&<7aph&%IhsUv)oM&FH+J^m7tpFxC3dKaDn1+ z*YVt`?e`HTX@K>Q_0Y$Fq+_2t6b2Y_g)f1b2_@@V)ldq3QVEezBfaOy0!lM9M?aF( z1%5Y4`CtZBBB&O*txh&qxH40y@EDkd+KGJ!AJX02ik)W|%3;=hH_e>%1tdp(wsV8! z)UbDQvjlcXo6G%bGJO!@T*x19JkY$wHHyY=jt}$mEoRCj$PNd z@hipmzs}It4!^(YD`5}6sv^r~TX4t=9MmmdRl!hWT%K0*uJt0&BT88*v-kYPkHRcx zDOAPr(0cUYnqCzlA+iKb2G$jddulLYDR{+JMPNEX)Qyt#j=#xorkW(+$}viGfS(A{ zf3J|Z6OR;^BYQ6`8nIn-Ab&m(lFohAQQV&Yr#0uKIP!D_A@h3y@aK!sbTE1-R!_nP zP;r27SF)TkNTPfwVajvu{`w*6RD5-8dyS2#G({nl-26l~wQV59YmbDB#3&RpuX00O z0(tJuV*c^4udN(1el&<1bc7DJ=-#HisVen}i9F3h8?Ek%^-~mD` zLI9H3FtnV~bIM%zi26UZ{#pl#HlG?g-<1B;07~K~IBh2t+D|#pgpxlztCiT881MwF z-!}hM+9zvf^v37UcckZ}mRQKX*{nDkJZxqLI9F>c!(Ibtn|fFM>q`~Ez-h>EfTxo6 z$`*E_5ZD^5Xe*eafCx?rp`VIJD1a68Srh{ROfc^x%~P(@EmtF4;bM3-P(U#=kLmJ*OSJi$<)ZWHh7z zT-|9TDH7$Q)koHkoKSr0rPV>Ebh_5wHPs|DZ&akg%C|Ud*3^oRHn+9@b}59SIq^-C zoS~korq?5YyZH_6F0VHw^d{KrO=AeE8!=a7p)N-K#hB@I&o^U9^%s23 zN{;2)&M|!F{V6_O^Z-0y<&tOV)@#I_p+eF}<_jMiX2`BC<$eWUZ2Ixs7GCM3tnkU- zvX?bh>@TT_FhlsBYAQ=p?r)qE#Mpy0G)y^6nJ)nR)<@t0SgAa)WBnQ8W_$O)&Z%)q zu$Z*)HNJXR9ShCXqnUV40bkwPoo^B**)vxUhHWc7P3)A{1(u|TPMq&DU;Rc)nF&^8 zJu#b=gisED`VSGH&z69*!%d}GF5=|7PwVn!-kkb3sQebAimHttFq>Ev6E>{#{@Tw^NsoOe+~*cp)feF<8t>4^qCqGjysumf!hhh3)0LZK03XBQ#>CO>|pz zf7zsIVx4`R?dT9yb9LPOzjH3r>@h~nFcltbR7`0PW6e~1q=(!;!3uy^SAj)ei4`e- z*Dm6?M;{);JRd`e3FUE9>0-$OMK;En$} zd-RtS+5P+C@DZcvJ>`DQRJ}#OKn%YM`C?#2UT|O5WEsvf*^lu2xsf*T1S$UqE@g1P zy*JMdJ?w4ZE6*)1qHTa2KMe335Zr)E|CA4gtQ3~Tyk;^v!f2tv6L^aGJHpW_yW=dJCM)Ut7pZw~Wc?$c+h+jzv50=8DP@}G+vodT`nCJ@ z!ZHlG$t?bC0$3-eVH;rR`B#?jeoY*E8cljG0mGfbKol5(%l)IR7X{X5+9m&!lTlbh zFM0zFdn3k|jq}h*WI&ZfBlStXTF?`Rj~6cF|0SIH@#*QT!|ucaj5d7uvZG{Ez57dl zU^R=bT^hbwY*UZnjJBZGY^xS1^{FNQ5=wNTt@28#3s;Urhn{iFH9xVrJB6U2%`5(S zj^f(@&cylru|*>+=?1h)FVlemNZzUE4fo!zN=?6*kgL-nPiYn&-bn5_RuB6kN@R>6Pu%?os>ojDvl^u>RIW;IDaZ-+AC(kY=J-Q@WKxS*fLw#Vb~mq9B&X zt+tOTJxFF8<|VR|f^(#5BkY-u#5d&5x6nIJ4P8I1x7p(X=krBx%)W(%4=eP`gzHx9 zyS9yWhRc(wd@mXHOXgJt4L>x$X9Ya#EZg=!jA~>G z6qtNbvQx}i=O;n#{FQ`H`c+7IBzZ+{Y$MZw-}_@>!#8zIm-IK^n==_)zO2qhoi=;HSK_~Hu3_)brO$}Cl)R+3S{5lyNa&QYU%tNO5*;M zL{2}&)p)smMY!fO;qTb>l$mH1M!;ye)jGs(H+u#<4rdWJFaiZu)VG6;u;I?7lxrNC%!Sk9Hn z!HR)=On7Tta7T|rSMKWf8gi%0(pB6in7|I+t={5}S&9>FN{6_FYImx)cj!ByAO~Am+N=l2CLm=T=)2ErE}q%ENDXxpNX0PSBK@44 zlY^g0fw6TcElVlF;PD;5EH*hEEuvV^oFZ82K;^1WhsrU`)qPtmiVYANi6 zz4<;m5l6IPkj=lUv`qwp%zBlc*dY_mKiTH)Z@w)X%3Och*Zfk2unpPO@L&0lHecC- zL8ALg(wpmkzjFJZO6>lXrWw%Ji#gOM-RX*K#2O#{c)ryngUO#NMGwFec%dYV-`FKr zCEsYAX%yp?4h{0z14Q!}$6U8dXI>c7 z$VVASaDF#ab5=ve*TpK&<(=)5d~4hrfr|jfe>=+*JxvF4%J1#JZBB3dEJD?voUnKp z>r_eG5?Xv(jWf{OIgJMN-zh>ES|ASQ8#G6PmG@1ID-~}k*2Q4j+OfxUeip1$Zqi%p z5kcWzqqQ-LvKv@E&+C)lFb?tAaYp8A&aR0OU6Z$%sK*w+`!p0kUN@z4He5kzg)bAK z2d*Gq%?`^MGlkD-B3DBDg$y8OEe!zE%>e;J8UULU0jys83F;?G#+qEz zOa3tF%n$nw*NTN+lW-$_;zxxYK{X6qM9pOpM4gc*qkU9rQWMBohWX14NHQv^sl6T? zpVh=vXM3a}452|g{moUiYh$T{PNPrLrt3aFW0l&-G)l7aM%vq`8@*8x%Gg_O?drpN zp|{_4QzIEU#c5JpV`-pwQDwwm0~hIOJ^q<(JvtL^OyVQs%^^Xrw1T(4X%|6@M#g=EtQlojOhns5+L?PeGYYQf4^(%fW#`ocM@o4&w| zOWH}h{{8Vs*f){y#!!VdM7Lmj2^s{YzssRWUL*m3!#NfKX2ATbnytM^y40Be#ZuS- zg6A->K3o%{@TRalTeIOCMY}<{!E9rN@M!kpV=}}-CBv+0Ks_B+WuY$Zw(DJHHlp-i zr)16PZZ=R?T6k2yXD^a?oj;2eFt{vc*EVD9v^T^o^o;O^B;V8C5Ubi*{%c0}DoImN z{sA-rKK##{5nNHk5^ua80Tojn=Di#cyLqnfk9sPk*2914Oi&@*R6l&P*8HJOPw}&W+@ISV&S}anfwZxx9Y8GNHe!O4y62 z=P?%4fos)R1cvW2$m8TfD~iWaFu~{YvA4$4KaAx`;wyr}AC2#+V!Efyr_d^K9c$%+ zl;f&g53ye`ervAwhK@gtZ%ZcI!hvRixat!oQso06Z&KU&TGpg%6pUHxVV`MO2$U@V z?NhYkkepbMjYLq$XQww}&V$5zt*#uSh`+zE6yWiWE{{eYVI@`J{BLhFj{S92dXpu| z8*3k14G_(^==J(pZ>ODz3v$x5GyNkMDit;zM7IB#%hFVVe)6|}xxFPdQRut(mH=Q0 zr=1X|Jg4rQ7U;faEO3;ti>Jz`fELDw|J>r=c%+)$(E39WqdSwH*=Hq$XozAF91|V` zQ!9nncJl;d?p9N zQ_vtc9Pk8seVYlm$Wu#G9CAd75V$7MA#ywgvwpq4Sfw%#A8p%g3|j7b33P<5x0#Sz z{(mN_25^{Nr5rv= zi>?UEiJbOClw&1w|IFO6@GvX>S)ssut;*ZykN|ynG4_VDCX0uNyT_zX4KnIZu^pNw zp-S3p|04cHU#oNSyf{=Vt>-lyOmKXQC$jk+x?gie4T4BCP23%-<(P+oJ zl=(rFF|EF4KSyMT*{K!^L$wqEzg7KTH+l3HZYoA*&aXv)Tr9pn zfx|R3J?zf2lqn-qo@x6bxnSmoX3n`ilu48#DUd4nxkW!#1Mk|yo5Ay)kqXk}_36Er z#%xMWk()H@muE89y(b}GhU9~7|{$BDpn-=|J1ZL!k^sIEB-Zj zGa%T|t!cR?YZ#rDY3wSZG%CE;KFaO(Vai2Um}yAx_qHO&EB^!!%}oL*B2w}4zF)qx z`aAS=Ztbl566tV&?nK?r2#mGL-+am!5G2N!SH7~JAl94kE;IA~k7OE`=h45Nobu5z z1GNcluw24itY(~zcl)gyK=TE6O!Dc^^=%`J{;fc~9Tx;6CF#QCkQS4oPRiWjTReoi zl(|`VSuBG_wyNcCnG!m=EXG$(&rmv#C@xl;#yI-XM!27CE99y+p;Lb(jEQs=i!d?F zG02lsoD!<5FcFTrZKcO(x^MT+$v}DlU+0xuGlTUx~@TXAu_OIqt?4*S6;OPpVD~KPV?QhQqQb zmS7_3%@{e-vb$D%9;TfF&JnKekjQcc;J6{qq9ezdo8Ka{r*L`Khj9m zj+VLZF(xc#W^3eiaH;9L3edf2E8tJ1jKOFO=;xa1m_EFM6FE09w(=iH-}HQC!*w zt88DdihL*@Ohny?BoR*0$pQPYAsrX2S!mR1*xEqoqu*Bu&7Mg#fy)kOIdMJlbdy%| zBv3aVPsoI^M=RVn6=-5-&en|y{(a?^>w*JBYxNbLV^W+x#bLO< z4ICU7U)wmiVZczH+k$1EcNA2r=Ky@J%1KTRzm=AMRK*b<=f8k zF73U71Ccwk4#sM5qbAvi1K<4Z$m_0RhU-BgqzY*ZsZR>d2)CR>trsG9Nn*~L&`A7= z3+F2n?yS$>%Scs2WLos1_Frn-%kV$nERJU_(O7e{@sxem&KV!08@HSzy7OqWRw z-AqRP;k51%XI%PP!HfAXBr)eaHp|6MiCgnfRZ)ru9|B8?Fl+OO+gB`fRUP}aDW zA;Ov~wAMb3WkRjjiC5s7F&~_2LH+F|5N`L4gir*iIQ&i)<;nU0c<&u>7R)pcoNAE< zH{L1RVeuXdhM(1&f}Uy}tSpUQ>X-$QERDqmJ_#MZS?$LU7~VBA6)z4Rl?~a4(4OM*%Tn@vG z7{aTmvGBV|=EoM2GOPf})lU*?;XB*quciQL38olydAp6~Z0VflS(T10NuE|KKii@EbChPJbB;#7y!LH z`*|W`nj@z{4+_*?(v(CdRV(KY6ZlHarVo2 zs@XmlEVkHpdS|5OE`KE11l6fd1z*fASF+h{ys2O@P=)Th<3WEOJ8rV%h`}(t8(meq3R3fQzpqNp4st;$UD@;P(?SgT z-?5m$Z$+VmrJ42cGtmU0wj0!*N(-&kGXkae&37^m%d#dHGYof)y~47Gv+F1M-uu@x z`}50R`PQqQ9|{YPemwy#C;{7J9M_7UGv`WOwKNU;YEpe%+BxYnOS?XPv1GimzaKAS zvkzMpo*~K?{F5@u9=RDl@}o&C06E%eAmiR*53=niSin%pg4{+vRl7<-K;BH@BTGIf zqEvslQwhAtkZfeiPo`407)xs3);Vrz%A4rrhbo1d?eYqj$*~hNCX-K=4W;H$+O#jc zH%A@%@ph78aEOgJ17+*V9$^Q}w0Fg3vqHxAUYG9WwVuT~i+O0;qKOa9<~M>mYn+Ug zDE(Oms!6@fe0GXc2Jf8S>E-q2t;+Ou9=*lcoXl6ksX8G&&vUlke)c|0>tgQsJxCIv z!GdDY14OizEw9JGC-tohOAVtjv>M`Y$zYg=8z0?sr_VxO#uGIZHEYDWa;rxSr^ zz+ZM;fEYiV6nF*c$~!Chk=5u+x8rzz<1^5pFZ~Qh`;tBDc=?zv}lH-+)zV2zp{WKDGH$( zAe3WAIbmC4f+UF zUhb0V5Y=PS-4czP(GHvY*8ZkXr%1tT65GB>MSw44^@;E^`T6q=Pwus#_hCrhxD!qX zS`AySMLx6jyeOT&h@C{v>-0ytzU}Hwkn#+nR1?P^VswB9+Cfw z`D0c}k9M!Fl55>ZFkWCsq%&1rxBc~4X<)=6sPg|~Jy65w2?B`AzHZB#r1B5sKy*(Pby1K^BUpGZ6TzifP=kEVy=qn?J>+j--5I!G1eM=<%Y zP_C75id~8926j6pgVL|qU`QjgKTm31a@lMl?4Wb-ia*leD69K!{v{^pZe@5;>hMBJ z2j>qbF*$@8WU%j2vhMt$d^1qxecYUc94OF9uVJJ*lK zEEZw0%%*=y zbu#7`Fl)>{8W(4lzX(xvJ?;ErGFr#e9-1`B@-GsZWw;Fv+`SzOK`9q2vq=DQvaW`! zA#=IPt4!bi20m{A-pnK|77Ic>Nw*r8ld&~u{1h|9O&q(8)eL9+l^;7rFP=_#2w(bU zMkA>d-$NO>!*|CFd6UA9rA8H$3TLvDz-k}YvHXAJlYyJ=HGi{D!DrkyvKiM^V~YK3 zMkTr+(}d!!CrLm+mCI~qmkayTijRA3OD7kSbKu*CGj^V^awF4fRnW+&l<1g z4LDfo{CgSr-bOBz{?m*Sdi23G`gcjuV54y|Lhm9^Z7#^lw_N_UnXYTmEPK<&(V>8H zo2dWUv@lm$*Kw#I||7$ls&UFG0sIDze zw{0BNwLZ9h{oWW#>Iv{g^iC^0m2QIc;L{GkHWk0;(HNnIUJY^DhBZ=m0$Y+3Y>Waa za*h%XIzP4iNLx6kcm?Lt^^*!MsNUfM+v8rb5+%1ctD!GrhDvq1`I}4>ET(6gf5m%Z z=8m5R{Ik=8`(bB7)Z2BH=S*U=OB1PW@RC}_ul6MI?R0$frypH^1@=-u5c4+E;;bxp z-0fvGiJ4t?sO?|-v4Ha_qL~iBE_>o-{J=Nli`l6@+ zuhg}R-(sM|MZ*MrkB8VFbHMtzZ}QX4(l)aVH6ft%?mr>~(nDdZ`^Xc_9s+b&$4;Z5 z;VX9I4;BC|9D8E}z>k#9^!g=SFdID@A?h0qGglvfo{f(xPC&q_&P6$s`4WG+ir5AF3io z1iC$E{@tk^kSRJY(dttplS5AT9C#JX!q&^f<=o$AH9r z1-G1akGg*CeS!Q%|KMDP7}buhM8)iV&;DBP;su3t(2~hQcUX|`Jg>MJ_T5QTx1%IuwHG8jQg>x>a z|9&{y-Nk*f)M#^&e#S9M7fghh9E{S}76k2y9-uSabT>KxQXtU^xYT+FyvNb}XJC>X zyox=}bymcH5WSl)!+_Mw)5WUuUWeSfVA9B17-H88J`;eey(6yNsXtCY#2?(pJHIzF zaby63GgkD|GT`lC&P{4g*@wlGq(DJnwzLJv&3{!(AN^O!&IO7n5_-(PSnn{aw40zV1g-6i7iuI z|FZbu7aU^T;8!H@{^&@9tp;0}gaeM76Q(Xd7;w4?&;z*M437bmcL|-)Mvr7nbsh4N zkGRgpgZz&f1@_4>Nb0@egOjCLo1zbxn{WgrNJj=|$rjjpyo+9dc&NlGznbfMzu}@I z2omHmPyuuOkVi025GLUB!wQhn0=)&=^5F9bTsU979wgA;14NX)MMyE>*M7-l*K>W6 zU&R2>_;pO>1~@#1%>nut;5Pt}sXHEZ1zIc3c!96I^igZ-?=xG9XrW9iNA}I3DJ5(O%eYMID2;GqYz%EhW0(__Ql%f!pR{>tUk4yM5 zg^6ET5#3c?{0C-Uv}gf0eXv5+mNAVD18f}^uzj{%Pz6p30#QE1+~<6lhyZm=8duUi zmwbo|r8Y3vRRkZ!)y9D;kpn4yL)lN_zjs=M>uwO5?_)B9nHpM%P}sXU+;R28AN-L^ zFiMhM`~W%A-|!Tp2$FCODD(L8k<|e&`ZngEdbD%pwN}-yi!9F>W6TxjWwiU?P1MN@ zmx+9we2qUnggYEJz=a`L?*U08SqttnH?=zZg#7>W0zB_K?M?nO{8|5-KYxKQ0G38Z zbq1=Gkl)9#PMdIV(!kj_9V)R)wXrh^BnBf{U}U(l@sZOZ?=&$fih&Qj=SCP*t1>4f zV78K{T=X&}%&QW4v}EE=zf84__3HD4b0F-&n6af@=L>B7z7V$(bGD^^D(nexj>n7 ze8;JP=dv{`^~-4(P$nE)2=S+-Vxnj_QhjXYm_CMBL?Dj&9k&6@0tKwJzlj)=Uv97? zf^pt~&V%} zLS~hgLf!~j?@c8&EZIC!=&_9813P*Ub^1zgA3jjLA4bSw9K_@fAenbQ|ARt-FQSi% zCl2Lp3{X%kZlan~HG*c9Jhu^UDZvG7>gd>+AH)i$g_c|To)r2%yqGJR9uB~L%0T+t z`|jc(#}OAdIz?#@s}Ae1XgMsZgsdl8XdK(F9pP#8>SPINQfLW)p3}m_<}6@K*zPeb z&)ppZU`bJW0sJAtx=)jpSPo8gQh+)fK3vR4{`odv8Q26j+Q&h$323sIootn{v1qCw zA3qd)cKC60qvRS?3jW17h@mDz%u8IATK-43#U=iqm zF%T7g;0dIS8Rn9d`yx;FTW!?+5UpFV`rM(lsQhg*FOyr81Fc-zV95JRK5+Tkqa^5F-Sztfa z{P{0EQ_?D4!1#9IpbRJ8J(`uF`*>G1%kHZ}{%0je)p@&(6R(Qai=*r&{LObuo)}5(C z5Jg^2zXx2-vv^%g8%aOU#0JP7YM?JaRs8DB)4$LSAImCIeVS{dxnK2fP>bn700N(x zYy(?6OYKmx+_{1&MUkSrT&NG))tcgb&Arrn4om)m;OF>Ac)sANYgIeC*$ghCmScqL zllE}dmma|tihsJbTbirzzSUf zZ=&VP+af|-JDJN4(A=W1P7eMQ461f8z~MPLJZ;nA5tHTpa5j6lyVqGxgKU6j-UVD6 zT4)NIVtjt~^~!*1b=1KOdeN>{&MBNa4lp@|7Y*kCM;))Br+Ck?pbQCgCqJ8kJ{t^( zpehihFpE82r~(R@*5_@a6ar?~g3P3Z+ceIPo?=XS0y_IK%`UfUXY!)t?ScC=|6Lc; z7d<`h4|WuhXJhCS^)hg6?xCTg-?)_C`T$|RGWtNZuE2u>js;^A92E`Lub2OTiziIz z>A?p0WiL;ZR4QxqwDTVDUe{}CT2E@b!|^ue%)f{6i9rf`%qZoV(y^fvyioW(s^GfF zO`fSLtOo6y|MTtx=oKD}2%Q>E$G?p^(c~!~O|!vn72n?BDkuo3{7H=Pij_ZPLf3wz z?n#yIUc4TBD66AR<-2VBA1rU?Q@GFGx+arqq=ZCNKoa5?@bgd8%nuOxx-Cn2m3A?q z-@8p)Xl3jB4YuRPfLNdcL8#jaAgJjxIR7`U4S+nh0>j zEw^_$tz{=$Suk`D|IWR*xw#}WQW=OiA@?WeiwRAejigwrz*K%rx*b8<^i+^gVD2lJ zBW`teu_(OzS)Et@W0gSZn|2IYVcfk#$94n>s{m6p<$^crOQawNzD>M=%F9w0*20^6 zx;y@SXZrFa>Sc$eh9to9i}H(ffHo)2b7CxabNy^X8K4-hp#$(|jXyBq8eo4|?|1HLrAU}+hMvfJidg9S4`bDDHgAisXlsAFxO$*m(d z9ms%Si2fI0I(nXa(H_mkf9sjTts_9^5+GDdrS8k+(xS^9YVarz%Sp1(wzsGa3}{c= z^lxbS&6%LF&vz`u%{Vbk>3%JI;bE1QhYA$HkpD4R_%-kHUG7s>7--?{?6IE5<-v@G zKnfKy*tS=b^vsM~X^E=VDwFsvnpnRy^=7@P={S8Nza92yjtme)EPogkwRxFe{OidaKB@<)^%?4=l`rJDYxF6S_| zKShUZfo;6FPmqGib(NQ>yH^GP%I=LIhT(5qOn^J=$13TGoU#93A5-=4KO+SN_8bym zH!~YR5E9Y;zb*6k00%A3xO#lIF6N4^1WhI!Gch;eSAHZ@*-YCNuV#8U)?3;AY8<;6 zdjqG0Y#qzVHHQ>7Mf1uwWl0z>4A|Tbxs*(jk1P~L6=ONX+^a}1! z98pJIoGCCqQqpz6h2tsZE*&W`!OerR3%3@3fLOTmzxaBV zc4xnAkb1R(>d~LKP9ER`7nse9$RuNi=+G`#q!&c0zK4gv-6tN4EM|Bf%C+hD>FoVZ z1{@#vyaY0P-}|^cgWWy+W{y#pXS@9H-Mj zKr)Q|O_B=mEV_`1Ix|4Ybv*R-&Y$snI|a5>eafB$GS49>UPCM5HqXS_GUMYn5^PH` zED3L=(f>?c=@<;le5TYpsmsPP;VWHhFWB=rOf&D(q|v_>jBd{NKglr#-43lC4KwjS z+j2q-?Wz?~Bq}XVUe;ERT9Hf+*D(L#90L z*7Z2|+c)1-rmC*=Umyt)md!d_?!3iaXlq;|h0ddXrksKfyV2zDQ5td9Pe*axfJQNY zl@*2)xq-R~!P5RW1y>s?LA@tbuy1%P4yty9xX;9(zX`-Eg;6DGy}J5hPE!dd)`TQ# zzIwC3Z_|MR(Wc|H8DosXg14j88~$`){wUL4qz4{`{BSVAKQ)O^YBihkLtuuxgH?q) zHa8iAC|l&`*4>iYJjOrkX;ikiYgvP=|9F<2rxV{^in>2FLK*tlMx2>!oF%+8sY

      k+N69A7OIzJ44U(qBlCM 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�#m2UF`8-hD%Nv{LW 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ξ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%0A>b&uTXMoUpBTL3 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 OA6FNTt-o%epZ*Ieq{0ON literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png.mcmeta b/common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png.mcmeta new file mode 100644 index 000000000..3d481d190 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png.mcmeta @@ -0,0 +1,15 @@ +{ + "animation": { + "interpolate": false, + "frames": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 0 + ] + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index cc215f65f..3bb89bbc1 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -2,6 +2,7 @@ import com.mojang.blaze3d.platform.InputConstants; import mod.azure.azurelib.fabric.core2.example.FacehuggerRenderer; +import mod.azure.azurelib.fabric.core2.example.azure.DoomHunterRenderer; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; @@ -65,5 +66,6 @@ public void onInitializeClient() { EntityRendererRegistry.register(ExampleEntityTypes.DRONE, DroneRenderer::new); EntityRendererRegistry.register(ExampleEntityTypes.FACEHUGGER, FacehuggerRenderer::new); + EntityRendererRegistry.register(ExampleEntityTypes.DOOMHUNTER, DoomHunterRenderer::new); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java index a7c10ec0b..de622de2d 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java @@ -1,5 +1,6 @@ package mod.azure.azurelib.fabric.core2.example; +import mod.azure.azurelib.fabric.core2.example.azure.DoomHunter; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; @@ -21,6 +22,11 @@ public class ExampleEntityTypes { EntityType.Builder.of(Facehugger::new, MobCategory.MONSTER).sized(0.75f, 0.25f) ); + public static final EntityType DOOMHUNTER = register( + "doomhunter", + EntityType.Builder.of(DoomHunter::new, MobCategory.MONSTER).sized(3.0f, 7.0f) + ); + private static EntityType register(String name, EntityType.Builder builder) { var entityType = builder.build(name); var resourceLocation = AzureLib.modResource(name); @@ -31,5 +37,6 @@ private static EntityType register(String name, EntityType public static void initialize() { FabricDefaultAttributeRegistry.register(DRONE, Drone.createMonsterAttributes()); FabricDefaultAttributeRegistry.register(FACEHUGGER, Facehugger.createMonsterAttributes()); + FabricDefaultAttributeRegistry.register(DOOMHUNTER, DoomHunter.createMonsterAttributes()); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java new file mode 100644 index 000000000..81d156241 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java @@ -0,0 +1,61 @@ +package mod.azure.azurelib.fabric.core2.example.azure; + +import mod.azure.azurelib.common.api.common.ai.pathing.AzureNavigation; +import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.goal.*; +import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; +import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; +import net.minecraft.world.entity.ai.navigation.PathNavigation; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; + +public class DoomHunter extends Monster { + + private final AzAnimationDispatcher animationDispatcher; + + public DoomHunter(EntityType entityType, Level level) { + super(entityType, level); + this.animationDispatcher = new AzAnimationDispatcher<>(this); + } + + @Override + protected @NotNull PathNavigation createNavigation(@NotNull Level level) { + return new AzureNavigation(this, level); + } + + @Override + public float maxUpStep() { + return 2.0F; + } + + @Override + public void tick() { + super.tick(); + + if (this.level().isClientSide && !this.isAggressive()) { + animationDispatcher.dispatchFromClient("base_controller", "chainsaw"); + } + } + + @Override + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 0.6F, true)); + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.5F)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true)); + this.targetSelector.addGoal(1, (new HurtByTargetGoal(this)).setAlertOthers(DoomHunter.class)); + } + + @Override + protected void playStepSound(BlockPos pos, BlockState state) { + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java new file mode 100644 index 000000000..9286bd8ad --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java @@ -0,0 +1,36 @@ +package mod.azure.azurelib.fabric.core2.example.azure; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +public class DoomHunterAnimator extends AzEntityAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource("animations/entity/doomhunter.animation.json"); + + private static final String IDLE_ANIMATION_NAME = "idle"; + + private static final String MELEE_ANIMATION_NAME = "chainsaw"; + + private static final AzRawAnimation IDLE_ANIMATION = AzRawAnimation.begin().thenLoop(IDLE_ANIMATION_NAME); + + private static final AzRawAnimation MELEE_ANIMATION = AzRawAnimation.begin().thenLoop(MELEE_ANIMATION_NAME); + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + new AzAnimationController<>(this, "base_controller", 0) + .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) + .triggerableAnim(MELEE_ANIMATION_NAME, MELEE_ANIMATION) + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(DoomHunter drone) { + return ANIMATIONS; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterRenderer.java new file mode 100644 index 000000000..173a34337 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterRenderer.java @@ -0,0 +1,35 @@ +package mod.azure.azurelib.fabric.core2.example.azure; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class DoomHunterRenderer extends AzEntityRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/entity/doomhunter.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/doomhunter.png"); + + public DoomHunterRenderer(EntityRendererProvider.Context context) { + super(context); + } + + @Override + protected @Nullable AzEntityAnimator createAnimator() { + return new DoomHunterAnimator(); + } + + @Override + protected @NotNull ResourceLocation getModelLocation(DoomHunter doomHunter) { + return MODEL; + } + + @Override + public @NotNull ResourceLocation getTextureLocation(@NotNull DoomHunter doomHunter) { + return TEXTURE; + } +} From ad055c0912b81b832c0e0b49db3fd3e3370d6aff Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:21:45 -0500 Subject: [PATCH 043/224] Update drone.png --- .../assets/azurelib/textures/entity/drone.png | Bin 18747 -> 7581 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/common/src/main/resources/assets/azurelib/textures/entity/drone.png b/common/src/main/resources/assets/azurelib/textures/entity/drone.png index cdfe267d909739e7d482c20b571b7181dd9c9beb..36e88f7dbea75861f81f76572a91564935232338 100644 GIT binary patch literal 7581 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 Date: Thu, 12 Dec 2024 21:44:21 -0500 Subject: [PATCH 044/224] Update hugger to 4 model model with the animation limited to just those as reproduceable loggable model. --- .../entity/facehugger.animation.json | 1943 +---------------- .../azurelib/geo/entity/facehugger.geo.json | 348 +-- 2 files changed, 26 insertions(+), 2265 deletions(-) diff --git a/common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json b/common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json index 8e8afd594..3341a4bbe 100644 --- a/common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json +++ b/common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json @@ -1,1978 +1,83 @@ { "format_version": "1.8.0", "animations": { - "animation.tailsway": { - "loop": true, - "animation_length": 2, - "bones": { - "gTail1": { - "rotation": { - "vector": [-5.5, "Math.cos(query.anim_time*180)*-0.5", "Math.cos(query.anim_time*180)*-0.4"] - } - }, - "gTail2": { - "rotation": { - "vector": [-5, "Math.cos(query.anim_time*180)*-1", "Math.cos(query.anim_time*180)*-0.4"] - } - }, - "gTail3": { - "rotation": { - "vector": [-2, "Math.cos(query.anim_time*180)*-1", "Math.cos(query.anim_time*180)*-0.4"] - } - }, - "gTail4": { - "rotation": { - "vector": ["5+Math.sin(query.anim_time*180)*0.5", "Math.cos(query.anim_time*180)*-2", "Math.cos(query.anim_time*180)*-0.3"] - } - }, - "gTail5": { - "rotation": { - "vector": ["Math.cos(query.anim_time*180)+19.5", "Math.cos(query.anim_time*180)*-2.5", "Math.cos(query.anim_time*180)*-0.4"] - } - }, - "gTail6": { - "rotation": { - "vector": ["15+Math.sin(query.anim_time*180)*0.5", "Math.cos(query.anim_time*180)*-3", "Math.cos(query.anim_time*180)*-0.4"] - } - }, - "gTail7": { - "rotation": { - "vector": ["Math.cos(query.anim_time*180)+7", "Math.sin(query.anim_time*180)*-3.5", "Math.sin(query.anim_time*180)*-0.8"] - } - }, - "gTail8": { - "rotation": { - "vector": ["10+Math.sin(query.anim_time*180)*0.5", "Math.sin(query.anim_time*180)*-4", "Math.sin(query.anim_time*180)*-0.8"] - } - }, - "gTail9": { - "rotation": { - "vector": ["Math.cos(query.anim_time*180)+12", "Math.sin(query.anim_time*180)*-4.5", "Math.sin(query.anim_time*180)*-0.8"] - } - }, - "gTail10": { - "rotation": { - "vector": ["12.5+Math.sin(query.anim_time*180)*0.5", "Math.sin(query.anim_time*180)*-5", "Math.sin(query.anim_time*180)*-0.8"] - } - }, - "gTail11": { - "rotation": { - "vector": [0, "Math.sin(query.anim_time*180)*-5.5", "Math.sin(query.anim_time*180)*-0.8"] - } - }, - "gMainBody": { - "rotation": { - "vector": ["Math.cos(query.anim_time*180)*-0.5", 0, 0] - } - }, - "gLowerBody": { - "rotation": { - "vector": ["Math.sin(query.anim_time*180)*0.25", 0, 0] - } - } - } - }, - "animation.sack": { - "loop": true, - "animation_length": 2, - "bones": { - "gSackLeft": { - "scale": { - "0.0": { - "vector": [1, 1, 1] - }, - "1.0": { - "vector": [0.95, 0.95, 0.95], - "easing": "easeInQuad" - }, - "2.0": { - "vector": [1, 1, 1], - "easing": "easeInQuad" - } - } - }, - "gSackRight": { - "scale": { - "0.0": { - "vector": [1, 1, 1] - }, - "1.0": { - "vector": [0.95, 0.95, 0.95], - "easing": "easeInQuad" - }, - "2.0": { - "vector": [1, 1, 1], - "easing": "easeInQuad" - } - } - } - } - }, - "animation.tailflail": { - "loop": true, - "animation_length": 0.5, - "bones": { - "gTail1": { - "rotation": { - "vector": ["-7+Math.cos(query.anim_time*1630)*-0.4", "Math.cos(query.anim_time*680)*-1.5", "Math.cos(query.anim_time*650)*-0.4"] - } - }, - "gTail2": { - "rotation": { - "vector": ["-8.5+ Math.cos(query.anim_time*1630)*-0.4", "Math.cos(query.anim_time*680)*-3", "Math.cos(query.anim_time*650)*-0.4"] - } - }, - "gTail3": { - "rotation": { - "vector": ["7.5+Math.cos(query.anim_time*1630)*-0.4", "Math.cos(query.anim_time*680)*-4.5", "Math.cos(query.anim_time*650)*-0.4"] - } - }, - "gTail4": { - "rotation": { - "vector": ["Math.cos(query.anim_time*1630)*5.6", "Math.cos(query.anim_time*680)*-6", "Math.cos(query.anim_time*650)*-0.4"] - } - }, - "gTail5": { - "rotation": { - "vector": ["12.5+Math.cos(query.anim_time*1630)*-0.4", "Math.cos(query.anim_time*680)*-7.5", "Math.cos(query.anim_time*650)*-0.4"] - } - }, - "gTail6": { - "rotation": { - "vector": ["12.5+Math.cos(query.anim_time*1630)*-0.4", "Math.cos(query.anim_time*680)*-9", "Math.cos(query.anim_time*650)*-0.4"] - } - }, - "gTail7": { - "rotation": { - "vector": ["10+Math.sin(query.anim_time*1630)*-0.8", "Math.sin(query.anim_time*680)*-10.5", "Math.sin(query.anim_time*650)*-0.8"] - } - }, - "gTail8": { - "rotation": { - "vector": ["5+Math.sin(query.anim_time*1630)*-0.8", "Math.sin(query.anim_time*680)*-12", "Math.sin(query.anim_time*650)*-0.8"] - } - }, - "gTail9": { - "rotation": { - "vector": ["Math.sin(query.anim_time*1630)*-0.8", "Math.sin(query.anim_time*680)*-13.5", "Math.sin(query.anim_time*650)*-0.8"] - } - }, - "gTail10": { - "rotation": { - "vector": ["Math.sin(query.anim_time*1630)*-0.8", "Math.sin(query.anim_time*600)*-15", "Math.sin(query.anim_time*600)*-0.8"] - } - }, - "gTail11": { - "rotation": { - "vector": ["Math.sin(query.anim_time*1630)*-0.8", "Math.sin(query.anim_time*680)*-15", "Math.sin(query.anim_time*650)*-0.8"] - } - } - } - }, "animation.run": { "loop": true, "animation_length": 0.5, "bones": { - "gWholeBody": { - "rotation": { - "vector": [0, "Math.cos(query.anim_time*680)*2.5", "Math.sin(query.anim_time*650)*2.5"] - }, - "position": { - "vector": [0, -1.2, 0] - } - }, - "gLowerBody": { - "rotation": { - "vector": ["-11+Math.sin(query.anim_time*680)*0.25", 0, 0] - } - }, - "gLMidLeg1": { - "rotation": { - "vector": [0, 0, 20] - } - }, - "gLMidLeg2": { - "rotation": { - "vector": [0, 0, 20] - } - }, - "gLBottomLeg": { - "rotation": { - "vector": [0, 0, 20] - } - }, - "gLBottomLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, -42.5] - }, - "0.0417": { - "vector": [0, 0, -55], - "easing": "easeOutSine" - }, - "0.0833": { - "vector": [0, 0, -60], - "easing": "easeOutSine" - }, - "0.125": { - "vector": [0, 0, -67.5], - "easing": "easeOutSine" - }, - "0.1667": { - "vector": [0, 0, -50], - "easing": "easeOutSine" - }, - "0.25": { - "vector": [0, 0, -42.5], - "easing": "easeOutSine" - }, - "0.2917": { - "vector": [0, 0, -52.5], - "easing": "easeOutSine" - }, - "0.3333": { - "vector": [0, 0, -55], - "easing": "easeOutSine" - }, - "0.375": { - "vector": [0, 0, -62.5], - "easing": "easeOutSine" - }, - "0.4167": { - "vector": [0, 0, -47.5], - "easing": "easeOutSine" - }, - "0.5": { - "vector": [0, 0, -40], - "easing": "easeOutSine" - } - } - }, - "gLBottomLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 8.5] - }, - "0.0417": { - "vector": [0, 0, 31], - "easing": "easeOutSine" - }, - "0.0833": { - "vector": [0, 0, 41], - "easing": "easeOutSine" - }, - "0.125": { - "vector": [0, 0, 8.5], - "easing": "easeOutSine" - }, - "0.1667": { - "vector": [0, 0, -4], - "easing": "easeOutSine" - }, - "0.25": { - "vector": [0, 0, 8.5], - "easing": "easeOutSine" - }, - "0.2917": { - "vector": [0, 0, 33.5], - "easing": "easeOutSine" - }, - "0.3333": { - "vector": [0, 0, 41], - "easing": "easeOutSine" - }, - "0.375": { - "vector": [0, 0, 8.5], - "easing": "easeOutSine" - }, - "0.4167": { - "vector": [0, 0, -4], - "easing": "easeOutSine" - }, - "0.5": { - "vector": [0, 0, 8.5], - "easing": "easeOutSine" - } - } - }, - "gLFrontLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, -32.5] - }, - "0.0417": { - "vector": [0, 0, -16] - }, - "0.0833": { - "vector": [0, 0, -1] - }, - "0.125": { - "vector": [0, 0, -21] - }, - "0.1667": { - "vector": [0, 0, -30] - }, - "0.25": { - "vector": [0, 0, -32.5] - }, - "0.2917": { - "vector": [0, 0, -16] - }, - "0.3333": { - "vector": [0, 0, 1.5] - }, - "0.375": { - "vector": [0, 0, -18.5] - }, - "0.4167": { - "vector": [0, 0, -27.5] - }, - "0.5": { - "vector": [0, 0, -32.5] - } - } - }, - "gLFrontLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, -32.5] - }, - "0.0417": { - "vector": [0, 0, -32], - "easing": "easeOutQuad" - }, - "0.0833": { - "vector": [0, 0, -33.5], - "easing": "easeOutQuad" - }, - "0.125": { - "vector": [0, 0, 3.5], - "easing": "easeOutQuad" - }, - "0.1667": { - "vector": [0, 0, 25.5], - "easing": "easeOutQuad" - }, - "0.25": { - "vector": [0, 0, -32.5] - }, - "0.2917": { - "vector": [0, 0, -32], - "easing": "easeOutQuad" - }, - "0.3333": { - "vector": [0, 0, -31], - "easing": "easeOutQuad" - }, - "0.375": { - "vector": [0, 0, 6], - "easing": "easeOutQuad" - }, - "0.4167": { - "vector": [0, 0, 28], - "easing": "easeOutQuad" - }, - "0.5": { - "vector": [0, 0, -32.5], - "easing": "easeOutQuad" - } - } - }, - "gLMidLeg1Mid": { + "gRFrontLegMid": { "rotation": { "0.0": { - "vector": [0, 0, -32] + "vector": [0, 0, 1] }, "0.0417": { - "vector": [0, 0, -45] + "vector": [0, 0, 21] }, "0.0833": { - "vector": [0, 0, -57.5] + "vector": [0, 0, 30] }, "0.125": { - "vector": [0, 0, -62.5] + "vector": [0, 0, 32.5] }, "0.1667": { - "vector": [0, 0, -40] + "vector": [0, 0, 16] }, "0.25": { - "vector": [0, 0, -32] + "vector": [0, 0, 1] }, "0.2917": { - "vector": [0, 0, -42.5] + "vector": [0, 0, 21] }, "0.3333": { - "vector": [0, 0, -57.5] + "vector": [0, 0, 30] }, "0.375": { - "vector": [0, 0, -62.5] + "vector": [0, 0, 32.5] }, "0.4167": { - "vector": [0, 0, -40] + "vector": [0, 0, 16] }, "0.5": { - "vector": [0, 0, -29.5] + "vector": [0, 0, 1] } } }, - "gLMidLeg1Bottom": { + "gRFrontLegBottom": { "rotation": { "0.0": { - "vector": [0, 0, -15] + "vector": [0, 0, 33.5] }, "0.0417": { - "vector": [0, 0, 12.5] + "vector": [0, 0, 3.5] }, "0.0833": { - "vector": [0, 0, 35] + "vector": [0, 0, -25.5] }, "0.125": { - "vector": [0, 0, -5] + "vector": [0, 0, 32.5] }, "0.1667": { - "vector": [0, 0, -25] + "vector": [0, 0, 32] }, "0.25": { - "vector": [0, 0, -15] + "vector": [0, 0, 33.5] }, "0.2917": { - "vector": [0, 0, 12.5] + "vector": [0, 0, 3.5] }, "0.3333": { - "vector": [0, 0, 35] + "vector": [0, 0, -25.5] }, "0.375": { - "vector": [0, 0, -5] + "vector": [0, 0, 32.5] }, "0.4167": { - "vector": [0, 0, -25] + "vector": [0, 0, 32] }, "0.5": { - "vector": [0, 0, -15] + "vector": [0, 0, 33.5] } } - }, - "gLMidLeg2Mid": { - "rotation": { - "0.0": { - "vector": [0, 0, -70] - }, - "0.0417": { - "vector": [0, 0, -47.5] - }, - "0.0833": { - "vector": [0, 0, -32.5] - }, - "0.125": { - "vector": [0, 0, -50] - }, - "0.1667": { - "vector": [0, 0, -67] - }, - "0.25": { - "vector": [0, 0, -70] - }, - "0.2917": { - "vector": [0, 0, -47.5] - }, - "0.3333": { - "vector": [0, 0, -27.5] - }, - "0.375": { - "vector": [0, 0, -45] - }, - "0.4167": { - "vector": [0, 0, -62] - }, - "0.5": { - "vector": [0, 0, -70] - } - } - }, - "gLMidLeg2Bottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.0417": { - "vector": [0, 0, -12.5], - "easing": "easeInQuad" - }, - "0.0833": { - "vector": [0, 0, -15.5], - "easing": "easeInQuad" - }, - "0.125": { - "vector": [0, 0, 15.5], - "easing": "easeInQuad" - }, - "0.1667": { - "vector": [0, 0, 47.5], - "easing": "easeInQuad" - }, - "0.25": { - "vector": [0, 0, 0], - "easing": "easeInQuad" - }, - "0.2917": { - "vector": [0, 0, -10], - "easing": "easeInQuad" - }, - "0.3333": { - "vector": [0, 0, -10.5], - "easing": "easeInQuad" - }, - "0.375": { - "vector": [0, 0, 20.5], - "easing": "easeInQuad" - }, - "0.4167": { - "vector": [0, 0, 50], - "easing": "easeInQuad" - }, - "0.5": { - "vector": [0, 0, 0], - "easing": "easeInQuad" - } - } - }, - "gRFrontLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, 1] - }, - "0.0417": { - "vector": [0, 0, 21] - }, - "0.0833": { - "vector": [0, 0, 30] - }, - "0.125": { - "vector": [0, 0, 32.5] - }, - "0.1667": { - "vector": [0, 0, 16] - }, - "0.25": { - "vector": [0, 0, 1] - }, - "0.2917": { - "vector": [0, 0, 21] - }, - "0.3333": { - "vector": [0, 0, 30] - }, - "0.375": { - "vector": [0, 0, 32.5] - }, - "0.4167": { - "vector": [0, 0, 16] - }, - "0.5": { - "vector": [0, 0, 1] - } - } - }, - "gRFrontLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 33.5] - }, - "0.0417": { - "vector": [0, 0, 3.5] - }, - "0.0833": { - "vector": [0, 0, -25.5] - }, - "0.125": { - "vector": [0, 0, 32.5] - }, - "0.1667": { - "vector": [0, 0, 32] - }, - "0.25": { - "vector": [0, 0, 33.5] - }, - "0.2917": { - "vector": [0, 0, 3.5] - }, - "0.3333": { - "vector": [0, 0, -25.5] - }, - "0.375": { - "vector": [0, 0, 32.5] - }, - "0.4167": { - "vector": [0, 0, 32] - }, - "0.5": { - "vector": [0, 0, 33.5] - } - } - }, - "gRMidLeg1Mid": { - "rotation": { - "0.0": { - "vector": [0, 0, 30] - }, - "0.0417": { - "vector": [0, 0, 35], - "easing": "easeInExpo" - }, - "0.0833": { - "vector": [0, 0, 12.5], - "easing": "easeInExpo" - }, - "0.125": { - "vector": [0, 0, 32], - "easing": "easeInExpo" - }, - "0.1667": { - "vector": [0, 0, 17.5], - "easing": "easeInExpo" - }, - "0.25": { - "vector": [0, 0, 27.5] - }, - "0.2917": { - "vector": [0, 0, 32.5], - "easing": "easeInExpo" - }, - "0.3333": { - "vector": [0, 0, 10], - "easing": "easeInExpo" - }, - "0.375": { - "vector": [0, 0, 29.5], - "easing": "easeInExpo" - }, - "0.4167": { - "vector": [0, 0, 25], - "easing": "easeInExpo" - }, - "0.5": { - "vector": [0, 0, 32.5] - } - } - }, - "gRMidLeg1Bottom": { - "rotation": { - "0.0": { - "vector": [0, 0, -35] - }, - "0.0417": { - "vector": [0, 0, 5] - }, - "0.0833": { - "vector": [0, 0, 25] - }, - "0.125": { - "vector": [0, 0, -15] - }, - "0.1667": { - "vector": [0, 0, -12.5] - }, - "0.25": { - "vector": [0, 0, -35] - }, - "0.2917": { - "vector": [0, 0, 5] - }, - "0.3333": { - "vector": [0, 0, 25] - }, - "0.375": { - "vector": [0, 0, -15] - }, - "0.4167": { - "vector": [0, 0, -12.5] - }, - "0.5": { - "vector": [0, 0, -35] - } - } - }, - "gRMidLeg2Mid": { - "rotation": { - "0.0": { - "vector": [0, 0, 5] - }, - "0.0417": { - "vector": [0, 0, 22.5] - }, - "0.0833": { - "vector": [0, 0, 32] - }, - "0.125": { - "vector": [0, 0, 42.5] - }, - "0.1667": { - "vector": [0, 0, 20] - }, - "0.25": { - "vector": [0, 0, 5] - }, - "0.2917": { - "vector": [0, 0, 22.5] - }, - "0.3333": { - "vector": [0, 0, 32] - }, - "0.375": { - "vector": [0, 0, 42.5] - }, - "0.4167": { - "vector": [0, 0, 20] - }, - "0.5": { - "vector": [0, 0, 7.5] - } - } - }, - "gRMidLeg2Bottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 15.5] - }, - "0.0417": { - "vector": [0, 0, -15.5] - }, - "0.0833": { - "vector": [0, 0, -47.5] - }, - "0.125": { - "vector": [0, 0, 0] - }, - "0.1667": { - "vector": [0, 0, 12.5] - }, - "0.25": { - "vector": [0, 0, 15.5] - }, - "0.2917": { - "vector": [0, 0, -15.5] - }, - "0.3333": { - "vector": [0, 0, -47.5] - }, - "0.375": { - "vector": [0, 0, 0] - }, - "0.4167": { - "vector": [0, 0, 12.5] - }, - "0.5": { - "vector": [0, 0, 15.5] - } - } - }, - "gRBottomLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, 30] - }, - "0.0417": { - "vector": [0, 0, 40] - }, - "0.0833": { - "vector": [0, 0, 22.5] - }, - "0.125": { - "vector": [0, 0, 15] - }, - "0.1667": { - "vector": [0, 0, 25] - }, - "0.25": { - "vector": [0, 0, 30] - }, - "0.2917": { - "vector": [0, 0, 40] - }, - "0.3333": { - "vector": [0, 0, 22.5] - }, - "0.375": { - "vector": [0, 0, 22.5] - }, - "0.4167": { - "vector": [0, 0, 32.5] - }, - "0.5": { - "vector": [0, 0, 35] - } - } - }, - "gRBottomLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, -41] - }, - "0.0417": { - "vector": [0, 0, -8.5] - }, - "0.0833": { - "vector": [0, 0, 4] - }, - "0.125": { - "vector": [0, 0, -8.5] - }, - "0.1667": { - "vector": [0, 0, -31] - }, - "0.25": { - "vector": [0, 0, -41] - }, - "0.2917": { - "vector": [0, 0, -8.5] - }, - "0.3333": { - "vector": [0, 0, 4] - }, - "0.375": { - "vector": [0, 0, -8.5] - }, - "0.4167": { - "vector": [0, 0, -31] - }, - "0.5": { - "vector": [0, 0, -41] - } - } - } - } - }, - "animation.leap": { - "loop": "hold_on_last_frame", - "animation_length": 1, - "bones": { - "gWholeBody": { - "position": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [0, -2, 0] - } - } - }, - "gLFrontLeg": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [0, 0, -15] - }, - "1.0": { - "vector": [0, 0, 0] - } - } - }, - "gLFrontLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [0, 0, -17.5] - }, - "1.0": { - "vector": [0, 0, 3] - } - } - }, - "gLFrontLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [0, 0, -52.5] - }, - "1.0": { - "vector": [0, 0, -65] - } - } - }, - "gRFrontLeg": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [0, 0, 15] - }, - "1.0": { - "vector": [0, 0, 0] - } - } - }, - "gRFrontLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [0, 0, 17.5] - }, - "1.0": { - "vector": [0, 0, -3] - } - } - }, - "gRFrontLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [0, 0, 52.5] - }, - "1.0": { - "vector": [0, 0, 65] - } - } - }, - "gLeftSide": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [0, 0, -15] - } - } - }, - "gLMidLeg1": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [28, 8, 19] - }, - "0.75": { - "vector": [39, -4, 39] - }, - "1.0": { - "vector": [-8, 14, 6] - } - } - }, - "gLMidLeg1Mid": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [5, -2, -20], - "easing": "linear" - }, - "0.375": { - "vector": [4, -1, -18], - "easing": "linear" - }, - "0.5": { - "vector": [-3, -2, -13], - "easing": "easeInExpo" - }, - "0.75": { - "vector": [-3, 1, 45] - }, - "1.0": { - "vector": [-3, -2, -3] - } - } - }, - "gLMidLeg1Bottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [1, 4, 22], - "easing": "easeInElastic", - "easingArgs": [6] - }, - "0.75": { - "vector": [-4, 2, -49] - }, - "1.0": { - "vector": [-4, 1, -59] - } - }, - "position": { - "0.5": { - "vector": [0, 0, 0] - }, - "0.75": { - "vector": [0.39619, -0.1141, 0.00413] - } - } - }, - "gLMidLeg2": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [31, 15, 10] - }, - "0.75": { - "vector": [26, 6, 25] - }, - "1.0": { - "vector": [-7, 4, 10] - } - } - }, - "gLMidLeg2Mid": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [1, -2, -21] - }, - "0.375": { - "vector": [1, -2, -29] - }, - "0.4583": { - "vector": [0, -1, -14] - }, - "0.5": { - "vector": [0, 0, -33], - "easing": "easeInExpo" - }, - "0.75": { - "vector": [0, 0, 47] - }, - "1.0": { - "vector": [0, 0, -8] - } - } - }, - "gLMidLeg2Bottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [0, 0, 60], - "easing": "easeInOutElastic", - "easingArgs": [4] - }, - "0.75": { - "vector": [0, 0, -38] - }, - "1.0": { - "vector": [0, 0, -55] - } - }, - "position": { - "0.5": { - "vector": [0, 0, 0] - }, - "0.75": { - "vector": [0.21346, -0.39277, -0.0131] - }, - "1.0": { - "vector": [0.21, -0.39, -0.01] - } - } - }, - "gLBottomLeg": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [28, 19, -3] - }, - "0.75": { - "vector": [23, 11, 13] - }, - "1.0": { - "vector": [-4, 0, 3] - } - } - }, - "gLBottomLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [-2, 0, -21] - }, - "0.375": { - "vector": [-1, 0, -27] - }, - "0.5": { - "vector": [0, 0, -27.5], - "easing": "easeInExpo" - }, - "0.75": { - "vector": [0, 0, 53] - }, - "1.0": { - "vector": [0, 0, -8] - } - } - }, - "gLBottomLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [0, 0, 55], - "easing": "easeInOutElastic", - "easingArgs": [1] - }, - "0.75": { - "vector": [0, 0, -38] - }, - "1.0": { - "vector": [0, 0, -53] - } - } - }, - "gRightSide": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [0, 0, 15] - } - } - }, - "gRMidLeg1Mid": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [5, 2, 20] - }, - "0.375": { - "vector": [4, 1, 18] - }, - "0.5": { - "vector": [0, 0, 19] - }, - "0.75": { - "vector": [3, -1, -45] - }, - "1.0": { - "vector": [3, 2, -3] - } - } - }, - "gRMidLeg1Bottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [1, -4, -22], - "easing": "easeInElastic", - "easingArgs": [6] - }, - "0.75": { - "vector": [-4, -2, 49] - }, - "1.0": { - "vector": [-4, -1, 59] - } - }, - "position": { - "0.5": { - "vector": [0, 0, 0] - }, - "0.75": { - "vector": [-0.38391, -0.09245, -0.0264] - } - } - }, - "gRMidLeg2Mid": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [1, -2, 21] - }, - "0.375": { - "vector": [1, 2, 29] - }, - "0.4583": { - "vector": [0, 1, 14] - }, - "0.5": { - "vector": [0, 0, 33] - }, - "0.75": { - "vector": [0, 0, -47] - }, - "1.0": { - "vector": [0, 0, -8] - } - } - }, - "gRMidLeg2Bottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [0, 0, -60] - }, - "0.75": { - "vector": [0, 0, 38] - }, - "1.0": { - "vector": [0, 0, 55] - } - }, - "position": { - "0.5": { - "vector": [0, 0, 0] - }, - "0.75": { - "vector": [-0.36551, -0.25416, -0.01] - }, - "1.0": { - "vector": [-0.37, -0.25, -0.01] - } - } - }, - "gRBottomLeg": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [28, -19, 3] - }, - "0.75": { - "vector": [23, -11, -13] - }, - "1.0": { - "vector": [-4, 0, -3] - } - } - }, - "gRBottomLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.25": { - "vector": [2, 0, 21] - }, - "0.375": { - "vector": [1, 0, 27] - }, - "0.5": { - "vector": [0, 0, 27.5] - }, - "0.75": { - "vector": [0, 0, -53] - }, - "1.0": { - "vector": [0, 0, 8] - } - } - }, - "gRBottomLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [0, 0, -55], - "easing": "easeInOutElastic", - "easingArgs": [1] - }, - "0.75": { - "vector": [0, 0, 38] - }, - "1.0": { - "vector": [0, 0, 53] - } - } - }, - "gLowerBody": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [22.5, 0, 0] - }, - "0.6667": { - "vector": [2.5, 0, 0] - }, - "1.0": { - "vector": [25, 0, 0] - } - } - }, - "gTail1": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [0.62758, 19.6835, 3.61644], - "easing": "easeInOutSine" - }, - "1.0": { - "vector": [0, 0, 0] - } - } - }, - "gTail2": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [9.50596, -70.30667, -8.99253], - "easing": "easeInOutSine" - }, - "1.0": { - "vector": [0, 0, 0] - } - } - }, - "gTail3": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [-3.4038, -51.72343, -9.85026], - "easing": "easeInOutSine" - }, - "1.0": { - "vector": [5, 0, 0] - } - } - }, - "gTail4": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [8.72705, 74.11249, 18.71331], - "easing": "easeInOutSine" - }, - "1.0": { - "vector": [5, 0, 0] - } - } - }, - "gTail5": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.1667": { - "vector": [24.91131, 16.54561, 40.56656] - }, - "0.5": { - "vector": [159.64524, 66.18244, 162.26626], - "easing": "easeInOutSine" - }, - "0.7917": { - "vector": [30.34459, 8.75787, 33.21299] - }, - "1.0": { - "vector": [5, 0, 0] - } - } - }, - "gTail6": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.2917": { - "vector": [15.1586, 11.48604, 5.77037] - }, - "0.3333": { - "vector": [13.68098, 14.16562, 5.81233] - }, - "0.5": { - "vector": [-0.31521, 39.54698, 6.20975], - "easing": "easeInOutSine" - }, - "0.7917": { - "vector": [12.36866, 16.47791, 2.5874] - }, - "1.0": { - "vector": [5, 0, 0] - } - } - }, - "gTail7": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [1.48528, -64.27201, -11.77905], - "easing": "easeInOutSine" - }, - "1.0": { - "vector": [7.5, 0, 0] - } - } - }, - "gTail8": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.125": { - "vector": [28.58147, -32.08955, -22.12633] - }, - "0.25": { - "vector": [44.53674, -54.27114, -77.87602] - }, - "0.375": { - "vector": [187.05612, -77.32591, -191.78217] - }, - "0.5": { - "vector": [188.70832, -71.31063, -190.44535], - "easing": "easeInOutSine" - }, - "0.7917": { - "vector": [48.62847, -29.71276, -79.35223] - }, - "1.0": { - "vector": [5, 0, 0] - } - } - }, - "gTail9": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.125": { - "vector": [1.86218, -22.39881, 12.94741] - }, - "0.3333": { - "vector": [13.55561, -28.83001, 3.72954] - }, - "0.5": { - "vector": [2.84529, -38.89591, -12.03609], - "easing": "easeInOutSine" - }, - "0.7917": { - "vector": [28.68554, -16.20663, -5.01504] - }, - "1.0": { - "vector": [5, 0, 0] - } - } - }, - "gTail10": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.125": { - "vector": [2.8142, -19.66726, 13.79217] - }, - "0.3333": { - "vector": [12.39061, -17.37222, 3.8378] - }, - "0.5": { - "vector": [-1.99961, -19.87032, -2.40596], - "easing": "easeInOutSine" - }, - "0.7917": { - "vector": [21.66683, -8.2793, -1.00248] - }, - "1.0": { - "vector": [2.5, 0, 0] - } - } - }, - "gTail11": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.125": { - "vector": [4.34312, -11.50509, 19.45564] - }, - "0.5": { - "vector": [7.15184, 64.18323, 12.64352], - "easing": "easeInOutSine" - }, - "1.0": { - "vector": [2.5, 0, 0] - } - } - }, - "root": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [-32.5, 0, 0] - }, - "0.625": { - "vector": [-32.5, 0, 0] - }, - "1.0": { - "vector": [-90, 0, 0] - } - }, - "position": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [0, 0, 0] - }, - "0.75": { - "vector": [0, 5, 0] - } - } - }, - "gRMidLeg1": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [30, -6, -24] - }, - "0.75": { - "vector": [39, 4, -39] - }, - "1.0": { - "vector": [-8, -14, -6] - } - } - }, - "gRMidLeg2": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.5": { - "vector": [31, -15, -10] - }, - "0.75": { - "vector": [26, -6, -25] - }, - "1.0": { - "vector": [-7, -4, -10] - } - } - } - } - }, - "animation.hug": { - "loop": "hold_on_last_frame", - "animation_length": 1, - "bones": { - "gWholeBody": { - "position": { - "vector": [0, -2, 0] - } - }, - "gLFrontLeg": { - "rotation": { - "vector": [0, 0, 0] - } - }, - "gLFrontLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, 3] - }, - "0.5": { - "vector": [0, 0, 9], - "easing": "easeOutElastic" - } - } - }, - "gLFrontLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, -65] - }, - "0.5": { - "vector": [0, 0, 5], - "easing": "easeOutElastic" - } - } - }, - "gRFrontLeg": { - "rotation": { - "vector": [0, 0, 0] - } - }, - "gRFrontLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, -3] - }, - "0.5": { - "vector": [0, 0, -3], - "easing": "easeOutElastic" - } - } - }, - "gRFrontLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 65] - }, - "0.5": { - "vector": [0, 0, -12], - "easing": "easeOutElastic" - } - } - }, - "gLeftSide": { - "rotation": { - "vector": [0, 0, -15] - } - }, - "gLMidLeg1": { - "rotation": { - "vector": [-8, 14, 6] - } - }, - "gLMidLeg1Mid": { - "rotation": { - "0.0": { - "vector": [-3, -2, -3] - }, - "0.5": { - "vector": [-3.5975, -0.2333, 26.95495], - "easing": "easeOutElastic", - "easingArgs": [2] - } - } - }, - "gLMidLeg1Bottom": { - "rotation": { - "0.0": { - "vector": [-4, 1, -59] - }, - "0.5": { - "vector": [-0.49984, 4.09255, 10.01706], - "easing": "easeOutExpo" - } - }, - "position": { - "vector": [0.4, -0.11, 0] - } - }, - "gLMidLeg2": { - "rotation": { - "vector": [-7, 4, 10] - } - }, - "gLMidLeg2Mid": { - "rotation": { - "0.0": { - "vector": [0, 0, -8] - }, - "0.5": { - "vector": [0, 0, 42], - "easing": "easeOutElastic", - "easingArgs": [2] - } - } - }, - "gLMidLeg2Bottom": { - "rotation": { - "0.0": { - "vector": [0, 0, -55] - }, - "0.5": { - "vector": [0, 0, -4], - "easing": "easeOutExpo" - } - }, - "position": { - "vector": [0.21, -0.39, -0.01] - } - }, - "gLBottomLeg": { - "rotation": { - "vector": [-4, 0, 3] - } - }, - "gLBottomLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, -8] - }, - "0.5": { - "vector": [0, 0, 50], - "easing": "easeOutElastic" - } - } - }, - "gLBottomLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, -53] - }, - "0.5": { - "vector": [0, 0, -8], - "easing": "easeOutExpo" - } - } - }, - "gRightSide": { - "rotation": { - "vector": [0, 0, 15] - } - }, - "gRMidLeg1Mid": { - "rotation": { - "0.0": { - "vector": [3, 2, -3] - }, - "0.5": { - "vector": [1.9804, 3.01297, -26.00029], - "easing": "easeOutElastic", - "easingArgs": [2] - } - } - }, - "gRMidLeg1Bottom": { - "rotation": { - "0.0": { - "vector": [-4, -1, 59] - }, - "0.5": { - "vector": [-0.14064, -4.12051, -15.02986], - "easing": "easeOutExpo" - } - }, - "position": { - "vector": [-0.38, -0.09, -0.03] - } - }, - "gRMidLeg2Mid": { - "rotation": { - "0.0": { - "vector": [0, 0, -8] - }, - "0.5": { - "vector": [0, 0, -41], - "easing": "easeOutElastic", - "easingArgs": [2] - } - } - }, - "gRMidLeg2Bottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 55] - }, - "0.5": { - "vector": [0, 0, 1], - "easing": "easeOutExpo" - } - }, - "position": { - "vector": [-0.37, -0.25, -0.01] - } - }, - "gRBottomLeg": { - "rotation": { - "vector": [-4, 0, -3] - } - }, - "gRBottomLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, 8] - }, - "0.5": { - "vector": [0, 0, -47], - "easing": "easeOutElastic" - } - } - }, - "gRBottomLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 53] - }, - "0.5": { - "vector": [0, 0, 4], - "easing": "easeOutExpo" - } - } - }, - "gLowerBody": { - "rotation": { - "0.0": { - "vector": [25, 0, 0] - }, - "0.5": { - "vector": [-10, 0, 0] - } - } - }, - "gTail1": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.8333": { - "vector": [0, -27.5, 0], - "easing": "easeInExpo" - } - } - }, - "gTail2": { - "rotation": { - "0.0": { - "vector": [0, 0, 0] - }, - "0.8333": { - "vector": [-16.21137, -47.24891, -22.58857], - "easing": "easeInExpo" - } - } - }, - "gTail3": { - "rotation": { - "0.0": { - "vector": [5, 0, 0] - }, - "0.8333": { - "vector": [3.43152, -22.7754, -2.55335], - "easing": "easeInExpo" - } - } - }, - "gTail4": { - "rotation": { - "0.0": { - "vector": [5, 0, 0] - }, - "0.8333": { - "vector": [-10.64538, -20.54777, 0.36816], - "easing": "easeInExpo" - } - } - }, - "gTail5": { - "rotation": { - "0.0": { - "vector": [5, 0, 0] - }, - "0.8333": { - "vector": [-21.76638, -21.57644, 11.52333], - "easing": "easeInExpo" - } - } - }, - "gTail6": { - "rotation": { - "0.0": { - "vector": [5, 0, 0] - }, - "0.8333": { - "vector": [-24.62328, 12.59297, -1.83968], - "easing": "easeInExpo" - } - } - }, - "gTail7": { - "rotation": { - "0.0": { - "vector": [7.5, 0, 0] - }, - "0.875": { - "vector": [-6.41797, 27.79564, -8.65747], - "easing": "easeInExpo" - } - } - }, - "gTail8": { - "rotation": { - "0.0": { - "vector": [5, 0, 0] - }, - "0.9167": { - "vector": [-46.34717, -35.75299, 16.98305], - "easing": "easeInExpo" - } - } - }, - "gTail9": { - "rotation": { - "0.0": { - "vector": [5, 0, 0] - }, - "0.9583": { - "vector": [-43.8764, -31.91772, 31.35942], - "easing": "easeInExpo" - } - } - }, - "gTail10": { - "rotation": { - "0.0": { - "vector": [2.5, 0, 0] - }, - "1.0": { - "vector": [17.06812, -8.43755, -9.68622], - "easing": "easeInExpo" - } - } - }, - "gTail11": { - "rotation": { - "0.0": { - "vector": [2.5, 0, 0] - }, - "1.0": { - "vector": [28.99061, -19.72598, -15.93986], - "easing": "easeInExpo" - } - } - }, - "root": { - "rotation": { - "vector": [-90, 0, 0] - }, - "position": { - "vector": [0, 5, 0] - } - }, - "gRMidLeg1": { - "rotation": { - "vector": [-8, -14, -6] - } - }, - "gRMidLeg2": { - "rotation": { - "vector": [-7, -4, -10] - } } } } diff --git a/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json b/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json index fb4306d0c..03fce4a38 100644 --- a/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json +++ b/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json @@ -1,5 +1,5 @@ { - "format_version": "1.12.0", + "format_version": "1.21.20", "minecraft:geometry": [ { "description": { @@ -20,34 +20,6 @@ "parent": "root", "pivot": [0, 4, 0] }, - { - "name": "gLFrontLeg", - "parent": "gWholeBody", - "pivot": [1.03227, 3.85146, -2.40085], - "rotation": [0, 47.5, -12.5], - "cubes": [ - {"origin": [0.36561, 2.95146, -2.90085], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15]} - ] - }, - { - "name": "gLFrontLegMid", - "parent": "gLFrontLeg", - "pivot": [2.06732, 3.37757, -2.40085], - "rotation": [0, 0, 7.5], - "cubes": [ - {"origin": [1.50206, 2.97329, -5.30085], "size": [1, 1, 3], "inflate": -0.1, "pivot": [2.00206, 3.87329, -2.40085], "rotation": [0, -90, 0], "uv": [15, 18], "mirror": true} - ] - }, - { - "name": "gLFrontLegBottom", - "parent": "gLFrontLegMid", - "pivot": [4.50361, 3.42542, -2.44872], - "rotation": [0, 0, 75], - "cubes": [ - {"origin": [3.91895, 2.90714, -5.00085], "size": [1, 1, 3], "inflate": -0.15, "pivot": [4.41895, 3.30714, -2.40085], "rotation": [0, -90, 0], "uv": [15, 23], "mirror": true}, - {"origin": [2.61895, 2.60714, -7.80085], "size": [3, 2, 4], "inflate": -1, "pivot": [4.11895, 3.40714, -2.40085], "rotation": [0, -90, 0], "uv": [12, 28]} - ] - }, { "name": "gRFrontLeg", "parent": "gWholeBody", @@ -72,323 +44,7 @@ "pivot": [-4.50361, 3.42542, -2.44872], "rotation": [0, 0, -75], "cubes": [ - {"origin": [-4.91895, 2.90714, -5.00085], "size": [1, 1, 3], "inflate": -0.15, "pivot": [-4.41895, 3.30714, -2.40085], "rotation": [0, 90, 0], "uv": [15, 23]}, - {"origin": [-5.61895, 2.60714, -7.80085], "size": [3, 2, 4], "inflate": -1, "pivot": [-4.11895, 3.40714, -2.40085], "rotation": [0, 90, 0], "uv": [12, 28], "mirror": true} - ] - }, - { - "name": "gLeftSide", - "parent": "gWholeBody", - "pivot": [0.80141, 4.2, -0.10743], - "rotation": [4, 0, 20], - "cubes": [ - {"origin": [0.79859, 3.30146, -1.64929], "size": [1, 1, 3], "uv": [15, 10]} - ] - }, - { - "name": "gLMidLeg1", - "parent": "gLeftSide", - "pivot": [1.81902, 3.6746, -1.19876], - "rotation": [0, 15, -37.5], - "cubes": [ - {"origin": [1.15236, 3.2746, -1.69876], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15]} - ] - }, - { - "name": "gLMidLeg1Mid", - "parent": "gLMidLeg1", - "pivot": [2.62976, 3.7434, -1.19876], - "rotation": [0, 0, 15], - "cubes": [ - {"origin": [2.12976, 3.3434, -4.09876], "size": [1, 1, 3], "inflate": -0.1, "pivot": [2.62976, 4.2434, -1.19876], "rotation": [0, -90, 0], "uv": [15, 18], "mirror": true} - ] - }, - { - "name": "gLMidLeg1Bottom", - "parent": "gLMidLeg1Mid", - "pivot": [5.03309, 3.66477, -1.35008], - "rotation": [0, 0, 75], - "cubes": [ - {"origin": [4.44755, 3.27521, -3.69876], "size": [1, 1, 3], "inflate": -0.15, "pivot": [4.94755, 3.67521, -1.19876], "rotation": [0, -90, 0], "uv": [15, 23], "mirror": true}, - {"origin": [3.64755, 2.97521, -5.99876], "size": [3, 2, 4], "inflate": -1, "pivot": [5.14755, 3.77521, -1.19876], "rotation": [0, -90, 0], "uv": [12, 28]} - ] - }, - { - "name": "gLMidLeg2", - "parent": "gLeftSide", - "pivot": [1.7643, 4.15146, -0.128], - "rotation": [0, 0, -37.5], - "cubes": [ - {"origin": [1.09763, 3.25146, -0.628], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15]} - ] - }, - { - "name": "gLMidLeg2Mid", - "parent": "gLMidLeg2", - "pivot": [2.68198, 3.70005, -0.128], - "rotation": [0, 0, 17.5], - "cubes": [ - {"origin": [2.18198, 3.30005, -3.028], "size": [1, 1, 3], "inflate": -0.1, "pivot": [2.68198, 4.20005, -0.128], "rotation": [0, -90, 0], "uv": [15, 18], "mirror": true} - ] - }, - { - "name": "gLMidLeg2Bottom", - "parent": "gLMidLeg2Mid", - "pivot": [4.88236, 3.80108, -0.15959], - "rotation": [0, 0, 70], - "cubes": [ - {"origin": [4.53845, 3.66674, -2.68896], "size": [1, 1, 3], "inflate": -0.15, "pivot": [5.04084, 4.16066, -0.12323], "rotation": [0, -90, 0], "uv": [15, 23], "mirror": true}, - {"origin": [3.20657, 3.36674, -5.62561], "size": [3, 2, 4], "inflate": -1, "pivot": [4.70657, 4.16674, -0.12561], "rotation": [0, -90, 0], "uv": [12, 28]} - ] - }, - { - "name": "gLBottomLeg", - "parent": "gLeftSide", - "pivot": [1.56487, 4.05487, 0.90676], - "rotation": [0, -15, -37.5], - "cubes": [ - {"origin": [0.8982, 3.15487, 0.40676], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15]} - ] - }, - { - "name": "gLBottomLegMid", - "parent": "gLBottomLeg", - "pivot": [2.52659, 3.69929, 0.90676], - "rotation": [0, 0, 20], - "cubes": [ - {"origin": [3.42659, 3.19929, -0.59324], "size": [1, 1, 3], "inflate": -0.1, "pivot": [3.92659, 3.69929, 0.90676], "rotation": [0, -90, 0], "uv": [15, 18], "mirror": true} - ] - }, - { - "name": "gLBottomLegBottom", - "parent": "gLBottomLegMid", - "pivot": [5.15708, 3.61705, 0.83966], - "rotation": [0, 0, 67.5], - "cubes": [ - {"origin": [4.53053, 3.02755, -1.79324], "size": [1, 1, 3], "inflate": -0.15, "pivot": [5.03053, 3.52755, 0.90676], "rotation": [0, -90, 0], "uv": [15, 23], "mirror": true}, - {"origin": [3.33053, 2.72755, -4.49324], "size": [3, 2, 4], "inflate": -1, "pivot": [4.83053, 3.52755, 0.90676], "rotation": [0, -90, 0], "uv": [12, 28]} - ] - }, - { - "name": "gRightSide", - "parent": "gWholeBody", - "pivot": [-0.80141, 4.2, -0.10743], - "rotation": [4, 0, -20], - "cubes": [ - {"origin": [-1.79859, 3.30146, -1.64929], "size": [1, 1, 3], "uv": [15, 10], "mirror": true} - ] - }, - { - "name": "gRMidLeg1", - "parent": "gRightSide", - "pivot": [-1.81902, 3.6746, -1.19876], - "rotation": [0, -15, 37.5], - "cubes": [ - {"origin": [-3.15236, 3.2746, -1.69876], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15], "mirror": true} - ] - }, - { - "name": "gRMidLeg1Mid", - "parent": "gRMidLeg1", - "pivot": [-2.62976, 3.7434, -1.19876], - "rotation": [0, 0, -15], - "cubes": [ - {"origin": [-3.12976, 3.3434, -4.09876], "size": [1, 1, 3], "inflate": -0.1, "pivot": [-2.62976, 4.2434, -1.19876], "rotation": [0, 90, 0], "uv": [15, 18]} - ] - }, - { - "name": "gRMidLeg1Bottom", - "parent": "gRMidLeg1Mid", - "pivot": [-5.03309, 3.66477, -1.35008], - "rotation": [0, 0, -75], - "cubes": [ - {"origin": [-5.45071, 3.27521, -3.64165], "size": [1, 1, 3], "inflate": -0.15, "pivot": [-4.97769, 3.76667, -1.17179], "rotation": [0, 90, 0], "uv": [15, 23]}, - {"origin": [-6.64755, 2.97521, -5.99876], "size": [3, 2, 4], "inflate": -1, "pivot": [-5.14755, 3.77521, -1.19876], "rotation": [0, 90, 0], "uv": [12, 28], "mirror": true} - ] - }, - { - "name": "gRMidLeg2", - "parent": "gRightSide", - "pivot": [-1.7643, 4.15146, -0.128], - "rotation": [0, 0, 37.5], - "cubes": [ - {"origin": [-3.09763, 3.25146, -0.628], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15], "mirror": true} - ] - }, - { - "name": "gRMidLeg2Mid", - "parent": "gRMidLeg2", - "pivot": [-2.68198, 3.70005, -0.128], - "rotation": [0, 0, -17.5], - "cubes": [ - {"origin": [-3.18198, 3.30005, -3.028], "size": [1, 1, 3], "inflate": -0.1, "pivot": [-2.68198, 4.20005, -0.128], "rotation": [0, 90, 0], "uv": [15, 18]} - ] - }, - { - "name": "gRMidLeg2Bottom", - "parent": "gRMidLeg2Mid", - "pivot": [-4.88244, 3.7013, -0.16615], - "rotation": [0, 0, -70], - "cubes": [ - {"origin": [-5.37859, 3.5071, -2.728], "size": [1, 1, 3], "inflate": -0.15, "pivot": [-4.87859, 3.9071, -0.128], "rotation": [0, 90, 0], "uv": [15, 23]}, - {"origin": [-6.07859, 3.2071, -5.628], "size": [3, 2, 4], "inflate": -1, "pivot": [-4.57859, 4.0071, -0.128], "rotation": [0, 90, 0], "uv": [12, 28], "mirror": true} - ] - }, - { - "name": "gRBottomLeg", - "parent": "gRightSide", - "pivot": [-1.56487, 4.05487, 0.90676], - "rotation": [0, 15, 37.5], - "cubes": [ - {"origin": [-2.8982, 3.15487, 0.40676], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15], "mirror": true} - ] - }, - { - "name": "gRBottomLegMid", - "parent": "gRBottomLeg", - "pivot": [-2.52659, 3.69929, 0.90676], - "rotation": [0, 0, -20], - "cubes": [ - {"origin": [-4.42659, 3.19929, -0.59324], "size": [1, 1, 3], "inflate": -0.1, "pivot": [-3.92659, 3.69929, 0.90676], "rotation": [0, 90, 0], "uv": [15, 18]} - ] - }, - { - "name": "gRBottomLegBottom", - "parent": "gRBottomLegMid", - "pivot": [-5.15708, 3.61705, 0.83966], - "rotation": [0, 0, -67.5], - "cubes": [ - {"origin": [-5.53053, 3.02755, -1.79324], "size": [1, 1, 3], "inflate": -0.15, "pivot": [-5.03053, 3.52755, 0.90676], "rotation": [0, 90, 0], "uv": [15, 23]}, - {"origin": [-6.33053, 2.72755, -4.49324], "size": [3, 2, 4], "inflate": -1, "pivot": [-4.83053, 3.52755, 0.90676], "rotation": [0, 90, 0], "uv": [12, 28], "mirror": true} - ] - }, - { - "name": "gMainBody", - "parent": "gWholeBody", - "pivot": [0.70442, 4.12465, 0.6], - "cubes": [ - {"origin": [-0.5, 3.2, -3.1], "size": [1, 1, 2], "uv": [2, 10]}, - {"origin": [-0.53592, 3.52293, -3.29019], "size": [2, 2, 3], "inflate": -0.46, "pivot": [-0.09289, 4.94853, -0.70488], "rotation": [11.46188, -11.23918, 43.86846], "uv": [0, 15]}, - {"origin": [-0.79289, 2.54853, -1.20488], "size": [2, 2, 3], "inflate": -0.26, "pivot": [0.70711, 4.04853, -0.70488], "rotation": [4.96208, -4.94357, 44.78567], "uv": [0, 22]}, - {"origin": [-2, 1.9, -3.5], "size": [4, 3, 6], "inflate": -0.7, "pivot": [0, 2.9, -1.5], "rotation": [4, 0, 0], "uv": [0, 0]} - ] - }, - { - "name": "gLowerBody", - "parent": "gMainBody", - "pivot": [0, 4.02465, 1.4], - "cubes": [ - {"origin": [-1, 3.1, 1.1], "size": [2, 1, 2], "pivot": [0, 4.1, 1.6], "rotation": [9, 0, 0], "uv": [29, 15]}, - {"origin": [-0.8339, 3.58254, 0.20856], "size": [2, 2, 3], "inflate": -0.72, "pivot": [0.12399, 4.8, 2], "rotation": [-2.47641, 2.4741, 44.94652], "uv": [0, 29]}, - {"origin": [-1, 3.12465, 0.9], "size": [2, 2, 3], "inflate": -0.43, "pivot": [0, 4.3, 1.5], "rotation": [3, 0, 0], "uv": [28, 2]} - ] - }, - { - "name": "gSackLeft", - "parent": "gLowerBody", - "pivot": [1.38741, 3.66306, 3.09836], - "cubes": [ - {"origin": [0.01285, 3.10867, 2.1041], "size": [3, 1, 2], "inflate": -0.1, "pivot": [1.38741, 3.66306, 3.09836], "rotation": [2.55101, -34.39062, 9.17266], "uv": [28, 23], "mirror": true}, - {"origin": [-0.39514, 3.1672, 1.46743], "size": [3, 1, 2], "inflate": -0.2, "pivot": [1.38741, 3.66306, 3.09836], "rotation": [2.22264, -58.48308, 10.5621], "uv": [28, 19]}, - {"origin": [-0.18688, 3.15891, 2.53294], "size": [3, 1, 2], "inflate": -0.2, "pivot": [1.38741, 3.66306, 3.09836], "rotation": [1.22861, -18.99823, 12.05711], "uv": [28, 27]} - ] - }, - { - "name": "gSackRight", - "parent": "gLowerBody", - "pivot": [-1.38741, 3.66306, 3.09836], - "cubes": [ - {"origin": [-2.81312, 3.15891, 2.53294], "size": [3, 1, 2], "inflate": -0.2, "pivot": [-1.38741, 3.66306, 3.09836], "rotation": [1.22861, 18.99823, -12.05711], "uv": [28, 27]}, - {"origin": [-3.01285, 3.10867, 2.1041], "size": [3, 1, 2], "inflate": -0.1, "pivot": [-1.38741, 3.66306, 3.09836], "rotation": [2.55101, 34.39062, -9.17266], "uv": [28, 23]}, - {"origin": [-2.60486, 3.1672, 1.46743], "size": [3, 1, 2], "inflate": -0.2, "pivot": [-1.38741, 3.66306, 3.09836], "rotation": [2.22264, 58.48308, -10.5621], "uv": [28, 19]} - ] - }, - { - "name": "gTail1", - "parent": "gLowerBody", - "pivot": [0, 4.22433, 3.10657], - "cubes": [ - {"origin": [-1, 3.22433, 2.50657], "size": [2, 2, 3], "inflate": -0.46, "uv": [28, 2]} - ] - }, - { - "name": "gTail2", - "parent": "gTail1", - "pivot": [0, 4.22433, 4.70657], - "cubes": [ - {"origin": [-1, 3.22433, 4.10657], "size": [2, 2, 3], "inflate": -0.49, "uv": [28, 2]} - ] - }, - { - "name": "gTail3", - "parent": "gTail2", - "pivot": [0, 4.22433, 6.30657], - "cubes": [ - {"origin": [-1, 3.22433, 5.60657], "size": [2, 2, 3], "inflate": -0.52, "uv": [28, 2]} - ] - }, - { - "name": "gTail4", - "parent": "gTail3", - "pivot": [0, 4.22433, 7.80657], - "cubes": [ - {"origin": [-1, 3.22433, 7.10657], "size": [2, 2, 3], "inflate": -0.55, "uv": [28, 2]} - ] - }, - { - "name": "gTail5", - "parent": "gTail4", - "pivot": [0, 4.22433, 9.30657], - "cubes": [ - {"origin": [-1, 3.22433, 8.40657], "size": [2, 2, 4], "inflate": -0.58, "uv": [27, 8]} - ] - }, - { - "name": "gTail6", - "parent": "gTail5", - "pivot": [0, 4.22433, 11.50657], - "cubes": [ - {"origin": [-1, 3.22433, 10.80657], "size": [2, 2, 4], "inflate": -0.61, "uv": [27, 8]} - ] - }, - { - "name": "gTail7", - "parent": "gTail6", - "pivot": [0, 4.22433, 14.10657], - "cubes": [ - {"origin": [-1, 3.22433, 13.00657], "size": [2, 2, 4], "inflate": -0.64, "uv": [27, 8]} - ] - }, - { - "name": "gTail8", - "parent": "gTail7", - "pivot": [0, 4.22433, 16.10657], - "cubes": [ - {"origin": [-1, 3.22433, 15.30657], "size": [2, 2, 4], "inflate": -0.67, "uv": [27, 8]} - ] - }, - { - "name": "gTail9", - "parent": "gTail8", - "pivot": [0, 4.22433, 18.30657], - "cubes": [ - {"origin": [-1, 3.22433, 17.50657], "size": [2, 2, 4], "inflate": -0.7, "uv": [27, 8]} - ] - }, - { - "name": "gTail10", - "parent": "gTail9", - "pivot": [0, 4.22433, 20.50657], - "cubes": [ - {"origin": [-1, 3.22433, 19.60657], "size": [2, 2, 4], "inflate": -0.73, "uv": [27, 8]} - ] - }, - { - "name": "gTail11", - "parent": "gTail10", - "pivot": [0, 4.22433, 22.60657], - "cubes": [ - {"origin": [-1, 3.22433, 21.70657], "size": [2, 2, 4], "inflate": -0.76, "uv": [27, 8]} + {"origin": [-4.91895, 2.90714, -5.00085], "size": [1, 1, 3], "inflate": -0.15, "pivot": [-4.41895, 3.30714, -2.40085], "rotation": [0, 90, 0], "uv": [15, 23]} ] } ] From 9b791fa8470f9b36f8619b13212efd770e04ad2e Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 22:19:16 -0500 Subject: [PATCH 045/224] Cleaned up AzEntityRenderer.java a little bit. Signed-off-by: = --- .../render/entity/AzEntityNameTagUtil.java | 60 +++++++++++++++++++ .../core2/render/entity/AzEntityRenderer.java | 48 +-------------- 2 files changed, 62 insertions(+), 46 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameTagUtil.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameTagUtil.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameTagUtil.java new file mode 100644 index 000000000..cd98dabe0 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameTagUtil.java @@ -0,0 +1,60 @@ +package mod.azure.azurelib.core2.render.entity; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; + +import java.util.Objects; + +public class AzEntityNameTagUtil { + + public static boolean shouldShowName(EntityRenderDispatcher entityRenderDispatcher, T entity) { + var nameRenderDistance = entity.isDiscrete() ? 32d : 64d; + + if (!(entity instanceof LivingEntity)) { + return false; + } + + if (entityRenderDispatcher.distanceToSqr(entity) >= nameRenderDistance * nameRenderDistance) { + return false; + } + + if ( + entity instanceof Mob && (!entity.shouldShowName() && (!entity.hasCustomName() + || entity != entityRenderDispatcher.crosshairPickEntity)) + ) { + return false; + } + + final var minecraft = Minecraft.getInstance(); + // TODO: See if we can do this null check better. + var player = Objects.requireNonNull(minecraft.player); + var visibleToClient = !entity.isInvisibleTo(player); + var entityTeam = entity.getTeam(); + + if (entityTeam == null) { + return Minecraft.renderNames() && entity != minecraft.getCameraEntity() && visibleToClient + && !entity.isVehicle(); + } + + var playerTeam = minecraft.player.getTeam(); + + return switch (entityTeam.getNameTagVisibility()) { + case ALWAYS -> visibleToClient; + case NEVER -> false; + case HIDE_FOR_OTHER_TEAMS -> playerTeam == null + ? visibleToClient + : entityTeam.isAlliedTo( + playerTeam + ) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); + case HIDE_FOR_OWN_TEAM -> + playerTeam == null ? visibleToClient : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; + }; + } + + private AzEntityNameTagUtil() { + throw new UnsupportedOperationException(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 76893b7fa..0e27a9418 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -2,20 +2,16 @@ import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; -import java.util.Objects; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; @@ -157,48 +153,8 @@ public AzEntityRenderer addRenderLayer(AzRenderLayer renderLayer) { * Pretty much exclusively used in {@link EntityRenderer#renderNameTag} */ @Override - public boolean shouldShowName(T entity) { - var nameRenderDistance = entity.isDiscrete() ? 32d : 64d; - - if (!(entity instanceof LivingEntity)) { - return false; - } - - if (this.entityRenderDispatcher.distanceToSqr(entity) >= nameRenderDistance * nameRenderDistance) { - return false; - } - - if ( - entity instanceof Mob && (!entity.shouldShowName() && (!entity.hasCustomName() - || entity != this.entityRenderDispatcher.crosshairPickEntity)) - ) { - return false; - } - - final var minecraft = Minecraft.getInstance(); - // TODO: See if we can do this null check better. - var player = Objects.requireNonNull(minecraft.player); - var visibleToClient = !entity.isInvisibleTo(player); - var entityTeam = entity.getTeam(); - - if (entityTeam == null) { - return Minecraft.renderNames() && entity != minecraft.getCameraEntity() && visibleToClient - && !entity.isVehicle(); - } - - var playerTeam = minecraft.player.getTeam(); - - return switch (entityTeam.getNameTagVisibility()) { - case ALWAYS -> visibleToClient; - case NEVER -> false; - case HIDE_FOR_OTHER_TEAMS -> playerTeam == null - ? visibleToClient - : entityTeam.isAlliedTo( - playerTeam - ) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); - case HIDE_FOR_OWN_TEAM -> - playerTeam == null ? visibleToClient : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; - }; + public boolean shouldShowName(@NotNull T entity) { + return AzEntityNameTagUtil.shouldShowName(entityRenderDispatcher, entity); } // Proxy method override for super.getBlockLightLevel external access. From 588c77e6e2cc830217afd5e49e3a732bad23f17d Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 22:19:23 -0500 Subject: [PATCH 046/224] Lint. Signed-off-by: = --- .../mod/azure/azurelib/fabric/ClientListener.java | 4 ++-- .../fabric/core2/example/ExampleEntityTypes.java | 6 +++--- .../azurelib/fabric/core2/example/Facehugger.java | 3 ++- .../fabric/core2/example/FacehuggerAnimator.java | 9 ++++++--- .../fabric/core2/example/FacehuggerRenderer.java | 7 ++++--- .../fabric/core2/example/azure/DoomHunter.java | 9 ++++----- .../core2/example/azure/DoomHunterAnimator.java | 15 +++++++++------ .../core2/example/azure/DoomHunterRenderer.java | 7 ++++--- 8 files changed, 34 insertions(+), 26 deletions(-) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index 3bb89bbc1..7948058c8 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -1,8 +1,6 @@ package mod.azure.azurelib.fabric; import com.mojang.blaze3d.platform.InputConstants; -import mod.azure.azurelib.fabric.core2.example.FacehuggerRenderer; -import mod.azure.azurelib.fabric.core2.example.azure.DoomHunterRenderer; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; @@ -15,6 +13,8 @@ import mod.azure.azurelib.common.internal.common.network.packet.*; import mod.azure.azurelib.fabric.core2.example.DroneRenderer; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; +import mod.azure.azurelib.fabric.core2.example.FacehuggerRenderer; +import mod.azure.azurelib.fabric.core2.example.azure.DoomHunterRenderer; public final class ClientListener implements ClientModInitializer { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java index de622de2d..e179dd80d 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java @@ -1,6 +1,5 @@ package mod.azure.azurelib.fabric.core2.example; -import mod.azure.azurelib.fabric.core2.example.azure.DoomHunter; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; @@ -9,6 +8,7 @@ import net.minecraft.world.entity.MobCategory; import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.fabric.core2.example.azure.DoomHunter; public class ExampleEntityTypes { @@ -23,8 +23,8 @@ public class ExampleEntityTypes { ); public static final EntityType DOOMHUNTER = register( - "doomhunter", - EntityType.Builder.of(DoomHunter::new, MobCategory.MONSTER).sized(3.0f, 7.0f) + "doomhunter", + EntityType.Builder.of(DoomHunter::new, MobCategory.MONSTER).sized(3.0f, 7.0f) ); private static EntityType register(String name, EntityType.Builder builder) { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java index 71ec7afcb..2ad156e23 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java @@ -1,10 +1,11 @@ package mod.azure.azurelib.fabric.core2.example; -import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.level.Level; +import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; + public class Facehugger extends Monster { private final AzAnimationDispatcher animationDispatcher; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java index 8d0d72291..2fc660635 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java @@ -1,16 +1,19 @@ package mod.azure.azurelib.fabric.core2.example; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; public class FacehuggerAnimator extends AzEntityAnimator { - private static final ResourceLocation ANIMATIONS = AzureLib.modResource("animations/entity/facehugger.animation.json"); + private static final ResourceLocation ANIMATIONS = AzureLib.modResource( + "animations/entity/facehugger.animation.json" + ); private static final String IDLE_ANIMATION_NAME = "animation.run"; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java index 312e6d765..62a96b134 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java @@ -1,13 +1,14 @@ package mod.azure.azurelib.fabric.core2.example; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; -import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; + public class FacehuggerRenderer extends AzEntityRenderer { private static final ResourceLocation MODEL = AzureLib.modResource("geo/entity/facehugger.geo.json"); diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java index 81d156241..24f437905 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java @@ -1,10 +1,7 @@ package mod.azure.azurelib.fabric.core2.example.azure; -import mod.azure.azurelib.common.api.common.ai.pathing.AzureNavigation; -import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.goal.*; import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; @@ -16,6 +13,9 @@ import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.api.common.ai.pathing.AzureNavigation; +import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; + public class DoomHunter extends Monster { private final AzAnimationDispatcher animationDispatcher; @@ -56,6 +56,5 @@ protected void registerGoals() { } @Override - protected void playStepSound(BlockPos pos, BlockState state) { - } + protected void playStepSound(BlockPos pos, BlockState state) {} } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java index 9286bd8ad..4ba5b246b 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java @@ -1,16 +1,19 @@ package mod.azure.azurelib.fabric.core2.example.azure; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; public class DoomHunterAnimator extends AzEntityAnimator { - private static final ResourceLocation ANIMATIONS = AzureLib.modResource("animations/entity/doomhunter.animation.json"); + private static final ResourceLocation ANIMATIONS = AzureLib.modResource( + "animations/entity/doomhunter.animation.json" + ); private static final String IDLE_ANIMATION_NAME = "idle"; @@ -23,9 +26,9 @@ public class DoomHunterAnimator extends AzEntityAnimator { @Override public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( - new AzAnimationController<>(this, "base_controller", 0) - .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) - .triggerableAnim(MELEE_ANIMATION_NAME, MELEE_ANIMATION) + new AzAnimationController<>(this, "base_controller", 0) + .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) + .triggerableAnim(MELEE_ANIMATION_NAME, MELEE_ANIMATION) ); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterRenderer.java index 173a34337..6807fc8f2 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterRenderer.java @@ -1,13 +1,14 @@ package mod.azure.azurelib.fabric.core2.example.azure; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; -import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; + public class DoomHunterRenderer extends AzEntityRenderer { private static final ResourceLocation MODEL = AzureLib.modResource("geo/entity/doomhunter.geo.json"); From 7d3957a6074513c72befdf4841e2335768cf8895 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 22:20:14 -0500 Subject: [PATCH 047/224] Refactor. Signed-off-by: = --- ...derLeashUtil.java => AzEntityLeashRenderUtil.java} | 4 ++-- ...tyNameTagUtil.java => AzEntityNameRenderUtil.java} | 4 ++-- .../core2/render/entity/AzEntityRenderer.java | 2 +- .../pipeline/impl/AzEntityRendererPipeline.java | 11 +++++++++-- 4 files changed, 14 insertions(+), 7 deletions(-) rename common/src/main/java/mod/azure/azurelib/core2/render/entity/{RenderLeashUtil.java => AzEntityLeashRenderUtil.java} (98%) rename common/src/main/java/mod/azure/azurelib/core2/render/entity/{AzEntityNameTagUtil.java => AzEntityNameRenderUtil.java} (96%) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/RenderLeashUtil.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLeashRenderUtil.java similarity index 98% rename from common/src/main/java/mod/azure/azurelib/core2/render/entity/RenderLeashUtil.java rename to common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLeashRenderUtil.java index a613dd603..21c8c281d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/RenderLeashUtil.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLeashRenderUtil.java @@ -13,7 +13,7 @@ import net.minecraft.world.phys.Vec3; import org.joml.Matrix4f; -public class RenderLeashUtil { +public class AzEntityLeashRenderUtil { /** * Static rendering code for rendering a leash segment.
      @@ -148,7 +148,7 @@ private static void renderLeashPiece( .setLight(packedLight); } - private RenderLeashUtil() { + private AzEntityLeashRenderUtil() { throw new UnsupportedOperationException(); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameTagUtil.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameRenderUtil.java similarity index 96% rename from common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameTagUtil.java rename to common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameRenderUtil.java index cd98dabe0..3ab870582 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameTagUtil.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameRenderUtil.java @@ -8,7 +8,7 @@ import java.util.Objects; -public class AzEntityNameTagUtil { +public class AzEntityNameRenderUtil { public static boolean shouldShowName(EntityRenderDispatcher entityRenderDispatcher, T entity) { var nameRenderDistance = entity.isDiscrete() ? 32d : 64d; @@ -54,7 +54,7 @@ public static boolean shouldShowName(EntityRenderDispatcher e }; } - private AzEntityNameTagUtil() { + private AzEntityNameRenderUtil() { throw new UnsupportedOperationException(); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 0e27a9418..c0e6c9796 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -154,7 +154,7 @@ public AzEntityRenderer addRenderLayer(AzRenderLayer renderLayer) { */ @Override public boolean shouldShowName(@NotNull T entity) { - return AzEntityNameTagUtil.shouldShowName(entityRenderDispatcher, entity); + return AzEntityNameRenderUtil.shouldShowName(entityRenderDispatcher, entity); } // Proxy method override for super.getBlockLightLevel external access. diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java index d76314f7c..cdbf6acc1 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -25,8 +25,8 @@ import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.entity.AzEntityLeashRenderUtil; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; -import mod.azure.azurelib.core2.render.entity.RenderLeashUtil; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; public class AzEntityRendererPipeline extends AzRendererPipeline { @@ -365,7 +365,14 @@ public void renderFinal( var leashHolder = mob.getLeashHolder(); if (leashHolder != null) { - RenderLeashUtil.renderLeash(azEntityRenderer, mob, partialTick, poseStack, bufferSource, leashHolder); + AzEntityLeashRenderUtil.renderLeash( + azEntityRenderer, + mob, + partialTick, + poseStack, + bufferSource, + leashHolder + ); } } } From d24ff88c64ced8886defb9bd3a7a832cada4a66a Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 12 Dec 2024 22:38:26 -0500 Subject: [PATCH 048/224] Moved animation queue building closer to animation queue. Signed-off-by: = --- .../core2/animation/AzAnimationProcessor.java | 45 +------------------ .../controller/AzAnimationController.java | 42 +++++++++++++++-- .../controller/AzAnimationQueue.java | 12 ++++- 3 files changed, 50 insertions(+), 49 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index fb310d555..30f4ca85f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -1,26 +1,19 @@ package mod.azure.azurelib.core2.animation; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.Collection; +import java.util.Map; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core.utils.Interpolations; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; -import mod.azure.azurelib.core2.animation.primitive.AzAnimation; -import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; -import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; -import mod.azure.azurelib.core2.animation.primitive.AzStage; import mod.azure.azurelib.core2.model.AzBakedModel; public class AzAnimationProcessor { - private static final Logger LOGGER = LoggerFactory.getLogger(AzAnimationProcessor.class); - private final AzAnimator animator; private final Map bonesByName; @@ -33,40 +26,6 @@ public AzAnimationProcessor(AzAnimator animator) { this.reloadAnimations = false; } - /** - * Build an animation queue for the given {@link AzRawAnimation} - * - * @param animatable The animatable object being rendered - * @param rawAnimation The raw animation to be compiled - * @return A queue of animations and loop types to play - */ - public Queue buildAnimationQueue(T animatable, AzRawAnimation rawAnimation) { - var animations = new LinkedList(); - - for (var stage : rawAnimation.getAnimationStages()) { - AzAnimation animation; - - if (Objects.equals(stage.animationName(), AzStage.WAIT)) { - animation = AzAnimation.generateWaitAnimation(stage.additionalTicks()); - } else { - animation = animator.getAnimation(animatable, stage.animationName()); - } - - if (animation == null) { - LOGGER.warn( - "Unable to find animation: {} for {}", - stage.animationName(), - animatable.getClass().getSimpleName() - ); - return null; - } else { - animations.add(new AzQueuedAnimation(animation, stage.loopType())); - } - } - - return animations; - } - /** * Tick and apply transformations to the model based on the current state of the {@link AzAnimationController} * diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index fcd303a55..80f15b868 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -5,7 +5,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Function; @@ -25,6 +27,7 @@ import mod.azure.azurelib.core2.animation.primitive.AzAnimation; import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; +import mod.azure.azurelib.core2.animation.primitive.AzStage; /** * The actual controller that handles the playing and usage of animations, including their various keyframes and @@ -41,7 +44,7 @@ public class AzAnimationController { protected final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); - private final AzAnimationQueue animationQueue; + private final AzAnimationQueue animationQueue; private final AzAnimator animator; @@ -92,7 +95,7 @@ public AzAnimationController(AzAnimator animator, String name, int transition this.animator = animator; this.name = name; this.transitionLength = transitionTickTime; - this.animationQueue = new AzAnimationQueue(); + this.animationQueue = new AzAnimationQueue<>(animator); this.boneSnapshotCache = new AzBoneSnapshotCache(); this.keyFrameCallbacks = AzKeyFrameCallbacks.noop(); this.keyFrameCallbackManager = new AzKeyFrameCallbackManager<>(this); @@ -271,6 +274,37 @@ public boolean isPlayingTriggeredAnimation() { return triggeredAnimation != null && !hasAnimationFinished(); } + /** + * Populates the animation queue with the given {@link AzRawAnimation} + * + * @param animatable The animatable object being rendered + * @param rawAnimation The raw animation to be compiled + * @return Whether the animations were loaded into the queue. + */ + public List tryCreateAnimationQueue(T animatable, AzRawAnimation rawAnimation) { + var stages = rawAnimation.getAnimationStages(); + var animations = new ArrayList(); + + for (var stage : stages) { + var animation = Objects.equals(stage.animationName(), AzStage.WAIT) + ? AzAnimation.generateWaitAnimation(stage.additionalTicks()) + : animator.getAnimation(animatable, stage.animationName()); + + if (animation == null) { + LOGGER.warn( + "Unable to find animation: {} for {}", + stage.animationName(), + animatable.getClass().getSimpleName() + ); + return List.of(); + } else { + animations.add(new AzQueuedAnimation(animation, stage.loopType())); + } + } + + return animations; + } + /** * Sets the currently loaded animation to the one provided.
      * This method may be safely called every render frame, as passing the same builder that is already loaded will do @@ -287,9 +321,9 @@ public void setAnimation(T animatable, AzRawAnimation rawAnimation) { } if (needsAnimationReload || !rawAnimation.equals(currentRawAnimation)) { - var animations = animator.getAnimationProcessor().buildAnimationQueue(animatable, rawAnimation); + var animations = tryCreateAnimationQueue(animatable, rawAnimation); - if (animations != null) { + if (!animations.isEmpty()) { animationQueue.clear(); animationQueue.addAll(animations); this.currentRawAnimation = rawAnimation; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java index 24b8af924..a5a05e0db 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java @@ -2,19 +2,27 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.LinkedList; import java.util.Queue; +import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; -public class AzAnimationQueue { +public class AzAnimationQueue { + + private static final Logger LOGGER = LoggerFactory.getLogger(AzAnimationQueue.class); private final Queue animationQueue; - public AzAnimationQueue() { + private final AzAnimator animator; + + public AzAnimationQueue(AzAnimator animator) { this.animationQueue = new LinkedList<>(); + this.animator = animator; } public void add(@NotNull AzQueuedAnimation queuedAnimation) { From 767546e9ec6bf9b967b977c2bb703d7909242e38 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 00:16:02 -0500 Subject: [PATCH 049/224] Committing progress. Signed-off-by: = --- .../core2/animation/AzAnimationProcessor.java | 241 ++---------------- .../core2/animation/AzAnimationState.java | 196 -------------- .../animation/AzAnimationTickAnalysis.java | 63 +++++ .../azurelib/core2/animation/AzAnimator.java | 74 ++---- .../animation/AzBoneAnimationUpdateUtil.java | 76 ++++++ .../animation/AzCachedBoneUpdateUtil.java | 133 ++++++++++ .../core2/animation/cache/AzBoneCache.java | 79 ++++++ .../animation/cache/AzBoneSnapshotCache.java | 28 -- .../controller/AzAnimationController.java | 11 +- .../animation/impl/AzEntityAnimator.java | 36 --- .../azurelib/core2/model/AzBakedModel.java | 22 +- .../core2/render/entity/AzEntityRenderer.java | 2 +- .../impl/AzEntityRendererPipeline.java | 3 +- .../azurelib/geo/entity/facehugger.geo.json | 7 +- 14 files changed, 410 insertions(+), 561 deletions(-) delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTickAnalysis.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index 30f4ca85f..6717ec0f6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -1,28 +1,19 @@ package mod.azure.azurelib.core2.animation; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; - -import java.util.Collection; -import java.util.Map; - -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; -import mod.azure.azurelib.core.animation.EasingType; -import mod.azure.azurelib.core.state.BoneSnapshot; -import mod.azure.azurelib.core.utils.Interpolations; +import mod.azure.azurelib.core2.animation.cache.AzBoneCache; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; -import mod.azure.azurelib.core2.model.AzBakedModel; public class AzAnimationProcessor { private final AzAnimator animator; - private final Map bonesByName; + private final AzBoneCache boneSnapshotCache; public boolean reloadAnimations; public AzAnimationProcessor(AzAnimator animator) { this.animator = animator; - this.bonesByName = new Object2ObjectOpenHashMap<>(); + this.boneSnapshotCache = new AzBoneCache(); this.reloadAnimations = false; } @@ -31,13 +22,17 @@ public AzAnimationProcessor(AzAnimator animator) { * * @param animatable The animatable object relevant to the animation being played */ - public void tickAnimation(T animatable, AzAnimationState event) { + public void update(T animatable) { var animTime = animator.getAnimTime(); - var boneSnapshotCollection = animator.getBoneSnapshotCache().getAll(); - // TODO: This mutates the bone snapshot cache in a way that is... well, terrible. find another way! - var boneSnapshots = updateBoneSnapshots(boneSnapshotCollection); + var shouldCrash = animator.crashIfBoneMissing(); + + boneSnapshotCache.updateBoneSnapshots(); + var boneSnapshots = boneSnapshotCache.getBoneSnapshotsByName(); + var bonesByName = boneSnapshotCache.getBonesByName(); for (var controller : animator.getAnimationControllerContainer().getAll()) { + var easingType = controller.getOverrideEasingTypeFunction().apply(animatable); + if (this.reloadAnimations) { controller.forceAnimationReset(); controller.getBoneAnimationQueues().clear(); @@ -45,223 +40,35 @@ public void tickAnimation(T animatable, AzAnimationState event) { controller.setJustStarting(animator.isFirstTick()); - event.withController(controller); - controller.process(event, this.bonesByName, boneSnapshots, animTime, animator.crashIfBoneMissing()); + controller.process(animatable, bonesByName, boneSnapshots, animTime, shouldCrash); + // Progresses the current bones according to the animation queue. for (var boneAnimation : controller.getBoneAnimationQueues().values()) { var bone = boneAnimation.bone(); var snapshot = boneSnapshots.get(bone.getName()); var initialSnapshot = bone.getInitialSnapshot(); - var rotXPoint = boneAnimation.rotationXQueue().poll(); - var rotYPoint = boneAnimation.rotationYQueue().poll(); - var rotZPoint = boneAnimation.rotationZQueue().poll(); - var posXPoint = boneAnimation.positionXQueue().poll(); - var posYPoint = boneAnimation.positionYQueue().poll(); - var posZPoint = boneAnimation.positionZQueue().poll(); - var scaleXPoint = boneAnimation.scaleXQueue().poll(); - var scaleYPoint = boneAnimation.scaleYQueue().poll(); - var scaleZPoint = boneAnimation.scaleZQueue().poll(); - var easingType = controller.getOverrideEasingTypeFunction().apply(animatable); - - if (rotXPoint != null && rotYPoint != null && rotZPoint != null) { - bone.setRotX( - (float) EasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() - ); - bone.setRotY( - (float) EasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() - ); - bone.setRotZ( - (float) EasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() - ); - snapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); - snapshot.startRotAnim(); - bone.markRotationAsChanged(); - } - - if (posXPoint != null && posYPoint != null && posZPoint != null) { - bone.setPosX((float) EasingType.lerpWithOverride(posXPoint, easingType)); - bone.setPosY((float) EasingType.lerpWithOverride(posYPoint, easingType)); - bone.setPosZ((float) EasingType.lerpWithOverride(posZPoint, easingType)); - snapshot.updateOffset(bone.getPosX(), bone.getPosY(), bone.getPosZ()); - snapshot.startPosAnim(); - bone.markPositionAsChanged(); - } - - if (scaleXPoint != null && scaleYPoint != null && scaleZPoint != null) { - bone.setScaleX((float) EasingType.lerpWithOverride(scaleXPoint, easingType)); - bone.setScaleY((float) EasingType.lerpWithOverride(scaleYPoint, easingType)); - bone.setScaleZ((float) EasingType.lerpWithOverride(scaleZPoint, easingType)); - snapshot.updateScale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); - snapshot.startScaleAnim(); - bone.markScaleAsChanged(); - } + AzBoneAnimationUpdateUtil.updateRotations(boneAnimation, bone, easingType, initialSnapshot, snapshot); + AzBoneAnimationUpdateUtil.updatePositions(boneAnimation, bone, easingType, snapshot); + AzBoneAnimationUpdateUtil.updateScale(boneAnimation, bone, easingType, snapshot); } } this.reloadAnimations = false; double resetTickLength = animator.getBoneResetTime(); - for (var bone : getRegisteredBones()) { - if (!bone.hasRotationChanged()) { - var initialSnapshot = bone.getInitialSnapshot(); - var saveSnapshot = boneSnapshots.get(bone.getName()); - - if (saveSnapshot.isRotAnimInProgress()) - saveSnapshot.stopRotAnim(animTime); - - double percentageReset = Math.min( - (animTime - saveSnapshot.getLastResetRotationTick()) / resetTickLength, - 1 - ); - - bone.setRotX( - (float) Interpolations.lerp(saveSnapshot.getRotX(), initialSnapshot.getRotX(), percentageReset) - ); - bone.setRotY( - (float) Interpolations.lerp(saveSnapshot.getRotY(), initialSnapshot.getRotY(), percentageReset) - ); - bone.setRotZ( - (float) Interpolations.lerp(saveSnapshot.getRotZ(), initialSnapshot.getRotZ(), percentageReset) - ); - - if (percentageReset >= 1) { - saveSnapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); - } - } - - if (!bone.hasPositionChanged()) { - var initialSnapshot = bone.getInitialSnapshot(); - var saveSnapshot = boneSnapshots.get(bone.getName()); - - if (saveSnapshot.isPosAnimInProgress()) { - saveSnapshot.stopPosAnim(animTime); - } - - var percentageReset = Math.min( - (animTime - saveSnapshot.getLastResetPositionTick()) / resetTickLength, - 1 - ); - - bone.setPosX( - (float) Interpolations.lerp( - saveSnapshot.getOffsetX(), - initialSnapshot.getOffsetX(), - percentageReset - ) - ); - bone.setPosY( - (float) Interpolations.lerp( - saveSnapshot.getOffsetY(), - initialSnapshot.getOffsetY(), - percentageReset - ) - ); - bone.setPosZ( - (float) Interpolations.lerp( - saveSnapshot.getOffsetZ(), - initialSnapshot.getOffsetZ(), - percentageReset - ) - ); - - if (percentageReset >= 1) { - saveSnapshot.updateOffset(bone.getPosX(), bone.getPosY(), bone.getPosZ()); - } - } - - if (!bone.hasScaleChanged()) { - var initialSnapshot = bone.getInitialSnapshot(); - var saveSnapshot = boneSnapshots.get(bone.getName()); - - if (saveSnapshot.isScaleAnimInProgress()) { - saveSnapshot.stopScaleAnim(animTime); - } - - double percentageReset = Math.min( - (animTime - saveSnapshot.getLastResetScaleTick()) / resetTickLength, - 1 - ); - - bone.setScaleX( - (float) Interpolations.lerp(saveSnapshot.getScaleX(), initialSnapshot.getScaleX(), percentageReset) - ); - bone.setScaleY( - (float) Interpolations.lerp(saveSnapshot.getScaleY(), initialSnapshot.getScaleY(), percentageReset) - ); - bone.setScaleZ( - (float) Interpolations.lerp(saveSnapshot.getScaleZ(), initialSnapshot.getScaleZ(), percentageReset) - ); - - if (percentageReset >= 1) { - saveSnapshot.updateScale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); - } - } + // Updates the cached bone snapshots (only if they have changed). + for (var bone : boneSnapshotCache.getRegisteredBones()) { + AzCachedBoneUpdateUtil.updateCachedBoneRotation(bone, boneSnapshots, animTime, resetTickLength); + AzCachedBoneUpdateUtil.updateCachedBonePosition(bone, boneSnapshots, animTime, resetTickLength); + AzCachedBoneUpdateUtil.updateCachedBoneScale(bone, boneSnapshots, animTime, resetTickLength); } - resetBoneTransformationMarkers(); + boneSnapshotCache.resetBoneTransformationMarkers(); animator.finishFirstTick(); } - /** - * Reset the transformation markers applied to each {@link CoreGeoBone} ready for the next render frame - */ - private void resetBoneTransformationMarkers() { - getRegisteredBones().forEach(CoreGeoBone::resetStateChanges); - } - - /** - * Create new bone {@link BoneSnapshot} based on the bone's initial snapshot for the currently registered - * {@link CoreGeoBone GeoBones}, filtered by the bones already present in the master snapshots map - * - * @param snapshots The master bone snapshots map. - * @return The input snapshots map, for easy assignment - */ - private Map updateBoneSnapshots(Map snapshots) { - for (var bone : getRegisteredBones()) { - if (!snapshots.containsKey(bone.getName())) { - snapshots.put(bone.getName(), BoneSnapshot.copy(bone.getInitialSnapshot())); - } - } - - return snapshots; - } - - /** - * Gets a bone by name. - * - * @param boneName The bone name - * @return the bone - */ - public CoreGeoBone getBone(String boneName) { - return this.bonesByName.get(boneName); - } - - /** - * Adds the given bone to the bones list for this processor.
      - * This is normally handled automatically by AzureLib.
      - * Failure to properly register a bone will break things. - */ - public void registerGeoBone(CoreGeoBone bone) { - bone.saveInitialSnapshot(); - this.bonesByName.put(bone.getName(), bone); - bone.getChildBones().forEach(this::registerGeoBone); - } - - /** - * Clear the {@link CoreGeoBone GeoBones} currently registered to the processor, then prepares the processor for a - * new model.
      - * Should be called whenever switching models to render/animate - */ - public void setActiveModel(AzBakedModel model) { - this.bonesByName.clear(); - model.getTopLevelBones().forEach(this::registerGeoBone); - } - - /** - * Get an iterable collection of the {@link CoreGeoBone GeoBones} currently registered to the processor - */ - public Collection getRegisteredBones() { - return this.bonesByName.values(); + public AzBoneCache getBoneSnapshotCache() { + return boneSnapshotCache; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java deleted file mode 100644 index 1f31a660e..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationState.java +++ /dev/null @@ -1,196 +0,0 @@ -package mod.azure.azurelib.core2.animation; - -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; - -import java.util.Map; -import java.util.Objects; - -import mod.azure.azurelib.core.object.DataTicket; -import mod.azure.azurelib.core.object.PlayState; -import mod.azure.azurelib.core2.animation.controller.AzAnimationController; -import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; - -/** - * Animation state handler for end-users.
      - * This is where users would set their selected animation to play, stop the controller, or any number of other - * animation-related actions. - */ -public class AzAnimationState { - - private final T animatable; - - private final float limbSwing; - - private final float limbSwingAmount; - - private final float partialTick; - - private final boolean isMoving; - - private final Map, Object> extraData = new Object2ObjectOpenHashMap<>(); - - public double animationTick; - - protected AzAnimationController controller; - - public AzAnimationState(T animatable, float limbSwing, float limbSwingAmount, float partialTick, boolean isMoving) { - this.animatable = animatable; - this.limbSwing = limbSwing; - this.limbSwingAmount = limbSwingAmount; - this.partialTick = partialTick; - this.isMoving = isMoving; - } - - /** - * Gets the amount of ticks that have passed in either the current transition or animation, depending on the - * controller's AnimationState. - */ - public double getAnimationTick() { - return this.animationTick; - } - - /** - * Gets the current {@link T animatable} being rendered - */ - public T getAnimatable() { - return this.animatable; - } - - public float getLimbSwing() { - return this.limbSwing; - } - - public float getLimbSwingAmount() { - return this.limbSwingAmount; - } - - /** - * Gets the fractional value of the current game tick that has passed in rendering - */ - public float getPartialTick() { - return this.partialTick; - } - - /** - * Gets whether the current {@link T animatable} is considered to be moving for animation purposes.
      - * Note that this is a best-case approximation of movement, and your needs may vary. - */ - public boolean isMoving() { - return this.isMoving; - } - - /** - * Gets the current {@link AzAnimationController} responsible for the current animation - */ - public AzAnimationController getController() { - return this.controller; - } - - /** - * Sets the {@code AnimationEvent}'s current {@link AzAnimationController} - */ - public AzAnimationState withController(AzAnimationController controller) { - this.controller = controller; - - return this; - } - - /** - * Gets the optional additional data map for the event.
      - * - * @see DataTicket - */ - public Map, ?> getExtraData() { - return this.extraData; - } - - /** - * Get a data value saved to this animation event by the ticket for that data.
      - * - * @param dataTicket The {@link DataTicket} for the data to retrieve - * @return The cached data for the given {@code DataTicket}, or null if not saved - * @see DataTicket - */ - public D getData(DataTicket dataTicket) { - return dataTicket.getData(this.extraData); - } - - /** - * Save a data value for the given {@link DataTicket} in the additional data map - * - * @param dataTicket The {@code DataTicket} for the data value - * @param data The data value - */ - public void setData(DataTicket dataTicket, D data) { - this.extraData.put(dataTicket, data); - } - - /** - * Sets the animation for the controller to start/continue playing.
      - * Basically just a shortcut for - * - *

      -     * getController().setAnimation()
      -     * 
      - * - * @param animation The animation to play - */ - public void setAnimation(AzRawAnimation animation) { - getController().setAnimation(animatable, animation); - } - - /** - * Helper method to set an animation to start/continue playing, and return {@link PlayState#CONTINUE} - */ - public PlayState setAndContinue(AzRawAnimation animation) { - getController().setAnimation(animatable, animation); - - return PlayState.CONTINUE; - } - - /** - * Checks whether the current {@link AzAnimationController}'s last animation was the one provided. This allows for - * multi-stage animation shifting where the next animation to play may depend on the previous one - * - * @param animation The animation to check - * @return Whether the controller's last animation is the one provided - */ - public boolean isCurrentAnimation(AzRawAnimation animation) { - return Objects.equals(getController().getCurrentRawAnimation(), animation); - } - - /** - * Similar to {@link AzAnimationState#isCurrentAnimation}, but additionally checks the current stage of the - * animation by name.
      - * This can be used to check if a multi-stage animation has reached a given stage (if it is running at all)
      - * Note that this will still return true even if the animation has finished, matching with the last animation stage - * in the {@link AzRawAnimation} last provided - * - * @param name The name of the animation stage to check (I.E. "move.walk") - * @return Whether the controller's current stage is the one provided - */ - public boolean isCurrentAnimationStage(String name) { - return getController().getCurrentAnimation() != null && getController().getCurrentAnimation() - .animation() - .name() - .equals(name); - } - - /** - * Helper method for {@link AzAnimationController#forceAnimationReset()}
      - * This should be used in controllers when stopping a non-looping animation, so that it is reset to the start for - * the next time it starts - */ - public void resetCurrentAnimation() { - getController().forceAnimationReset(); - } - - /** - * Helper method for {@link AzAnimationController#setAnimationSpeed} - * - * @param speed The speed modifier for the controller (2 = twice as fast, 0.5 = half as fast, etc) - */ - public void setControllerSpeed(float speed) { - getController().setAnimationSpeed(speed); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTickAnalysis.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTickAnalysis.java new file mode 100644 index 000000000..126f474a4 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTickAnalysis.java @@ -0,0 +1,63 @@ +package mod.azure.azurelib.core2.animation; + +import net.minecraft.client.Minecraft; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; + +public class AzAnimationTickAnalysis { + + private final boolean shouldPlayAnimationsWhileGamePaused; + + // Remnants from AnimatableManager. + private double lastUpdateTime; + + private boolean isFirstTick = true; + + private double firstTickTime = -1; + + // Remnants from GeoModel. + private double animTime; + + private double lastGameTickTime; + + public AzAnimationTickAnalysis(boolean shouldPlayAnimationsWhileGamePaused) { + this.shouldPlayAnimationsWhileGamePaused = shouldPlayAnimationsWhileGamePaused; + } + + public void tick() { + var minecraft = Minecraft.getInstance(); + // TODO: If encountering rendering smoothness issues, break glass (this used to be a DataTickets.TICK fetch). + var currentTick = RenderUtils.getCurrentTick(); + + if (firstTickTime == -1) { + firstTickTime = currentTick + minecraft.getTimer().getGameTimeDeltaTicks(); + } + + double currentFrameTime = currentTick - firstTickTime; + boolean isReRender = !isFirstTick && currentFrameTime == lastUpdateTime; + + // TODO: Figure out why this was here to begin with. + // if (isReRender && instanceId == this.lastRenderedInstance) { + // return; + // } + + if (!isReRender && (!minecraft.isPaused() || shouldPlayAnimationsWhileGamePaused)) { + this.lastUpdateTime = currentFrameTime; + + this.animTime += lastUpdateTime - this.lastGameTickTime; + this.lastGameTickTime = lastUpdateTime; + } + } + + public double getAnimTime() { + return animTime; + } + + public boolean isFirstTick() { + return this.isFirstTick; + } + + protected void finishFirstTick() { + this.isFirstTick = false; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index eff7412cf..28139555a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -6,13 +6,11 @@ import java.util.Objects; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.AzureLibException; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.MolangQueries; import mod.azure.azurelib.core2.animation.cache.AzBakedAnimationCache; -import mod.azure.azurelib.core2.animation.cache.AzBoneSnapshotCache; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; @@ -23,63 +21,31 @@ public abstract class AzAnimator { private final AzAnimationProcessor animationProcessor; - private final AzBoneSnapshotCache boneSnapshotCache; - - // Remnants from AnimatableManager. - private double lastUpdateTime; - - private boolean isFirstTick = true; - - private double firstTickTime = -1; - - // Remnants from GeoModel. - private double animTime; - - private double lastGameTickTime; + private final AzAnimationTickAnalysis tickAnalysis; protected AzAnimator() { this.animationControllerContainer = new AzAnimationControllerContainer<>(); this.animationProcessor = new AzAnimationProcessor<>(this); - this.boneSnapshotCache = new AzBoneSnapshotCache(); + this.tickAnalysis = new AzAnimationTickAnalysis(shouldPlayAnimsWhileGamePaused()); } public abstract void registerControllers(AzAnimationControllerContainer animationControllerContainer); public abstract @NotNull ResourceLocation getAnimationLocation(T animatable); - public void animate(T animatable, AzAnimationState animationState) { - var minecraft = Minecraft.getInstance(); - // TODO: If encountering rendering smoothness issues, break glass (this used to be a DataTickets.TICK fetch). - var currentTick = RenderUtils.getCurrentTick(); - - if (firstTickTime == -1) { - firstTickTime = currentTick + minecraft.getTimer().getGameTimeDeltaTicks(); - } - - double currentFrameTime = currentTick - firstTickTime; - boolean isReRender = !isFirstTick && currentFrameTime == lastUpdateTime; - - // TODO: Figure out why this was here to begin with. - // if (isReRender && instanceId == this.lastRenderedInstance) { - // return; - // } - - if (!isReRender && (!minecraft.isPaused() || shouldPlayAnimsWhileGamePaused())) { - this.lastUpdateTime = currentFrameTime; - - this.animTime += lastUpdateTime - this.lastGameTickTime; - this.lastGameTickTime = lastUpdateTime; - } + public void animate(T animatable) { + tickAnalysis.tick(); - animationState.animationTick = this.animTime; + preAnimationSetup(animatable, tickAnalysis.getAnimTime()); - preAnimationSetup(animatable, this.animTime); + var minecraft = Minecraft.getInstance(); + var shouldRun = !minecraft.isPaused() || shouldPlayAnimsWhileGamePaused(); - if (!animationProcessor.getRegisteredBones().isEmpty()) { - animationProcessor.tickAnimation(animatable, animationState); + if (shouldRun && !animationProcessor.getBoneSnapshotCache().getRegisteredBones().isEmpty()) { + animationProcessor.update(animatable); } - setCustomAnimations(animatable, animationState); + setCustomAnimations(animatable); } /** @@ -90,10 +56,8 @@ protected void preAnimationSetup(T animatable, double animTime) { } protected void applyMolangQueries(T animatable, double animTime) { + var level = Objects.requireNonNull(Minecraft.getInstance().level); var parser = MolangParser.INSTANCE; - var minecraft = Minecraft.getInstance(); - // TODO: See if there's a better way to null-check here. - var level = Objects.requireNonNull(minecraft.level); parser.setMemoizedValue(MolangQueries.LIFE_TIME, () -> animTime / 20d); parser.setMemoizedValue(MolangQueries.ACTOR_COUNT, level::getEntityCount); @@ -105,11 +69,9 @@ protected void applyMolangQueries(T animatable, double animTime) { * This method is called once per render frame for each {@link T animatable} being rendered.
      * Override to set custom animations (such as head rotation, etc). * - * @param animatable The {@code GeoAnimatable} instance currently being rendered - * @param animationState An {@link AzAnimationState} instance created to hold animation data for the - * {@code animatable} for this method call + * @param animatable The {@code GeoAnimatable} instance currently being rendered */ - public void setCustomAnimations(T animatable, AzAnimationState animationState) {} + public void setCustomAnimations(T animatable) {} /** * Defines whether the animations for this animator should continue playing in the background when the game is @@ -153,7 +115,7 @@ public AzAnimationProcessor getAnimationProcessor() { } public double getAnimTime() { - return animTime; + return tickAnalysis.getAnimTime(); } /** @@ -164,15 +126,11 @@ public double getBoneResetTime() { return 1; } - public AzBoneSnapshotCache getBoneSnapshotCache() { - return boneSnapshotCache; - } - public boolean isFirstTick() { - return this.isFirstTick; + return tickAnalysis.isFirstTick(); } protected void finishFirstTick() { - this.isFirstTick = false; + tickAnalysis.finishFirstTick(); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java new file mode 100644 index 000000000..40b34a6a0 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java @@ -0,0 +1,76 @@ +package mod.azure.azurelib.core2.animation; + +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.animation.EasingType; +import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; +import mod.azure.azurelib.core.state.BoneSnapshot; + +public class AzBoneAnimationUpdateUtil { + + public static void updatePositions( + BoneAnimationQueue boneAnimation, + CoreGeoBone bone, + EasingType easingType, + BoneSnapshot snapshot + ) { + var posXPoint = boneAnimation.positionXQueue().poll(); + var posYPoint = boneAnimation.positionYQueue().poll(); + var posZPoint = boneAnimation.positionZQueue().poll(); + + if (posXPoint != null && posYPoint != null && posZPoint != null) { + bone.setPosX((float) EasingType.lerpWithOverride(posXPoint, easingType)); + bone.setPosY((float) EasingType.lerpWithOverride(posYPoint, easingType)); + bone.setPosZ((float) EasingType.lerpWithOverride(posZPoint, easingType)); + snapshot.updateOffset(bone.getPosX(), bone.getPosY(), bone.getPosZ()); + snapshot.startPosAnim(); + bone.markPositionAsChanged(); + } + } + + public static void updateRotations( + BoneAnimationQueue boneAnimation, + CoreGeoBone bone, + EasingType easingType, + BoneSnapshot initialSnapshot, + BoneSnapshot snapshot + ) { + var rotXPoint = boneAnimation.rotationXQueue().poll(); + var rotYPoint = boneAnimation.rotationYQueue().poll(); + var rotZPoint = boneAnimation.rotationZQueue().poll(); + + if (rotXPoint != null && rotYPoint != null && rotZPoint != null) { + bone.setRotX( + (float) EasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() + ); + bone.setRotY( + (float) EasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() + ); + bone.setRotZ( + (float) EasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() + ); + snapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); + snapshot.startRotAnim(); + bone.markRotationAsChanged(); + } + } + + public static void updateScale( + BoneAnimationQueue boneAnimation, + CoreGeoBone bone, + EasingType easingType, + BoneSnapshot snapshot + ) { + var scaleXPoint = boneAnimation.scaleXQueue().poll(); + var scaleYPoint = boneAnimation.scaleYQueue().poll(); + var scaleZPoint = boneAnimation.scaleZQueue().poll(); + + if (scaleXPoint != null && scaleYPoint != null && scaleZPoint != null) { + bone.setScaleX((float) EasingType.lerpWithOverride(scaleXPoint, easingType)); + bone.setScaleY((float) EasingType.lerpWithOverride(scaleYPoint, easingType)); + bone.setScaleZ((float) EasingType.lerpWithOverride(scaleZPoint, easingType)); + snapshot.updateScale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); + snapshot.startScaleAnim(); + bone.markScaleAsChanged(); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java new file mode 100644 index 000000000..890025010 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java @@ -0,0 +1,133 @@ +package mod.azure.azurelib.core2.animation; + +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.state.BoneSnapshot; +import mod.azure.azurelib.core.utils.Interpolations; + +import java.util.Map; + +public class AzCachedBoneUpdateUtil { + + public static void updateCachedBonePosition( + CoreGeoBone bone, + Map boneSnapshots, + double animTime, + double resetTickLength + ) { + if (bone.hasPositionChanged()) { + return; + } + + var initialSnapshot = bone.getInitialSnapshot(); + var saveSnapshot = boneSnapshots.get(bone.getName()); + + if (saveSnapshot.isPosAnimInProgress()) { + saveSnapshot.stopPosAnim(animTime); + } + + var percentageReset = Math.min( + (animTime - saveSnapshot.getLastResetPositionTick()) / resetTickLength, + 1 + ); + + bone.setPosX( + (float) Interpolations.lerp( + saveSnapshot.getOffsetX(), + initialSnapshot.getOffsetX(), + percentageReset + ) + ); + bone.setPosY( + (float) Interpolations.lerp( + saveSnapshot.getOffsetY(), + initialSnapshot.getOffsetY(), + percentageReset + ) + ); + bone.setPosZ( + (float) Interpolations.lerp( + saveSnapshot.getOffsetZ(), + initialSnapshot.getOffsetZ(), + percentageReset + ) + ); + + if (percentageReset >= 1) { + saveSnapshot.updateOffset(bone.getPosX(), bone.getPosY(), bone.getPosZ()); + } + } + + public static void updateCachedBoneRotation( + CoreGeoBone bone, + Map boneSnapshots, + double animTime, + double resetTickLength + ) { + if (bone.hasRotationChanged()) { + return; + } + + var initialSnapshot = bone.getInitialSnapshot(); + var saveSnapshot = boneSnapshots.get(bone.getName()); + + if (saveSnapshot.isRotAnimInProgress()) { + saveSnapshot.stopRotAnim(animTime); + } + + double percentageReset = Math.min( + (animTime - saveSnapshot.getLastResetRotationTick()) / resetTickLength, + 1 + ); + + bone.setRotX( + (float) Interpolations.lerp(saveSnapshot.getRotX(), initialSnapshot.getRotX(), percentageReset) + ); + bone.setRotY( + (float) Interpolations.lerp(saveSnapshot.getRotY(), initialSnapshot.getRotY(), percentageReset) + ); + bone.setRotZ( + (float) Interpolations.lerp(saveSnapshot.getRotZ(), initialSnapshot.getRotZ(), percentageReset) + ); + + if (percentageReset >= 1) { + saveSnapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); + } + } + + public static void updateCachedBoneScale( + CoreGeoBone bone, + Map boneSnapshots, + double animTime, + double resetTickLength + ) { + if (bone.hasScaleChanged()) { + return; + } + + var initialSnapshot = bone.getInitialSnapshot(); + var saveSnapshot = boneSnapshots.get(bone.getName()); + + if (saveSnapshot.isScaleAnimInProgress()) { + saveSnapshot.stopScaleAnim(animTime); + } + + double percentageReset = Math.min( + (animTime - saveSnapshot.getLastResetScaleTick()) / resetTickLength, + 1 + ); + + bone.setScaleX( + (float) Interpolations.lerp(saveSnapshot.getScaleX(), initialSnapshot.getScaleX(), percentageReset) + ); + bone.setScaleY( + (float) Interpolations.lerp(saveSnapshot.getScaleY(), initialSnapshot.getScaleY(), percentageReset) + ); + bone.setScaleZ( + (float) Interpolations.lerp(saveSnapshot.getScaleZ(), initialSnapshot.getScaleZ(), percentageReset) + ); + + if (percentageReset >= 1) { + saveSnapshot.updateScale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java new file mode 100644 index 000000000..91ab69e77 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java @@ -0,0 +1,79 @@ +package mod.azure.azurelib.core2.animation.cache; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +import java.util.Collection; +import java.util.Map; + +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.state.BoneSnapshot; +import mod.azure.azurelib.core2.model.AzBakedModel; + +public class AzBoneCache { + + private final Map bonesByName; + + private final Map boneSnapshotsByName; + + public AzBoneCache() { + this.bonesByName = new Object2ObjectOpenHashMap<>(); + this.boneSnapshotsByName = new Object2ObjectOpenHashMap<>(); + } + + /** + * Create new bone {@link BoneSnapshot} based on the bone's initial snapshot for the currently registered + * {@link CoreGeoBone GeoBones}, filtered by the bones already present in the master snapshots map + * + * @return The input snapshots map, for easy assignment + */ + public void updateBoneSnapshots() { + for (var bone : getRegisteredBones()) { + if (!boneSnapshotsByName.containsKey(bone.getName())) { + boneSnapshotsByName.put(bone.getName(), BoneSnapshot.copy(bone.getInitialSnapshot())); + } + } + } + + /** + * Get an iterable collection of the {@link CoreGeoBone GeoBones} currently registered to the processor + */ + public Collection getRegisteredBones() { + return this.bonesByName.values(); + } + + /** + * Reset the transformation markers applied to each {@link CoreGeoBone} ready for the next render frame + */ + public void resetBoneTransformationMarkers() { + getRegisteredBones().forEach(CoreGeoBone::resetStateChanges); + } + + /** + * Adds the given bone to the bones list for this processor.
      + * This is normally handled automatically by AzureLib.
      + * Failure to properly register a bone will break things. + */ + public void registerGeoBone(CoreGeoBone bone) { + bone.saveInitialSnapshot(); + this.bonesByName.put(bone.getName(), bone); + bone.getChildBones().forEach(this::registerGeoBone); + } + + /** + * Clear the {@link CoreGeoBone GeoBones} currently registered to the processor, then prepares the processor for a + * new model.
      + * Should be called whenever switching models to render/animate + */ + public void setActiveModel(AzBakedModel model) { + this.bonesByName.clear(); + model.getTopLevelBones().forEach(this::registerGeoBone); + } + + public Map getBonesByName() { + return bonesByName; + } + + public Map getBoneSnapshotsByName() { + return boneSnapshotsByName; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java deleted file mode 100644 index 406941233..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneSnapshotCache.java +++ /dev/null @@ -1,28 +0,0 @@ -package mod.azure.azurelib.core2.animation.cache; - -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; - -import java.util.Map; - -import mod.azure.azurelib.core.state.BoneSnapshot; - -public class AzBoneSnapshotCache { - - private final Map boneSnapshotsByName; - - public AzBoneSnapshotCache() { - this.boneSnapshotsByName = new Object2ObjectOpenHashMap<>(); - } - - public Map getBoneByName(String name) { - return boneSnapshotsByName; - } - - public void clear() { - this.boneSnapshotsByName.clear(); - } - - public Map getAll() { - return boneSnapshotsByName; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 80f15b868..8175777d5 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -19,7 +19,6 @@ import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core2.animation.AzAnimationProcessor; -import mod.azure.azurelib.core2.animation.AzAnimationState; import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; @@ -367,13 +366,13 @@ public boolean tryTriggerAnimation(String animName) { /** * Handle a given AnimationState, alongside the current triggered animation if applicable */ - protected PlayState handleAnimationState(AzAnimationState state) { + protected PlayState handleAnimationState(T animatable) { if (triggeredAnimation != null) { if (currentRawAnimation != triggeredAnimation) { this.currentAnimation = null; } - setAnimation(state.getAnimatable(), triggeredAnimation); + setAnimation(animatable, triggeredAnimation); if (!hasAnimationFinished()) { return PlayState.CONTINUE; @@ -391,7 +390,6 @@ protected PlayState handleAnimationState(AzAnimationState state) { * This method is called every frame in order to populate the animation point queues, and process animation state * logic. * - * @param state The animation test state * @param bones The registered {@link CoreGeoBone bones} for this model * @param snapshots The {@link BoneSnapshot} map * @param seekTime The current tick + partial tick @@ -399,13 +397,12 @@ protected PlayState handleAnimationState(AzAnimationState state) { * bones */ public void process( - AzAnimationState state, + T animatable, Map bones, Map snapshots, final double seekTime, boolean crashWhenCantFindBone ) { - var animatable = state.getAnimatable(); double adjustedTick = adjustTick(animatable, seekTime); if (animationState == AzAnimationControllerState.TRANSITIONING && adjustedTick >= transitionLength) { @@ -414,7 +411,7 @@ public void process( adjustedTick = adjustTick(animatable, seekTime); } - PlayState playState = handleAnimationState(state); + PlayState playState = handleAnimationState(animatable); if (playState == PlayState.STOP || (currentAnimation == null && animationQueue.isEmpty())) { this.animationState = AzAnimationControllerState.STOPPED; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java index 0fdae43d2..ae64d266b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java @@ -5,35 +5,13 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; -import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.MolangQueries; -import mod.azure.azurelib.core2.animation.AzAnimationState; import mod.azure.azurelib.core2.animation.AzAnimator; public abstract class AzEntityAnimator extends AzAnimator { - public AzAnimationState createAnimationState( - T animatable, - float limbSwing, - float limbSwingAmount, - float partialTick - ) { - var velocity = animatable.getDeltaMovement(); - var avgVelocity = (float) (Math.abs(velocity.x) + Math.abs(velocity.z) / 2f); - var motionThreshold = getMotionAnimThreshold(animatable); - - return new AzAnimationState<>( - animatable, - limbSwing, - limbSwingAmount, - partialTick, - avgVelocity >= motionThreshold && limbSwingAmount != 0 - ); - } - @Override protected void applyMolangQueries(T entity, double animTime) { super.applyMolangQueries(entity, animTime); @@ -63,18 +41,4 @@ protected void applyMolangQueries(T entity, double animTime) { parser.setMemoizedValue(MolangQueries.YAW_SPEED, () -> livingEntity.getYRot() - livingEntity.yRotO); } } - - /** - * Determines the threshold value before the animatable should be considered moving for animation purposes.
      - * The default value and usage for this varies depending on the renderer.
      - *
        - *
      • For entities, it represents the averaged lateral velocity of the object.
      • - *
      • For {@link GeoBlockEntity Tile Entities} and {@link GeoItem Items}, it's currently unused
      • - *
      - * The lower the value, the more sensitive the {@link AzAnimationState#isMoving()} check will be.
      - * Particularly low values may have adverse effects however - */ - protected float getMotionAnimThreshold(T animatable) { - return 0.015f; - } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java index ca10d01cc..90316d2cc 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java @@ -1,11 +1,11 @@ package mod.azure.azurelib.core2.model; +import java.util.ArrayDeque; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; public class AzBakedModel { @@ -27,13 +27,15 @@ public Optional getBoneByName(String name) { } private Map mapBonesByName(List bones) { - return bones.stream() - .collect( - Collectors.toMap( - AzBone::getName, - Function.identity(), - (left, right) -> right - ) - ); + var bonesByName = new HashMap(); + var nodesToMap = new ArrayDeque<>(bones); + + while (!nodesToMap.isEmpty()) { + var currentBone = nodesToMap.poll(); + nodesToMap.addAll(currentBone.getChildBones()); + bonesByName.put(currentBone.getName(), currentBone); + } + + return bonesByName; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index c0e6c9796..ba447e1e9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -88,7 +88,7 @@ public void render( var bakedGeoModel = AzBakedModelCache.getInstance().getNullable(modelResourceLocation); if (cachedEntityAnimator != null && bakedGeoModel != null) { - cachedEntityAnimator.getAnimationProcessor().setActiveModel(bakedGeoModel); + cachedEntityAnimator.getAnimationProcessor().getBoneSnapshotCache().setActiveModel(bakedGeoModel); } return bakedGeoModel; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java index cdbf6acc1..2d6abad67 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -218,8 +218,7 @@ public void actuallyRender( var animator = azEntityRenderer.getAnimator(); if (animator != null) { - var animationState = animator.createAnimationState(animatable, limbSwing, limbSwingAmount, partialTick); - animator.animate(animatable, animationState); + animator.animate(animatable); } } diff --git a/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json b/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json index 03fce4a38..cbcf42197 100644 --- a/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json +++ b/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json @@ -15,14 +15,9 @@ "name": "root", "pivot": [0, 4, 0] }, - { - "name": "gWholeBody", - "parent": "root", - "pivot": [0, 4, 0] - }, { "name": "gRFrontLeg", - "parent": "gWholeBody", + "parent": "root", "pivot": [-1.03227, 3.85146, -2.40085], "rotation": [0, -47.5, 12.5], "cubes": [ From c20f9efd8c93f94c516d773a614a7ed7fd5fc061 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 01:46:22 -0500 Subject: [PATCH 050/224] Fixed bad numeric type being used during keyframe location calcs. Signed-off-by: = --- .../animation/controller/keyframe/AzKeyFrameProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java index df1330f16..b0f3c56d8 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java @@ -236,7 +236,7 @@ protected KeyframeLocation> getCurrentKeyFrameLocation( List> frames, double ageInTicks ) { - var totalFrameTime = 0; + var totalFrameTime = 0.0; for (var frame : frames) { totalFrameTime += frame.length(); From 9d28ed424e13752d8b30a36c57dca0efed595b5e Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 01:47:56 -0500 Subject: [PATCH 051/224] Lint. Signed-off-by: = --- .../azurelib/core2/animation/AzCachedBoneUpdateUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java index 890025010..cc1750152 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java @@ -1,11 +1,11 @@ package mod.azure.azurelib.core2.animation; +import java.util.Map; + import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core.utils.Interpolations; -import java.util.Map; - public class AzCachedBoneUpdateUtil { public static void updateCachedBonePosition( From 190f0d6a262ecda09c3d1382954b4a66183c86de Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 01:52:01 -0500 Subject: [PATCH 052/224] Stupid javadoc, you make me look bad! OOOOOOGA BOOOGA BOOOGAAAAAAAAAAAA Signed-off-by: = --- .../mod/azure/azurelib/core2/animation/cache/AzBoneCache.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java index 91ab69e77..d351b45cc 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java @@ -23,8 +23,6 @@ public AzBoneCache() { /** * Create new bone {@link BoneSnapshot} based on the bone's initial snapshot for the currently registered * {@link CoreGeoBone GeoBones}, filtered by the bones already present in the master snapshots map - * - * @return The input snapshots map, for easy assignment */ public void updateBoneSnapshots() { for (var bone : getRegisteredBones()) { From f20a150dbf1e00769f9c4cfabb004314e6ef1a0b Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Fri, 13 Dec 2024 01:53:39 -0500 Subject: [PATCH 053/224] RETURNNNN THE double, OR SUFFERRRRR MYYY CURSSSSEEE --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 3c762cad8..b683d3d1b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -51,5 +51,5 @@ mod_logo = azurelib.png mod_name = AzureLib mod_sources = https://github.com/AzureDoom/AzureLib mod_url = https://modrinth.com/mod/azurelib -version = 3.0.0-alpha5 +version = 3.0.0-alpha7 modrinth_id = 7zlUOZvb From 4da9dc58f8736376efe95cb6ea28b259df2eabfa Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 14:06:34 -0500 Subject: [PATCH 054/224] Bit of cleanup. Signed-off-by: = --- .../core2/animation/AzAnimationProcessor.java | 18 +++++++-------- ...ickAnalysis.java => AzAnimationTimer.java} | 4 ++-- .../azurelib/core2/animation/AzAnimator.java | 22 +++++++++---------- .../core2/render/entity/AzEntityRenderer.java | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) rename common/src/main/java/mod/azure/azurelib/core2/animation/{AzAnimationTickAnalysis.java => AzAnimationTimer.java} (93%) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index 6717ec0f6..6996c2319 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -7,13 +7,13 @@ public class AzAnimationProcessor { private final AzAnimator animator; - private final AzBoneCache boneSnapshotCache; + private final AzBoneCache boneCache; public boolean reloadAnimations; public AzAnimationProcessor(AzAnimator animator) { this.animator = animator; - this.boneSnapshotCache = new AzBoneCache(); + this.boneCache = new AzBoneCache(); this.reloadAnimations = false; } @@ -26,9 +26,9 @@ public void update(T animatable) { var animTime = animator.getAnimTime(); var shouldCrash = animator.crashIfBoneMissing(); - boneSnapshotCache.updateBoneSnapshots(); - var boneSnapshots = boneSnapshotCache.getBoneSnapshotsByName(); - var bonesByName = boneSnapshotCache.getBonesByName(); + boneCache.updateBoneSnapshots(); + var boneSnapshots = boneCache.getBoneSnapshotsByName(); + var bonesByName = boneCache.getBonesByName(); for (var controller : animator.getAnimationControllerContainer().getAll()) { var easingType = controller.getOverrideEasingTypeFunction().apply(animatable); @@ -58,17 +58,17 @@ public void update(T animatable) { double resetTickLength = animator.getBoneResetTime(); // Updates the cached bone snapshots (only if they have changed). - for (var bone : boneSnapshotCache.getRegisteredBones()) { + for (var bone : boneCache.getRegisteredBones()) { AzCachedBoneUpdateUtil.updateCachedBoneRotation(bone, boneSnapshots, animTime, resetTickLength); AzCachedBoneUpdateUtil.updateCachedBonePosition(bone, boneSnapshots, animTime, resetTickLength); AzCachedBoneUpdateUtil.updateCachedBoneScale(bone, boneSnapshots, animTime, resetTickLength); } - boneSnapshotCache.resetBoneTransformationMarkers(); + boneCache.resetBoneTransformationMarkers(); animator.finishFirstTick(); } - public AzBoneCache getBoneSnapshotCache() { - return boneSnapshotCache; + public AzBoneCache getBoneCache() { + return boneCache; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTickAnalysis.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java similarity index 93% rename from common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTickAnalysis.java rename to common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java index 126f474a4..c328cfda1 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTickAnalysis.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java @@ -4,7 +4,7 @@ import mod.azure.azurelib.common.internal.client.util.RenderUtils; -public class AzAnimationTickAnalysis { +public class AzAnimationTimer { private final boolean shouldPlayAnimationsWhileGamePaused; @@ -20,7 +20,7 @@ public class AzAnimationTickAnalysis { private double lastGameTickTime; - public AzAnimationTickAnalysis(boolean shouldPlayAnimationsWhileGamePaused) { + public AzAnimationTimer(boolean shouldPlayAnimationsWhileGamePaused) { this.shouldPlayAnimationsWhileGamePaused = shouldPlayAnimationsWhileGamePaused; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index 28139555a..1e838ad51 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -16,17 +16,17 @@ public abstract class AzAnimator { - // Remnants from AnimatableManager. + // Holds animation controllers. private final AzAnimationControllerContainer animationControllerContainer; - + // Processes animations. private final AzAnimationProcessor animationProcessor; - - private final AzAnimationTickAnalysis tickAnalysis; + // Tracks animation time. + private final AzAnimationTimer timer; protected AzAnimator() { this.animationControllerContainer = new AzAnimationControllerContainer<>(); this.animationProcessor = new AzAnimationProcessor<>(this); - this.tickAnalysis = new AzAnimationTickAnalysis(shouldPlayAnimsWhileGamePaused()); + this.timer = new AzAnimationTimer(shouldPlayAnimsWhileGamePaused()); } public abstract void registerControllers(AzAnimationControllerContainer animationControllerContainer); @@ -34,14 +34,14 @@ protected AzAnimator() { public abstract @NotNull ResourceLocation getAnimationLocation(T animatable); public void animate(T animatable) { - tickAnalysis.tick(); + timer.tick(); - preAnimationSetup(animatable, tickAnalysis.getAnimTime()); + preAnimationSetup(animatable, timer.getAnimTime()); var minecraft = Minecraft.getInstance(); var shouldRun = !minecraft.isPaused() || shouldPlayAnimsWhileGamePaused(); - if (shouldRun && !animationProcessor.getBoneSnapshotCache().getRegisteredBones().isEmpty()) { + if (shouldRun && !animationProcessor.getBoneCache().getRegisteredBones().isEmpty()) { animationProcessor.update(animatable); } @@ -115,7 +115,7 @@ public AzAnimationProcessor getAnimationProcessor() { } public double getAnimTime() { - return tickAnalysis.getAnimTime(); + return timer.getAnimTime(); } /** @@ -127,10 +127,10 @@ public double getBoneResetTime() { } public boolean isFirstTick() { - return tickAnalysis.isFirstTick(); + return timer.isFirstTick(); } protected void finishFirstTick() { - tickAnalysis.finishFirstTick(); + timer.finishFirstTick(); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index ba447e1e9..a061c7235 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -88,7 +88,7 @@ public void render( var bakedGeoModel = AzBakedModelCache.getInstance().getNullable(modelResourceLocation); if (cachedEntityAnimator != null && bakedGeoModel != null) { - cachedEntityAnimator.getAnimationProcessor().getBoneSnapshotCache().setActiveModel(bakedGeoModel); + cachedEntityAnimator.getAnimationProcessor().getBoneCache().setActiveModel(bakedGeoModel); } return bakedGeoModel; From d9a6a7d0c580739729e1c1791af67ae9a12e3216 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 15:01:44 -0500 Subject: [PATCH 055/224] Implemented AzAnimatorConfig.java. Signed-off-by: = --- .../core2/animation/AzAnimationProcessor.java | 4 +- .../core2/animation/AzAnimationTimer.java | 8 +-- .../azurelib/core2/animation/AzAnimator.java | 40 ++++-------- .../core2/animation/AzAnimatorConfig.java | 61 +++++++++++++++++++ .../animation/impl/AzEntityAnimator.java | 5 ++ .../fabric/core2/example/DroneAnimator.java | 5 ++ .../core2/example/FacehuggerAnimator.java | 5 ++ .../example/azure/DoomHunterAnimator.java | 5 ++ 8 files changed, 98 insertions(+), 35 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorConfig.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index 6996c2319..c9fc2f150 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -24,7 +24,7 @@ public AzAnimationProcessor(AzAnimator animator) { */ public void update(T animatable) { var animTime = animator.getAnimTime(); - var shouldCrash = animator.crashIfBoneMissing(); + var shouldCrash = animator.config().crashIfBoneMissing(); boneCache.updateBoneSnapshots(); var boneSnapshots = boneCache.getBoneSnapshotsByName(); @@ -55,7 +55,7 @@ public void update(T animatable) { } this.reloadAnimations = false; - double resetTickLength = animator.getBoneResetTime(); + double resetTickLength = animator.config().boneResetTime(); // Updates the cached bone snapshots (only if they have changed). for (var bone : boneCache.getRegisteredBones()) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java index c328cfda1..aa54d8259 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java @@ -6,7 +6,7 @@ public class AzAnimationTimer { - private final boolean shouldPlayAnimationsWhileGamePaused; + private final AzAnimatorConfig config; // Remnants from AnimatableManager. private double lastUpdateTime; @@ -20,8 +20,8 @@ public class AzAnimationTimer { private double lastGameTickTime; - public AzAnimationTimer(boolean shouldPlayAnimationsWhileGamePaused) { - this.shouldPlayAnimationsWhileGamePaused = shouldPlayAnimationsWhileGamePaused; + public AzAnimationTimer(AzAnimatorConfig config) { + this.config = config; } public void tick() { @@ -41,7 +41,7 @@ public void tick() { // return; // } - if (!isReRender && (!minecraft.isPaused() || shouldPlayAnimationsWhileGamePaused)) { + if (!isReRender && (!minecraft.isPaused() || config.shouldPlayAnimationsWhileGamePaused())) { this.lastUpdateTime = currentFrameTime; this.animTime += lastUpdateTime - this.lastGameTickTime; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index 1e838ad51..50a604b78 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -7,7 +7,6 @@ import java.util.Objects; import mod.azure.azurelib.common.internal.common.AzureLibException; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.MolangQueries; import mod.azure.azurelib.core2.animation.cache.AzBakedAnimationCache; @@ -16,17 +15,23 @@ public abstract class AzAnimator { + // Holds general properties for the animator and its controllers. + private final AzAnimatorConfig config; + // Holds animation controllers. private final AzAnimationControllerContainer animationControllerContainer; + // Processes animations. private final AzAnimationProcessor animationProcessor; + // Tracks animation time. private final AzAnimationTimer timer; - protected AzAnimator() { + protected AzAnimator(AzAnimatorConfig config) { + this.config = config; this.animationControllerContainer = new AzAnimationControllerContainer<>(); this.animationProcessor = new AzAnimationProcessor<>(this); - this.timer = new AzAnimationTimer(shouldPlayAnimsWhileGamePaused()); + this.timer = new AzAnimationTimer(config); } public abstract void registerControllers(AzAnimationControllerContainer animationControllerContainer); @@ -39,7 +44,7 @@ public void animate(T animatable) { preAnimationSetup(animatable, timer.getAnimTime()); var minecraft = Minecraft.getInstance(); - var shouldRun = !minecraft.isPaused() || shouldPlayAnimsWhileGamePaused(); + var shouldRun = !minecraft.isPaused() || config.shouldPlayAnimationsWhileGamePaused(); if (shouldRun && !animationProcessor.getBoneCache().getRegisteredBones().isEmpty()) { animationProcessor.update(animatable); @@ -73,25 +78,6 @@ protected void applyMolangQueries(T animatable, double animTime) { */ public void setCustomAnimations(T animatable) {} - /** - * Defines whether the animations for this animator should continue playing in the background when the game is - * paused.
      - * By default, animation progress will be stalled while the game is paused. - */ - public boolean shouldPlayAnimsWhileGamePaused() { - return false; - } - - /** - * Override this and return true if AzureLib should crash when attempting to animate the model, but fails to find a - * bone.
      - * By default, AzureLib will just gracefully ignore a missing bone, which might cause oddities with incorrect models - * or mismatching variables.
      - */ - public boolean crashIfBoneMissing() { - return false; - } - /** * Get the baked animation object used for rendering from the given resource path */ @@ -118,12 +104,8 @@ public double getAnimTime() { return timer.getAnimTime(); } - /** - * Defines the speed in which the {@link AzAnimationProcessor} should return {@link CoreGeoBone GeoBones} that - * currently have no animations to their default position. - */ - public double getBoneResetTime() { - return 1; + public AzAnimatorConfig config() { + return config; } public boolean isFirstTick() { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorConfig.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorConfig.java new file mode 100644 index 000000000..572bfd1af --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorConfig.java @@ -0,0 +1,61 @@ +package mod.azure.azurelib.core2.animation; + +/** + * @param boneResetTime The speed with which bones lacking animation should reset back to their + * default position. 1 by default. + * @param crashIfBoneMissing Crash when a bone cannot be found while animating. False by default. + * @param shouldPlayAnimationsWhileGamePaused Whether animations should continue playing in the background when the game + * is paused. False by default. + */ +public record AzAnimatorConfig( + double boneResetTime, + boolean crashIfBoneMissing, + boolean shouldPlayAnimationsWhileGamePaused +) { + + public static Builder builder() { + return new Builder(); + } + + public static AzAnimatorConfig defaultConfig() { + return builder().build(); + } + + public static class Builder { + + private double boneResetTime; + + private boolean crashIfBoneMissing; + + private boolean shouldPlayAnimationsWhileGamePaused; + + private Builder() { + this.boneResetTime = 1; + this.crashIfBoneMissing = false; + this.shouldPlayAnimationsWhileGamePaused = false; + } + + public Builder crashIfBoneMissing() { + this.crashIfBoneMissing = true; + return this; + } + + public Builder shouldPlayAnimationsWhileGamePaused() { + this.shouldPlayAnimationsWhileGamePaused = true; + return this; + } + + public Builder withBoneResetTime(double boneResetTime) { + this.boneResetTime = boneResetTime; + return this; + } + + public AzAnimatorConfig build() { + return new AzAnimatorConfig( + boneResetTime, + crashIfBoneMissing, + shouldPlayAnimationsWhileGamePaused + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java index ae64d266b..5bfb91e1c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java @@ -9,9 +9,14 @@ import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.MolangQueries; import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; public abstract class AzEntityAnimator extends AzAnimator { + protected AzEntityAnimator(AzAnimatorConfig config) { + super(config); + } + @Override protected void applyMolangQueries(T entity, double animTime) { super.applyMolangQueries(entity, animTime); diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java index b05bc7f93..ec7674283 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; @@ -17,6 +18,10 @@ public class DroneAnimator extends AzEntityAnimator { private static final AzRawAnimation IDLE_ANIMATION = AzRawAnimation.begin().thenLoop(IDLE_ANIMATION_NAME); + public DroneAnimator() { + super(AzAnimatorConfig.defaultConfig()); + } + @Override public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java index 2fc660635..09b7b1c56 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; @@ -19,6 +20,10 @@ public class FacehuggerAnimator extends AzEntityAnimator { private static final AzRawAnimation IDLE_ANIMATION = AzRawAnimation.begin().thenLoop(IDLE_ANIMATION_NAME); + public FacehuggerAnimator() { + super(AzAnimatorConfig.defaultConfig()); + } + @Override public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java index 4ba5b246b..92afddaf8 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; @@ -23,6 +24,10 @@ public class DoomHunterAnimator extends AzEntityAnimator { private static final AzRawAnimation MELEE_ANIMATION = AzRawAnimation.begin().thenLoop(MELEE_ANIMATION_NAME); + public DoomHunterAnimator() { + super(AzAnimatorConfig.defaultConfig()); + } + @Override public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( From 41c5938085fee10313ffdcca7b7b8c637f4930c1 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 15:53:03 -0500 Subject: [PATCH 056/224] Implemented AzAnimationContext.java, more cleanup. Signed-off-by: = --- .../core2/animation/AzAnimationContext.java | 41 +++++++++++++ .../core2/animation/AzAnimationProcessor.java | 38 +++++-------- .../azurelib/core2/animation/AzAnimator.java | 48 +++++++--------- .../core2/animation/cache/AzBoneCache.java | 57 +++++++++++++------ 4 files changed, 112 insertions(+), 72 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationContext.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationContext.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationContext.java new file mode 100644 index 000000000..ea3fab18f --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationContext.java @@ -0,0 +1,41 @@ +package mod.azure.azurelib.core2.animation; + +import mod.azure.azurelib.core2.animation.cache.AzBoneCache; + +public class AzAnimationContext { + + private final AzBoneCache boneCache; + + private final AzAnimatorConfig config; + + private final AzAnimationTimer timer; + + // Package-private for mutability purposes. + T animatable; + + public AzAnimationContext( + AzBoneCache boneCache, + AzAnimatorConfig config, + AzAnimationTimer timer + ) { + this.boneCache = boneCache; + this.config = config; + this.timer = timer; + } + + public T animatable() { + return animatable; + } + + public AzBoneCache boneCache() { + return boneCache; + } + + public AzAnimatorConfig config() { + return config; + } + + public AzAnimationTimer timer() { + return timer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index c9fc2f150..a59e562ee 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -1,32 +1,32 @@ package mod.azure.azurelib.core2.animation; -import mod.azure.azurelib.core2.animation.cache.AzBoneCache; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; public class AzAnimationProcessor { private final AzAnimator animator; - private final AzBoneCache boneCache; - public boolean reloadAnimations; public AzAnimationProcessor(AzAnimator animator) { this.animator = animator; - this.boneCache = new AzBoneCache(); this.reloadAnimations = false; } /** * Tick and apply transformations to the model based on the current state of the {@link AzAnimationController} * - * @param animatable The animatable object relevant to the animation being played + * @param context An animation context provided by the animator. */ - public void update(T animatable) { - var animTime = animator.getAnimTime(); - var shouldCrash = animator.config().crashIfBoneMissing(); - - boneCache.updateBoneSnapshots(); + public void update(AzAnimationContext context) { + var animatable = context.animatable(); + var timer = context.timer(); + var animTime = timer.getAnimTime(); + var boneCache = context.boneCache(); + var config = context.config(); + var shouldCrash = config.crashIfBoneMissing(); + + boneCache.snapshot(); var boneSnapshots = boneCache.getBoneSnapshotsByName(); var bonesByName = boneCache.getBonesByName(); @@ -38,7 +38,7 @@ public void update(T animatable) { controller.getBoneAnimationQueues().clear(); } - controller.setJustStarting(animator.isFirstTick()); + controller.setJustStarting(timer.isFirstTick()); controller.process(animatable, bonesByName, boneSnapshots, animTime, shouldCrash); @@ -55,20 +55,8 @@ public void update(T animatable) { } this.reloadAnimations = false; - double resetTickLength = animator.config().boneResetTime(); - - // Updates the cached bone snapshots (only if they have changed). - for (var bone : boneCache.getRegisteredBones()) { - AzCachedBoneUpdateUtil.updateCachedBoneRotation(bone, boneSnapshots, animTime, resetTickLength); - AzCachedBoneUpdateUtil.updateCachedBonePosition(bone, boneSnapshots, animTime, resetTickLength); - AzCachedBoneUpdateUtil.updateCachedBoneScale(bone, boneSnapshots, animTime, resetTickLength); - } - - boneCache.resetBoneTransformationMarkers(); - animator.finishFirstTick(); - } - public AzBoneCache getBoneCache() { - return boneCache; + boneCache.update(context); + timer.finishFirstTick(); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index 50a604b78..cb2794f2e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -10,13 +10,13 @@ import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.MolangQueries; import mod.azure.azurelib.core2.animation.cache.AzBakedAnimationCache; +import mod.azure.azurelib.core2.animation.cache.AzBoneCache; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; public abstract class AzAnimator { - // Holds general properties for the animator and its controllers. - private final AzAnimatorConfig config; + private final AzAnimationContext reusableContext; // Holds animation controllers. private final AzAnimationControllerContainer animationControllerContainer; @@ -24,14 +24,14 @@ public abstract class AzAnimator { // Processes animations. private final AzAnimationProcessor animationProcessor; - // Tracks animation time. - private final AzAnimationTimer timer; - protected AzAnimator(AzAnimatorConfig config) { - this.config = config; this.animationControllerContainer = new AzAnimationControllerContainer<>(); this.animationProcessor = new AzAnimationProcessor<>(this); - this.timer = new AzAnimationTimer(config); + + var boneCache = new AzBoneCache(); + var timer = new AzAnimationTimer(config); + + this.reusableContext = new AzAnimationContext<>(boneCache, config, timer); } public abstract void registerControllers(AzAnimationControllerContainer animationControllerContainer); @@ -39,6 +39,12 @@ protected AzAnimator(AzAnimatorConfig config) { public abstract @NotNull ResourceLocation getAnimationLocation(T animatable); public void animate(T animatable) { + reusableContext.animatable = animatable; + + var boneCache = reusableContext.boneCache(); + var config = reusableContext.config(); + var timer = reusableContext.timer(); + timer.tick(); preAnimationSetup(animatable, timer.getAnimTime()); @@ -46,8 +52,8 @@ public void animate(T animatable) { var minecraft = Minecraft.getInstance(); var shouldRun = !minecraft.isPaused() || config.shouldPlayAnimationsWhileGamePaused(); - if (shouldRun && !animationProcessor.getBoneCache().getRegisteredBones().isEmpty()) { - animationProcessor.update(animatable); + if (shouldRun && !boneCache.isEmpty()) { + animationProcessor.update(reusableContext); } setCustomAnimations(animatable); @@ -92,27 +98,11 @@ public AzAnimation getAnimation(T animatable, String name) { return bakedAnimations.getAnimation(name); } - public AzAnimationControllerContainer getAnimationControllerContainer() { - return animationControllerContainer; - } - - public AzAnimationProcessor getAnimationProcessor() { - return animationProcessor; + public AzAnimationContext context() { + return reusableContext; } - public double getAnimTime() { - return timer.getAnimTime(); - } - - public AzAnimatorConfig config() { - return config; - } - - public boolean isFirstTick() { - return timer.isFirstTick(); - } - - protected void finishFirstTick() { - timer.finishFirstTick(); + public AzAnimationControllerContainer getAnimationControllerContainer() { + return animationControllerContainer; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java index d351b45cc..2290d41cf 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java @@ -7,6 +7,8 @@ import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.state.BoneSnapshot; +import mod.azure.azurelib.core2.animation.AzAnimationContext; +import mod.azure.azurelib.core2.animation.AzCachedBoneUpdateUtil; import mod.azure.azurelib.core2.model.AzBakedModel; public class AzBoneCache { @@ -24,26 +26,37 @@ public AzBoneCache() { * Create new bone {@link BoneSnapshot} based on the bone's initial snapshot for the currently registered * {@link CoreGeoBone GeoBones}, filtered by the bones already present in the master snapshots map */ - public void updateBoneSnapshots() { + public void snapshot() { for (var bone : getRegisteredBones()) { - if (!boneSnapshotsByName.containsKey(bone.getName())) { - boneSnapshotsByName.put(bone.getName(), BoneSnapshot.copy(bone.getInitialSnapshot())); - } + boneSnapshotsByName.computeIfAbsent(bone.getName(), $ -> BoneSnapshot.copy(bone.getInitialSnapshot())); } } /** - * Get an iterable collection of the {@link CoreGeoBone GeoBones} currently registered to the processor + * Clear the {@link CoreGeoBone GeoBones} currently registered to the processor, then prepares the processor for a + * new model.
      + * Should be called whenever switching models to render/animate */ - public Collection getRegisteredBones() { - return this.bonesByName.values(); + public void setActiveModel(AzBakedModel model) { + this.bonesByName.clear(); + model.getTopLevelBones().forEach(this::registerGeoBone); } - /** - * Reset the transformation markers applied to each {@link CoreGeoBone} ready for the next render frame - */ - public void resetBoneTransformationMarkers() { - getRegisteredBones().forEach(CoreGeoBone::resetStateChanges); + public void update(AzAnimationContext context) { + var config = context.config(); + var timer = context.timer(); + var animTime = timer.getAnimTime(); + var boneSnapshots = getBoneSnapshotsByName(); + var resetTickLength = config.boneResetTime(); + + // Updates the cached bone snapshots (only if they have changed). + for (var bone : getRegisteredBones()) { + AzCachedBoneUpdateUtil.updateCachedBoneRotation(bone, boneSnapshots, animTime, resetTickLength); + AzCachedBoneUpdateUtil.updateCachedBonePosition(bone, boneSnapshots, animTime, resetTickLength); + AzCachedBoneUpdateUtil.updateCachedBoneScale(bone, boneSnapshots, animTime, resetTickLength); + } + + resetBoneTransformationMarkers(); } /** @@ -58,13 +71,17 @@ public void registerGeoBone(CoreGeoBone bone) { } /** - * Clear the {@link CoreGeoBone GeoBones} currently registered to the processor, then prepares the processor for a - * new model.
      - * Should be called whenever switching models to render/animate + * Reset the transformation markers applied to each {@link CoreGeoBone} ready for the next render frame */ - public void setActiveModel(AzBakedModel model) { - this.bonesByName.clear(); - model.getTopLevelBones().forEach(this::registerGeoBone); + private void resetBoneTransformationMarkers() { + getRegisteredBones().forEach(CoreGeoBone::resetStateChanges); + } + + /** + * Get an iterable collection of the {@link CoreGeoBone GeoBones} currently registered to the processor + */ + private Collection getRegisteredBones() { + return this.bonesByName.values(); } public Map getBonesByName() { @@ -74,4 +91,8 @@ public Map getBonesByName() { public Map getBoneSnapshotsByName() { return boneSnapshotsByName; } + + public boolean isEmpty() { + return getRegisteredBones().isEmpty(); + } } From 2492181b9f730672cc1ea619867fbabe9542ca52 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 15:53:24 -0500 Subject: [PATCH 057/224] Separation of concerns. Signed-off-by: = --- .../core2/render/entity/AzEntityRenderer.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index a061c7235..7f44cb220 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -62,9 +62,15 @@ public void render( int packedLight ) { var cachedEntityAnimator = provideAnimator(entity); - var azBakedModel = provideBakedModel(entity, cachedEntityAnimator); + var azBakedModel = provideBakedModel(entity); + + if (cachedEntityAnimator != null && azBakedModel != null) { + cachedEntityAnimator.context().boneCache().setActiveModel(azBakedModel); + } + // Point the renderer's current animator reference to the cached entity animator before rendering. reusedAzEntityAnimator = cachedEntityAnimator; + // Execute the render pipeline. azEntityRendererPipeline.render( poseStack, @@ -83,15 +89,9 @@ public void render( return null; } - protected @Nullable AzBakedModel provideBakedModel(@NotNull T entity, AzEntityAnimator cachedEntityAnimator) { + protected @Nullable AzBakedModel provideBakedModel(@NotNull T entity) { var modelResourceLocation = getModelLocation(entity); - var bakedGeoModel = AzBakedModelCache.getInstance().getNullable(modelResourceLocation); - - if (cachedEntityAnimator != null && bakedGeoModel != null) { - cachedEntityAnimator.getAnimationProcessor().getBoneCache().setActiveModel(bakedGeoModel); - } - - return bakedGeoModel; + return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); } protected @Nullable AzEntityAnimator provideAnimator(T entity) { From 6ee1e2ff0bfdffb96046db16bc03015774c0092d Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 16:01:30 -0500 Subject: [PATCH 058/224] Reduced controller process arg boilerplate. Signed-off-by: = --- .../core2/animation/AzAnimationProcessor.java | 8 +----- .../controller/AzAnimationController.java | 26 +++++++++---------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index a59e562ee..bdf23acf5 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -21,14 +21,10 @@ public AzAnimationProcessor(AzAnimator animator) { public void update(AzAnimationContext context) { var animatable = context.animatable(); var timer = context.timer(); - var animTime = timer.getAnimTime(); var boneCache = context.boneCache(); - var config = context.config(); - var shouldCrash = config.crashIfBoneMissing(); boneCache.snapshot(); var boneSnapshots = boneCache.getBoneSnapshotsByName(); - var bonesByName = boneCache.getBonesByName(); for (var controller : animator.getAnimationControllerContainer().getAll()) { var easingType = controller.getOverrideEasingTypeFunction().apply(animatable); @@ -38,9 +34,7 @@ public void update(AzAnimationContext context) { controller.getBoneAnimationQueues().clear(); } - controller.setJustStarting(timer.isFirstTick()); - - controller.process(animatable, bonesByName, boneSnapshots, animTime, shouldCrash); + controller.update(context); // Progresses the current bones according to the animation queue. for (var boneAnimation : controller.getBoneAnimationQueues().values()) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 8175777d5..69a1376ff 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -1,6 +1,7 @@ package mod.azure.azurelib.core2.animation.controller; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mod.azure.azurelib.core2.animation.AzAnimationContext; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,7 +18,6 @@ import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; import mod.azure.azurelib.core.object.PlayState; -import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core2.animation.AzAnimationProcessor; import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; @@ -389,20 +389,18 @@ protected PlayState handleAnimationState(T animatable) { /** * This method is called every frame in order to populate the animation point queues, and process animation state * logic. - * - * @param bones The registered {@link CoreGeoBone bones} for this model - * @param snapshots The {@link BoneSnapshot} map - * @param seekTime The current tick + partial tick - * @param crashWhenCantFindBone Whether to hard-fail when a bone can't be found, or to continue with the remaining - * bones */ - public void process( - T animatable, - Map bones, - Map snapshots, - final double seekTime, - boolean crashWhenCantFindBone - ) { + public void update(AzAnimationContext context) { + var animatable = context.animatable(); + var boneCache = context.boneCache(); + var bones = boneCache.getBonesByName(); + var snapshots = boneCache.getBoneSnapshotsByName(); + var crashWhenCantFindBone = context.config().crashIfBoneMissing(); + var timer = context.timer(); + var seekTime = timer.getAnimTime(); + + setJustStarting(timer.isFirstTick()); + double adjustedTick = adjustTick(animatable, seekTime); if (animationState == AzAnimationControllerState.TRANSITIONING && adjustedTick >= transitionLength) { From b8bf3253471c9675352b9ad9895f413dc7d0639e Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 16:14:10 -0500 Subject: [PATCH 059/224] Refactor. Signed-off-by: = --- .../core2/animation/AzAnimationProcessor.java | 32 +++++++++++++------ .../controller/AzAnimationController.java | 2 +- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index bdf23acf5..98ca4e051 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -1,5 +1,9 @@ package mod.azure.azurelib.core2.animation; +import java.util.Map; + +import mod.azure.azurelib.core.animation.EasingType; +import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; public class AzAnimationProcessor { @@ -36,16 +40,7 @@ public void update(AzAnimationContext context) { controller.update(context); - // Progresses the current bones according to the animation queue. - for (var boneAnimation : controller.getBoneAnimationQueues().values()) { - var bone = boneAnimation.bone(); - var snapshot = boneSnapshots.get(bone.getName()); - var initialSnapshot = bone.getInitialSnapshot(); - - AzBoneAnimationUpdateUtil.updateRotations(boneAnimation, bone, easingType, initialSnapshot, snapshot); - AzBoneAnimationUpdateUtil.updatePositions(boneAnimation, bone, easingType, snapshot); - AzBoneAnimationUpdateUtil.updateScale(boneAnimation, bone, easingType, snapshot); - } + updateBoneSnapshots(controller, boneSnapshots, easingType); } this.reloadAnimations = false; @@ -53,4 +48,21 @@ public void update(AzAnimationContext context) { boneCache.update(context); timer.finishFirstTick(); } + + private void updateBoneSnapshots( + AzAnimationController controller, + Map boneSnapshots, + EasingType easingType + ) { + // Progresses the current bones according to the animation queue. + for (var boneAnimation : controller.getBoneAnimationQueues().values()) { + var bone = boneAnimation.bone(); + var snapshot = boneSnapshots.get(bone.getName()); + var initialSnapshot = bone.getInitialSnapshot(); + + AzBoneAnimationUpdateUtil.updateRotations(boneAnimation, bone, easingType, initialSnapshot, snapshot); + AzBoneAnimationUpdateUtil.updatePositions(boneAnimation, bone, easingType, snapshot); + AzBoneAnimationUpdateUtil.updateScale(boneAnimation, bone, easingType, snapshot); + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 69a1376ff..00e5dc980 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -1,7 +1,6 @@ package mod.azure.azurelib.core2.animation.controller; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.core2.animation.AzAnimationContext; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,6 +17,7 @@ import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; import mod.azure.azurelib.core.object.PlayState; +import mod.azure.azurelib.core2.animation.AzAnimationContext; import mod.azure.azurelib.core2.animation.AzAnimationProcessor; import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; From 99ba0c6aa6e538781ebfe555901d03ffe2315529 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 16:23:18 -0500 Subject: [PATCH 060/224] perf: Avoid flushing bone cache every frame. Signed-off-by: = --- .../core2/animation/cache/AzBoneCache.java | 14 ++++++++-- .../azurelib/core2/model/AzBakedModel.java | 27 ++++++++++++------- .../core2/model/cache/AzBakedModelCache.java | 2 +- .../model/factory/AzBakedModelFactory.java | 3 ++- .../impl/AzBuiltinBakedModelFactory.java | 5 ++-- 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java index 2290d41cf..b0f5d2fe4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java @@ -1,6 +1,7 @@ package mod.azure.azurelib.core2.animation.cache; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.resources.ResourceLocation; import java.util.Collection; import java.util.Map; @@ -17,6 +18,8 @@ public class AzBoneCache { private final Map boneSnapshotsByName; + private ResourceLocation cachedResourceLocation; + public AzBoneCache() { this.bonesByName = new Object2ObjectOpenHashMap<>(); this.boneSnapshotsByName = new Object2ObjectOpenHashMap<>(); @@ -38,8 +41,15 @@ public void snapshot() { * Should be called whenever switching models to render/animate */ public void setActiveModel(AzBakedModel model) { - this.bonesByName.clear(); - model.getTopLevelBones().forEach(this::registerGeoBone); + var newModelResourceLocation = model.getResourceLocation(); + + // If the cached resource location has not been set, or if the new resource location is different, + // then flush the bone cache and repopulate it with the new model's bones. + if (cachedResourceLocation == null || !cachedResourceLocation.equals(newModelResourceLocation)) { + bonesByName.clear(); + model.getTopLevelBones().forEach(this::registerGeoBone); + this.cachedResourceLocation = newModelResourceLocation; + } } public void update(AzAnimationContext context) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java index 90316d2cc..404d90913 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java @@ -1,5 +1,7 @@ package mod.azure.azurelib.core2.model; +import net.minecraft.resources.ResourceLocation; + import java.util.ArrayDeque; import java.util.Collections; import java.util.HashMap; @@ -11,21 +13,16 @@ public class AzBakedModel { private final Map bonesByName; + private final ResourceLocation resourceLocation; + private final List topLevelBones; - public AzBakedModel(List topLevelBones) { + public AzBakedModel(ResourceLocation resourceLocation, List topLevelBones) { + this.resourceLocation = resourceLocation; this.topLevelBones = Collections.unmodifiableList(topLevelBones); this.bonesByName = Collections.unmodifiableMap(mapBonesByName(topLevelBones)); } - public List getTopLevelBones() { - return topLevelBones; - } - - public Optional getBoneByName(String name) { - return Optional.ofNullable(bonesByName.get(name)); - } - private Map mapBonesByName(List bones) { var bonesByName = new HashMap(); var nodesToMap = new ArrayDeque<>(bones); @@ -38,4 +35,16 @@ private Map mapBonesByName(List bones) { return bonesByName; } + + public Optional getBoneByName(String name) { + return Optional.ofNullable(bonesByName.get(name)); + } + + public ResourceLocation getResourceLocation() { + return resourceLocation; + } + + public List getTopLevelBones() { + return topLevelBones; + } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java b/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java index 62718eaa7..557209339 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java @@ -35,7 +35,7 @@ public CompletableFuture loadModels(Executor backgroundExecutor, ResourceM Model model = FileLoader.loadModelFile(resource, resourceManager); return AzBakedModelFactoryRegistry.getForNamespace(resource.getNamespace()) - .constructGeoModel(GeometryTree.fromModel(model)); + .constructGeoModel(resource, GeometryTree.fromModel(model)); }, bakedModels::put); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java index 5573ff13f..ee4cbc257 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java @@ -1,6 +1,7 @@ package mod.azure.azurelib.core2.model.factory; import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; @@ -21,7 +22,7 @@ public abstract class AzBakedModelFactory { /** * Construct the output model from the given {@link GeometryTree}.
      */ - public abstract AzBakedModel constructGeoModel(GeometryTree geometryTree); + public abstract AzBakedModel constructGeoModel(ResourceLocation resourceLocation, GeometryTree geometryTree); /** * Construct a {@link AzBone} from the relevant raw input data diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java index 2626f56f6..97a9703e6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java @@ -1,6 +1,7 @@ package mod.azure.azurelib.core2.model.factory.impl; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.phys.Vec3; import mod.azure.azurelib.common.internal.client.util.RenderUtils; @@ -17,14 +18,14 @@ public final class AzBuiltinBakedModelFactory extends AzBakedModelFactory { @Override - public AzBakedModel constructGeoModel(GeometryTree geometryTree) { + public AzBakedModel constructGeoModel(ResourceLocation resourceLocation, GeometryTree geometryTree) { var bones = new ObjectArrayList(); for (var boneStructure : geometryTree.topLevelBones().values()) { bones.add(constructBone(boneStructure, geometryTree.properties(), null)); } - return new AzBakedModel(bones); + return new AzBakedModel(resourceLocation, bones); } @Override From 9681fbb2850ea17384f871487b51d563b1f79d62 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 13 Dec 2024 17:17:40 -0500 Subject: [PATCH 061/224] Simplify bone caching. Signed-off-by: = --- .../core2/animation/cache/AzBoneCache.java | 14 ++------------ .../azure/azurelib/core2/model/AzBakedModel.java | 4 ++++ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java index b0f5d2fe4..09bca9744 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java @@ -47,7 +47,8 @@ public void setActiveModel(AzBakedModel model) { // then flush the bone cache and repopulate it with the new model's bones. if (cachedResourceLocation == null || !cachedResourceLocation.equals(newModelResourceLocation)) { bonesByName.clear(); - model.getTopLevelBones().forEach(this::registerGeoBone); + model.getBonesByName().forEach(($, value) -> value.saveInitialSnapshot()); + bonesByName.putAll(model.getBonesByName()); this.cachedResourceLocation = newModelResourceLocation; } } @@ -69,17 +70,6 @@ public void update(AzAnimationContext context) { resetBoneTransformationMarkers(); } - /** - * Adds the given bone to the bones list for this processor.
      - * This is normally handled automatically by AzureLib.
      - * Failure to properly register a bone will break things. - */ - public void registerGeoBone(CoreGeoBone bone) { - bone.saveInitialSnapshot(); - this.bonesByName.put(bone.getName(), bone); - bone.getChildBones().forEach(this::registerGeoBone); - } - /** * Reset the transformation markers applied to each {@link CoreGeoBone} ready for the next render frame */ diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java index 404d90913..144c5fe68 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java @@ -40,6 +40,10 @@ public Optional getBoneByName(String name) { return Optional.ofNullable(bonesByName.get(name)); } + public Map getBonesByName() { + return bonesByName; + } + public ResourceLocation getResourceLocation() { return resourceLocation; } From 437643848a7aa9ba16adceb3bfcbe40611ebe4be Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 01:15:15 -0500 Subject: [PATCH 062/224] And this... is to go... even further... BEYOND! haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Signed-off-by: = --- .../core2/animation/cache/AzBoneCache.java | 40 ++++++------------- .../controller/AzAnimationController.java | 4 +- .../keyframe/AzKeyFrameProcessor.java | 4 +- .../azurelib/core2/model/AzBakedModel.java | 14 ++----- .../core2/model/cache/AzBakedModelCache.java | 2 +- .../model/factory/AzBakedModelFactory.java | 3 +- .../impl/AzBuiltinBakedModelFactory.java | 5 +-- 7 files changed, 25 insertions(+), 47 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java index 09bca9744..eb67ea36c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java @@ -1,33 +1,30 @@ package mod.azure.azurelib.core2.animation.cache; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.resources.ResourceLocation; import java.util.Collection; import java.util.Map; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core2.animation.AzAnimationContext; import mod.azure.azurelib.core2.animation.AzCachedBoneUpdateUtil; import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; public class AzBoneCache { - private final Map bonesByName; + private AzBakedModel bakedModel; private final Map boneSnapshotsByName; - private ResourceLocation cachedResourceLocation; - public AzBoneCache() { - this.bonesByName = new Object2ObjectOpenHashMap<>(); + this.bakedModel = AzBakedModel.EMPTY; this.boneSnapshotsByName = new Object2ObjectOpenHashMap<>(); } /** * Create new bone {@link BoneSnapshot} based on the bone's initial snapshot for the currently registered - * {@link CoreGeoBone GeoBones}, filtered by the bones already present in the master snapshots map + * {@link AzBone AzBones}, filtered by the bones already present in the master snapshots map */ public void snapshot() { for (var bone : getRegisteredBones()) { @@ -36,21 +33,10 @@ public void snapshot() { } /** - * Clear the {@link CoreGeoBone GeoBones} currently registered to the processor, then prepares the processor for a - * new model.
      - * Should be called whenever switching models to render/animate + * Sets the current model from which to */ public void setActiveModel(AzBakedModel model) { - var newModelResourceLocation = model.getResourceLocation(); - - // If the cached resource location has not been set, or if the new resource location is different, - // then flush the bone cache and repopulate it with the new model's bones. - if (cachedResourceLocation == null || !cachedResourceLocation.equals(newModelResourceLocation)) { - bonesByName.clear(); - model.getBonesByName().forEach(($, value) -> value.saveInitialSnapshot()); - bonesByName.putAll(model.getBonesByName()); - this.cachedResourceLocation = newModelResourceLocation; - } + this.bakedModel = model; } public void update(AzAnimationContext context) { @@ -71,21 +57,21 @@ public void update(AzAnimationContext context) { } /** - * Reset the transformation markers applied to each {@link CoreGeoBone} ready for the next render frame + * Reset the transformation markers applied to each {@link AzBone} ready for the next render frame */ private void resetBoneTransformationMarkers() { - getRegisteredBones().forEach(CoreGeoBone::resetStateChanges); + getRegisteredBones().forEach(AzBone::resetStateChanges); } /** - * Get an iterable collection of the {@link CoreGeoBone GeoBones} currently registered to the processor + * Get an iterable collection of the {@link AzBone AzBones} currently registered to the processor */ - private Collection getRegisteredBones() { - return this.bonesByName.values(); + private Collection getRegisteredBones() { + return getBonesByName().values(); } - public Map getBonesByName() { - return bonesByName; + public Map getBonesByName() { + return bakedModel.getBonesByName(); } public Map getBoneSnapshotsByName() { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 00e5dc980..7355e9a9c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -13,7 +13,6 @@ import java.util.function.Function; import java.util.function.ToDoubleFunction; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; import mod.azure.azurelib.core.object.PlayState; @@ -27,6 +26,7 @@ import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; import mod.azure.azurelib.core2.animation.primitive.AzStage; +import mod.azure.azurelib.core2.model.AzBone; /** * The actual controller that handles the playing and usage of animations, including their various keyframes and @@ -480,7 +480,7 @@ public void update(AzAnimationContext context) { * * @param modelRendererList The bone list from the {@link AzAnimationProcessor} */ - protected void createInitialQueues(Collection modelRendererList) { + protected void createInitialQueues(Collection modelRendererList) { boneAnimationQueues.clear(); for (var modelRenderer : modelRendererList) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java index b0f3c56d8..4de5b1159 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java @@ -4,7 +4,6 @@ import java.util.Map; import java.util.NoSuchElementException; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.keyframe.AnimationPoint; import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; import mod.azure.azurelib.core.keyframe.Keyframe; @@ -16,6 +15,7 @@ import mod.azure.azurelib.core.object.Axis; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerState; +import mod.azure.azurelib.core2.model.AzBone; public class AzKeyFrameProcessor { @@ -125,7 +125,7 @@ public void runCurrentAnimation( public void transitionFromCurrentAnimation( Map boneAnimationQueues, - Map bones, + Map bones, boolean crashWhenCantFindBone, double adjustedTick ) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java index 144c5fe68..33c9c4c91 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java @@ -1,7 +1,5 @@ package mod.azure.azurelib.core2.model; -import net.minecraft.resources.ResourceLocation; - import java.util.ArrayDeque; import java.util.Collections; import java.util.HashMap; @@ -11,14 +9,13 @@ public class AzBakedModel { - private final Map bonesByName; + public static final AzBakedModel EMPTY = new AzBakedModel(List.of()); - private final ResourceLocation resourceLocation; + private final Map bonesByName; private final List topLevelBones; - public AzBakedModel(ResourceLocation resourceLocation, List topLevelBones) { - this.resourceLocation = resourceLocation; + public AzBakedModel(List topLevelBones) { this.topLevelBones = Collections.unmodifiableList(topLevelBones); this.bonesByName = Collections.unmodifiableMap(mapBonesByName(topLevelBones)); } @@ -30,6 +27,7 @@ private Map mapBonesByName(List bones) { while (!nodesToMap.isEmpty()) { var currentBone = nodesToMap.poll(); nodesToMap.addAll(currentBone.getChildBones()); + currentBone.saveInitialSnapshot(); bonesByName.put(currentBone.getName(), currentBone); } @@ -44,10 +42,6 @@ public Map getBonesByName() { return bonesByName; } - public ResourceLocation getResourceLocation() { - return resourceLocation; - } - public List getTopLevelBones() { return topLevelBones; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java b/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java index 557209339..62718eaa7 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java @@ -35,7 +35,7 @@ public CompletableFuture loadModels(Executor backgroundExecutor, ResourceM Model model = FileLoader.loadModelFile(resource, resourceManager); return AzBakedModelFactoryRegistry.getForNamespace(resource.getNamespace()) - .constructGeoModel(resource, GeometryTree.fromModel(model)); + .constructGeoModel(GeometryTree.fromModel(model)); }, bakedModels::put); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java index ee4cbc257..5573ff13f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java @@ -1,7 +1,6 @@ package mod.azure.azurelib.core2.model.factory; import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; @@ -22,7 +21,7 @@ public abstract class AzBakedModelFactory { /** * Construct the output model from the given {@link GeometryTree}.
      */ - public abstract AzBakedModel constructGeoModel(ResourceLocation resourceLocation, GeometryTree geometryTree); + public abstract AzBakedModel constructGeoModel(GeometryTree geometryTree); /** * Construct a {@link AzBone} from the relevant raw input data diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java index 97a9703e6..2626f56f6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java @@ -1,7 +1,6 @@ package mod.azure.azurelib.core2.model.factory.impl; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.phys.Vec3; import mod.azure.azurelib.common.internal.client.util.RenderUtils; @@ -18,14 +17,14 @@ public final class AzBuiltinBakedModelFactory extends AzBakedModelFactory { @Override - public AzBakedModel constructGeoModel(ResourceLocation resourceLocation, GeometryTree geometryTree) { + public AzBakedModel constructGeoModel(GeometryTree geometryTree) { var bones = new ObjectArrayList(); for (var boneStructure : geometryTree.topLevelBones().values()) { bones.add(constructBone(boneStructure, geometryTree.properties(), null)); } - return new AzBakedModel(resourceLocation, bones); + return new AzBakedModel(bones); } @Override From 7dc8392037c7c8a5358a1e22f1de73cb26fdea9d Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 02:54:50 -0500 Subject: [PATCH 063/224] Progress towards rewriting bone-related logic. Signed-off-by: = --- .../core2/animation/AzAnimationProcessor.java | 6 +- .../animation/AzBoneAnimationUpdateUtil.java | 26 +- .../animation/AzCachedBoneUpdateUtil.java | 22 +- .../core2/animation/cache/AzBoneCache.java | 10 +- .../controller/AzAnimationController.java | 10 +- .../controller/AzAnimationQueue.java | 6 +- .../controller/AzBoneSnapshotCache.java | 12 +- .../keyframe/AzBoneAnimationQueue.java | 400 ++++++++++++++++++ .../keyframe/AzKeyFrameProcessor.java | 7 +- .../azure/azurelib/core2/model/AzBone.java | 144 +++---- .../azurelib/core2/model/AzBoneMetadata.java | 19 + .../azurelib/core2/model/AzBoneSnapshot.java | 180 ++++++++ .../impl/AzBuiltinBakedModelFactory.java | 11 +- .../render/pipeline/AzRendererPipeline.java | 2 + 14 files changed, 712 insertions(+), 143 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/model/AzBoneMetadata.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/model/AzBoneSnapshot.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index 98ca4e051..5d6db5c08 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -3,8 +3,8 @@ import java.util.Map; import mod.azure.azurelib.core.animation.EasingType; -import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; public class AzAnimationProcessor { @@ -51,14 +51,14 @@ public void update(AzAnimationContext context) { private void updateBoneSnapshots( AzAnimationController controller, - Map boneSnapshots, + Map boneSnapshots, EasingType easingType ) { // Progresses the current bones according to the animation queue. for (var boneAnimation : controller.getBoneAnimationQueues().values()) { var bone = boneAnimation.bone(); var snapshot = boneSnapshots.get(bone.getName()); - var initialSnapshot = bone.getInitialSnapshot(); + var initialSnapshot = bone.getInitialAzSnapshot(); AzBoneAnimationUpdateUtil.updateRotations(boneAnimation, bone, easingType, initialSnapshot, snapshot); AzBoneAnimationUpdateUtil.updatePositions(boneAnimation, bone, easingType, snapshot); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java index 40b34a6a0..bc6fcea94 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java @@ -1,17 +1,17 @@ package mod.azure.azurelib.core2.animation; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animation.EasingType; -import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; -import mod.azure.azurelib.core.state.BoneSnapshot; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; public class AzBoneAnimationUpdateUtil { public static void updatePositions( - BoneAnimationQueue boneAnimation, - CoreGeoBone bone, + AzBoneAnimationQueue boneAnimation, + AzBone bone, EasingType easingType, - BoneSnapshot snapshot + AzBoneSnapshot snapshot ) { var posXPoint = boneAnimation.positionXQueue().poll(); var posYPoint = boneAnimation.positionYQueue().poll(); @@ -28,11 +28,11 @@ public static void updatePositions( } public static void updateRotations( - BoneAnimationQueue boneAnimation, - CoreGeoBone bone, + AzBoneAnimationQueue boneAnimation, + AzBone bone, EasingType easingType, - BoneSnapshot initialSnapshot, - BoneSnapshot snapshot + AzBoneSnapshot initialSnapshot, + AzBoneSnapshot snapshot ) { var rotXPoint = boneAnimation.rotationXQueue().poll(); var rotYPoint = boneAnimation.rotationYQueue().poll(); @@ -55,10 +55,10 @@ public static void updateRotations( } public static void updateScale( - BoneAnimationQueue boneAnimation, - CoreGeoBone bone, + AzBoneAnimationQueue boneAnimation, + AzBone bone, EasingType easingType, - BoneSnapshot snapshot + AzBoneSnapshot snapshot ) { var scaleXPoint = boneAnimation.scaleXQueue().poll(); var scaleYPoint = boneAnimation.scaleYQueue().poll(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java index cc1750152..f482f6e9e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java @@ -2,15 +2,15 @@ import java.util.Map; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; -import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core.utils.Interpolations; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; public class AzCachedBoneUpdateUtil { public static void updateCachedBonePosition( - CoreGeoBone bone, - Map boneSnapshots, + AzBone bone, + Map boneSnapshots, double animTime, double resetTickLength ) { @@ -18,7 +18,7 @@ public static void updateCachedBonePosition( return; } - var initialSnapshot = bone.getInitialSnapshot(); + var initialSnapshot = bone.getInitialAzSnapshot(); var saveSnapshot = boneSnapshots.get(bone.getName()); if (saveSnapshot.isPosAnimInProgress()) { @@ -58,8 +58,8 @@ public static void updateCachedBonePosition( } public static void updateCachedBoneRotation( - CoreGeoBone bone, - Map boneSnapshots, + AzBone bone, + Map boneSnapshots, double animTime, double resetTickLength ) { @@ -67,7 +67,7 @@ public static void updateCachedBoneRotation( return; } - var initialSnapshot = bone.getInitialSnapshot(); + var initialSnapshot = bone.getInitialAzSnapshot(); var saveSnapshot = boneSnapshots.get(bone.getName()); if (saveSnapshot.isRotAnimInProgress()) { @@ -95,8 +95,8 @@ public static void updateCachedBoneRotation( } public static void updateCachedBoneScale( - CoreGeoBone bone, - Map boneSnapshots, + AzBone bone, + Map boneSnapshots, double animTime, double resetTickLength ) { @@ -104,7 +104,7 @@ public static void updateCachedBoneScale( return; } - var initialSnapshot = bone.getInitialSnapshot(); + var initialSnapshot = bone.getInitialAzSnapshot(); var saveSnapshot = boneSnapshots.get(bone.getName()); if (saveSnapshot.isScaleAnimInProgress()) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java index eb67ea36c..d6b750119 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java @@ -5,17 +5,17 @@ import java.util.Collection; import java.util.Map; -import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core2.animation.AzAnimationContext; import mod.azure.azurelib.core2.animation.AzCachedBoneUpdateUtil; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; public class AzBoneCache { private AzBakedModel bakedModel; - private final Map boneSnapshotsByName; + private final Map boneSnapshotsByName; public AzBoneCache() { this.bakedModel = AzBakedModel.EMPTY; @@ -23,12 +23,12 @@ public AzBoneCache() { } /** - * Create new bone {@link BoneSnapshot} based on the bone's initial snapshot for the currently registered + * Create new bone {@link AzBoneSnapshot} based on the bone's initial snapshot for the currently registered * {@link AzBone AzBones}, filtered by the bones already present in the master snapshots map */ public void snapshot() { for (var bone : getRegisteredBones()) { - boneSnapshotsByName.computeIfAbsent(bone.getName(), $ -> BoneSnapshot.copy(bone.getInitialSnapshot())); + boneSnapshotsByName.computeIfAbsent(bone.getName(), $ -> AzBoneSnapshot.copy(bone.getInitialAzSnapshot())); } } @@ -74,7 +74,7 @@ public Map getBonesByName() { return bakedModel.getBonesByName(); } - public Map getBoneSnapshotsByName() { + public Map getBoneSnapshotsByName() { return boneSnapshotsByName; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 7355e9a9c..19c18adbb 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -19,6 +19,7 @@ import mod.azure.azurelib.core2.animation.AzAnimationContext; import mod.azure.azurelib.core2.animation.AzAnimationProcessor; import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameProcessor; @@ -39,7 +40,7 @@ public class AzAnimationController { protected final String name; - protected final Map boneAnimationQueues = new Object2ObjectOpenHashMap<>(); + protected final Map boneAnimationQueues = new Object2ObjectOpenHashMap<>(); protected final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); @@ -94,7 +95,7 @@ public AzAnimationController(AzAnimator animator, String name, int transition this.animator = animator; this.name = name; this.transitionLength = transitionTickTime; - this.animationQueue = new AzAnimationQueue<>(animator); + this.animationQueue = new AzAnimationQueue<>(); this.boneSnapshotCache = new AzBoneSnapshotCache(); this.keyFrameCallbacks = AzKeyFrameCallbacks.noop(); this.keyFrameCallbackManager = new AzKeyFrameCallbackManager<>(this); @@ -190,7 +191,7 @@ public AzQueuedAnimation getCurrentAnimation() { /** * Gets the currently loaded animation's {@link BoneAnimationQueue BoneAnimationQueues}. */ - public Map getBoneAnimationQueues() { + public Map getBoneAnimationQueues() { return boneAnimationQueues; } @@ -484,7 +485,8 @@ protected void createInitialQueues(Collection modelRendererList) { boneAnimationQueues.clear(); for (var modelRenderer : modelRendererList) { - boneAnimationQueues.put(modelRenderer.getName(), new BoneAnimationQueue(modelRenderer)); + // TODO: Optimize. + boneAnimationQueues.put(modelRenderer.getName(), new AzBoneAnimationQueue(modelRenderer)); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java index a5a05e0db..20cd88b68 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java @@ -9,7 +9,6 @@ import java.util.LinkedList; import java.util.Queue; -import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; public class AzAnimationQueue { @@ -18,11 +17,8 @@ public class AzAnimationQueue { private final Queue animationQueue; - private final AzAnimator animator; - - public AzAnimationQueue(AzAnimator animator) { + public AzAnimationQueue() { this.animationQueue = new LinkedList<>(); - this.animator = animator; } public void add(@NotNull AzQueuedAnimation queuedAnimation) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneSnapshotCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneSnapshotCache.java index ade445ab5..b8ee08d81 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneSnapshotCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneSnapshotCache.java @@ -6,25 +6,25 @@ import java.util.Collection; import java.util.Map; -import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; public class AzBoneSnapshotCache { - private final Map boneSnapshots; + private final Map boneSnapshots; public AzBoneSnapshotCache() { this.boneSnapshots = new Object2ObjectOpenHashMap<>(); } /** - * Cache the relevant {@link BoneSnapshot BoneSnapshots} for the current {@link AzQueuedAnimation} for animation + * Cache the relevant {@link AzBoneSnapshot AzBoneSnapshots} for the current {@link AzQueuedAnimation} for animation * lerping * * @param animation The {@code QueuedAnimation} to filter {@code BoneSnapshots} for * @param snapshots The master snapshot collection to pull filter from */ - public void put(AzQueuedAnimation animation, Collection snapshots) { + public void put(AzQueuedAnimation animation, Collection snapshots) { if (animation.animation().boneAnimations() == null) { return; } @@ -32,14 +32,14 @@ public void put(AzQueuedAnimation animation, Collection snapshots) for (var snapshot : snapshots) { for (var boneAnimation : animation.animation().boneAnimations()) { if (boneAnimation.boneName().equals(snapshot.getBone().getName())) { - boneSnapshots.put(boneAnimation.boneName(), BoneSnapshot.copy(snapshot)); + boneSnapshots.put(boneAnimation.boneName(), AzBoneSnapshot.copy(snapshot)); break; } } } } - public @Nullable BoneSnapshot getOrNull(String name) { + public @Nullable AzBoneSnapshot getOrNull(String name) { return boneSnapshots.get(name); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java new file mode 100644 index 000000000..e83b3c2c1 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java @@ -0,0 +1,400 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import mod.azure.azurelib.core.keyframe.AnimationPoint; +import mod.azure.azurelib.core.keyframe.AnimationPointQueue; +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; + +/** + * A bone pseudo-stack for bone animation positions, scales, and rotations. Animation points are calculated then pushed + * onto their respective queues to be used for transformations in rendering + */ +public record AzBoneAnimationQueue( + AzBone bone, + AnimationPointQueue rotationXQueue, + AnimationPointQueue rotationYQueue, + AnimationPointQueue rotationZQueue, + AnimationPointQueue positionXQueue, + AnimationPointQueue positionYQueue, + AnimationPointQueue positionZQueue, + AnimationPointQueue scaleXQueue, + AnimationPointQueue scaleYQueue, + AnimationPointQueue scaleZQueue +) { + + public AzBoneAnimationQueue(AzBone bone) { + // TODO: Optimize + this( + bone, + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue() + ); + } + + /** + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#positionXQueue} + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addPosXPoint( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.positionXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#positionYQueue} + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addPosYPoint( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.positionYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#positionZQueue} + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addPosZPoint( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.positionZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new X, Y, and Z position {@link AnimationPoint} to their respective queues + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (base on the {@link AzAnimationController} + * @param startSnapshot The {@link AzBoneSnapshot} that serves as the starting positions relevant to the keyframe + * provided + * @param nextXPoint The X {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextYPoint The Y {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextZPoint The Z {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + */ + public void addNextPosition( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + AzBoneSnapshot startSnapshot, + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint + ) { + addPosXPoint( + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getOffsetX(), + nextXPoint.animationStartValue() + ); + addPosYPoint( + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getOffsetY(), + nextYPoint.animationStartValue() + ); + addPosZPoint( + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getOffsetZ(), + nextZPoint.animationStartValue() + ); + } + + /** + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#scaleXQueue} + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addScaleXPoint( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.scaleXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#scaleYQueue} + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addScaleYPoint( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.scaleYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#scaleZQueue} + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addScaleZPoint( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.scaleZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new X, Y, and Z scale {@link AnimationPoint} to their respective queues + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (base on the {@link AzAnimationController} + * @param startSnapshot The {@link AzBoneSnapshot} that serves as the starting scales relevant to the keyframe + * provided + * @param nextXPoint The X {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextYPoint The Y {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextZPoint The Z {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + */ + public void addNextScale( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + AzBoneSnapshot startSnapshot, + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint + ) { + addScaleXPoint( + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getScaleX(), + nextXPoint.animationStartValue() + ); + addScaleYPoint( + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getScaleY(), + nextYPoint.animationStartValue() + ); + addScaleZPoint( + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getScaleZ(), + nextZPoint.animationStartValue() + ); + } + + /** + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#rotationXQueue} + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addRotationXPoint( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.rotationXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#rotationYQueue} + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addRotationYPoint( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.rotationYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#rotationZQueue} + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addRotationZPoint( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.rotationZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new X, Y, and Z scale {@link AnimationPoint} to their respective queues + * + * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (base on the {@link AzAnimationController} + * @param startSnapshot The {@link AzBoneSnapshot} that serves as the starting rotations relevant to the keyframe + * provided + * @param initialSnapshot The {@link AzBoneSnapshot} that serves as the unmodified rotations of the bone + * @param nextXPoint The X {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextYPoint The Y {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextZPoint The Z {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + */ + public void addNextRotation( + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + AzBoneSnapshot startSnapshot, + AzBoneSnapshot initialSnapshot, + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint + ) { + addRotationXPoint( + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getRotX() - initialSnapshot.getRotX(), + nextXPoint.animationStartValue() + ); + addRotationYPoint( + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getRotY() - initialSnapshot.getRotY(), + nextYPoint.animationStartValue() + ); + addRotationZPoint( + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getRotZ() - initialSnapshot.getRotZ(), + nextZPoint.animationStartValue() + ); + } + + /** + * Add an X, Y, and Z position {@link AnimationPoint} to their respective queues + * + * @param xPoint The x position {@code AnimationPoint} to add + * @param yPoint The y position {@code AnimationPoint} to add + * @param zPoint The z position {@code AnimationPoint} to add + */ + public void addPositions(AnimationPoint xPoint, AnimationPoint yPoint, AnimationPoint zPoint) { + this.positionXQueue.add(xPoint); + this.positionYQueue.add(yPoint); + this.positionZQueue.add(zPoint); + } + + /** + * Add an X, Y, and Z scale {@link AnimationPoint} to their respective queues + * + * @param xPoint The x scale {@code AnimationPoint} to add + * @param yPoint The y scale {@code AnimationPoint} to add + * @param zPoint The z scale {@code AnimationPoint} to add + */ + public void addScales(AnimationPoint xPoint, AnimationPoint yPoint, AnimationPoint zPoint) { + this.scaleXQueue.add(xPoint); + this.scaleYQueue.add(yPoint); + this.scaleZQueue.add(zPoint); + } + + /** + * Add an X, Y, and Z rotation {@link AnimationPoint} to their respective queues + * + * @param xPoint The x rotation {@code AnimationPoint} to add + * @param yPoint The y rotation {@code AnimationPoint} to add + * @param zPoint The z rotation {@code AnimationPoint} to add + */ + public void addRotations(AnimationPoint xPoint, AnimationPoint yPoint, AnimationPoint zPoint) { + this.rotationXQueue.add(xPoint); + this.rotationYQueue.add(yPoint); + this.rotationZQueue.add(zPoint); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java index 4de5b1159..ba7447756 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java @@ -5,7 +5,6 @@ import java.util.NoSuchElementException; import mod.azure.azurelib.core.keyframe.AnimationPoint; -import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; import mod.azure.azurelib.core.keyframe.Keyframe; import mod.azure.azurelib.core.keyframe.KeyframeLocation; import mod.azure.azurelib.core.math.Constant; @@ -35,7 +34,7 @@ public AzKeyFrameProcessor(AzAnimationController animationController) { * bone, or continue with the remaining bones */ public void runCurrentAnimation( - Map boneAnimationQueues, + Map boneAnimationQueues, T animatable, double adjustedTick, double seekTime, @@ -124,7 +123,7 @@ public void runCurrentAnimation( } public void transitionFromCurrentAnimation( - Map boneAnimationQueues, + Map boneAnimationQueues, Map bones, boolean crashWhenCantFindBone, double adjustedTick @@ -157,7 +156,7 @@ public void transitionFromCurrentAnimation( adjustedTick, transitionLength, boneSnapshot, - bone.getInitialSnapshot(), + bone.getInitialAzSnapshot(), getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java index b9f8d9d03..962bd2b31 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java @@ -6,10 +6,10 @@ package mod.azure.azurelib.core2.model; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import org.jetbrains.annotations.Nullable; import org.joml.Matrix3f; import org.joml.Matrix4f; import org.joml.Vector3d; +import org.joml.Vector3f; import org.joml.Vector4f; import java.util.List; @@ -25,57 +25,31 @@ */ public class AzBone implements CoreGeoBone { - private final AzBone parent; - - private final String name; + private final AzBoneMetadata metadata; private final List children = new ObjectArrayList<>(); private final List cubes = new ObjectArrayList<>(); - private final Boolean mirror; - - private final Double inflate; - - private final Boolean dontRender; - - private final Boolean reset; - private final Matrix4f modelSpaceMatrix = new Matrix4f(); private final Matrix4f localSpaceMatrix = new Matrix4f(); private final Matrix4f worldSpaceMatrix = new Matrix4f(); - private BoneSnapshot initialSnapshot; + private AzBoneSnapshot initialSnapshot; private boolean hidden; private boolean childrenHidden = false; - private float scaleX = 1; - - private float scaleY = 1; - - private float scaleZ = 1; - - private float positionX; - - private float positionY; + private final Vector3f pivot; - private float positionZ; + private final Vector3f position; - private float pivotX; + private final Vector3f rotation; - private float pivotY; - - private float pivotZ; - - private float rotX; - - private float rotY; - - private float rotZ; + private final Vector3f scale; private boolean positionChanged = false; @@ -87,22 +61,15 @@ public class AzBone implements CoreGeoBone { private boolean trackingMatrices; - public AzBone( - @Nullable AzBone parent, - String name, - Boolean mirror, - @Nullable Double inflate, - @Nullable Boolean dontRender, - @Nullable Boolean reset - ) { - this.parent = parent; - this.name = name; - this.mirror = mirror; - this.inflate = inflate; - this.dontRender = dontRender; - this.reset = reset; + public AzBone(AzBoneMetadata metadata) { + this.metadata = metadata; this.trackingMatrices = false; - this.hidden = this.dontRender == Boolean.TRUE; + this.hidden = metadata.dontRender() == Boolean.TRUE; + + this.position = new Vector3f(); + this.pivot = new Vector3f(); + this.rotation = new Vector3f(); + this.scale = new Vector3f(1, 1, 1); this.worldSpaceNormal.identity(); this.worldSpaceMatrix.identity(); @@ -112,118 +79,118 @@ public AzBone( @Override public String getName() { - return this.name; + return metadata.name(); } @Override public AzBone getParent() { - return this.parent; + return metadata.parent(); } @Override public float getRotX() { - return this.rotX; + return this.rotation.x; } @Override public void setRotX(float value) { - this.rotX = value; + this.rotation.x = value; markRotationAsChanged(); } @Override public float getRotY() { - return this.rotY; + return this.rotation.y; } @Override public void setRotY(float value) { - this.rotY = value; + this.rotation.y = value; markRotationAsChanged(); } @Override public float getRotZ() { - return this.rotZ; + return this.rotation.z; } @Override public void setRotZ(float value) { - this.rotZ = value; + this.rotation.z = value; markRotationAsChanged(); } @Override public float getPosX() { - return this.positionX; + return this.position.x; } @Override public void setPosX(float value) { - this.positionX = value; + this.position.x = value; markPositionAsChanged(); } @Override public float getPosY() { - return this.positionY; + return this.position.y; } @Override public void setPosY(float value) { - this.positionY = value; + this.position.y = value; markPositionAsChanged(); } @Override public float getPosZ() { - return this.positionZ; + return this.position.z; } @Override public void setPosZ(float value) { - this.positionZ = value; + this.position.z = value; markPositionAsChanged(); } @Override public float getScaleX() { - return this.scaleX; + return this.scale.x; } @Override public void setScaleX(float value) { - this.scaleX = value; + this.scale.x = value; markScaleAsChanged(); } @Override public float getScaleY() { - return this.scaleY; + return this.scale.y; } @Override public void setScaleY(float value) { - this.scaleY = value; + this.scale.y = value; markScaleAsChanged(); } @Override public float getScaleZ() { - return this.scaleZ; + return this.scale.z; } @Override public void setScaleZ(float value) { - this.scaleZ = value; + this.scale.z = value; markScaleAsChanged(); } @@ -247,32 +214,32 @@ public void setChildrenHidden(boolean hideChildren) { @Override public float getPivotX() { - return this.pivotX; + return this.pivot.x; } @Override public void setPivotX(float value) { - this.pivotX = value; + this.pivot.x = value; } @Override public float getPivotY() { - return this.pivotY; + return this.pivot.y; } @Override public void setPivotY(float value) { - this.pivotY = value; + this.pivot.y = value; } @Override public float getPivotZ() { - return this.pivotZ; + return this.pivot.z; } @Override public void setPivotZ(float value) { - this.pivotZ = value; + this.pivot.z = value; } @Override @@ -317,8 +284,16 @@ public void resetStateChanges() { this.positionChanged = false; } + /** + * @deprecated DO NOT USE OR I WILL FIND YOU. + */ @Override + @Deprecated(forRemoval = true) public BoneSnapshot getInitialSnapshot() { + throw new UnsupportedOperationException(); + } + + public AzBoneSnapshot getInitialAzSnapshot() { return this.initialSnapshot; } @@ -329,24 +304,25 @@ public List getChildBones() { @Override public void saveInitialSnapshot() { - if (this.initialSnapshot == null) - this.initialSnapshot = saveSnapshot(); + if (this.initialSnapshot == null) { + this.initialSnapshot = new AzBoneSnapshot(this); + } } public Boolean getMirror() { - return this.mirror; + return metadata.mirror(); } public Double getInflate() { - return this.inflate; + return metadata.inflate(); } public Boolean shouldNeverRender() { - return this.dontRender; + return metadata.dontRender(); } public Boolean getReset() { - return this.reset; + return metadata.reset(); } public List getCubes() { @@ -419,7 +395,7 @@ public Vector3d getModelPosition() { public void setModelPosition(Vector3d pos) { // Doesn't work on bones with parent transforms - AzBone parent = getParent(); + AzBone parent = metadata.parent(); Matrix4f matrix = (parent == null ? new Matrix4f().identity() : new Matrix4f(parent.getModelSpaceMatrix())) .invert(); Vector4f vec = matrix.transform( @@ -460,9 +436,9 @@ public Vector3d getScaleVector() { } public void addRotationOffsetFromBone(AzBone source) { - setRotX(getRotX() + source.getRotX() - source.getInitialSnapshot().getRotX()); - setRotY(getRotY() + source.getRotY() - source.getInitialSnapshot().getRotY()); - setRotZ(getRotZ() + source.getRotZ() - source.getInitialSnapshot().getRotZ()); + setRotX(getRotX() + source.getRotX() - source.getInitialAzSnapshot().getRotX()); + setRotY(getRotY() + source.getRotY() - source.getInitialAzSnapshot().getRotY()); + setRotZ(getRotZ() + source.getRotZ() - source.getInitialAzSnapshot().getRotZ()); } @Override diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneMetadata.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneMetadata.java new file mode 100644 index 000000000..5122afac4 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneMetadata.java @@ -0,0 +1,19 @@ +package mod.azure.azurelib.core2.model; + +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.common.internal.common.loading.json.raw.Bone; + +public record AzBoneMetadata( + @Nullable Boolean dontRender, + @Nullable Double inflate, + Boolean mirror, + String name, + @Nullable AzBone parent, + @Nullable Boolean reset +) { + + public AzBoneMetadata(Bone bone, AzBone parent) { + this(bone.neverRender(), bone.inflate(), bone.mirror(), bone.name(), parent, bone.reset()); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneSnapshot.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneSnapshot.java new file mode 100644 index 000000000..a4804d17c --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneSnapshot.java @@ -0,0 +1,180 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ + +package mod.azure.azurelib.core2.model; + +import org.joml.Vector3f; + +/** + * A state monitoring class for a given {@link AzBone}.
      + */ +public class AzBoneSnapshot { + + private final AzBone bone; + + private final Vector3f offsetPosition; + + private final Vector3f rotation; + + private final Vector3f scale; + + private double lastResetRotationTick = 0; + + private double lastResetPositionTick = 0; + + private double lastResetScaleTick = 0; + + private boolean rotAnimInProgress = true; + + private boolean posAnimInProgress = true; + + private boolean scaleAnimInProgress = true; + + public AzBoneSnapshot(AzBone bone) { + this.bone = bone; + this.offsetPosition = new Vector3f(bone.getPosX(), bone.getPosY(), bone.getPosZ()); + this.rotation = new Vector3f(bone.getRotX(), bone.getRotY(), bone.getRotZ()); + this.scale = new Vector3f(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); + } + + public static AzBoneSnapshot copy(AzBoneSnapshot snapshot) { + AzBoneSnapshot newSnapshot = new AzBoneSnapshot(snapshot.bone); + + newSnapshot.offsetPosition.set(snapshot.offsetPosition); + newSnapshot.rotation.set(snapshot.rotation); + newSnapshot.scale.set(snapshot.scale); + + return newSnapshot; + } + + public AzBone getBone() { + return this.bone; + } + + public float getScaleX() { + return this.scale.x; + } + + public float getScaleY() { + return this.scale.y; + } + + public float getScaleZ() { + return this.scale.z; + } + + public float getOffsetX() { + return this.offsetPosition.x; + } + + public float getOffsetY() { + return this.offsetPosition.y; + } + + public float getOffsetZ() { + return this.offsetPosition.z; + } + + public float getRotX() { + return this.rotation.x; + } + + public float getRotY() { + return this.rotation.y; + } + + public float getRotZ() { + return this.rotation.z; + } + + public double getLastResetRotationTick() { + return this.lastResetRotationTick; + } + + public double getLastResetPositionTick() { + return this.lastResetPositionTick; + } + + public double getLastResetScaleTick() { + return this.lastResetScaleTick; + } + + public boolean isRotAnimInProgress() { + return this.rotAnimInProgress; + } + + public boolean isPosAnimInProgress() { + return this.posAnimInProgress; + } + + public boolean isScaleAnimInProgress() { + return this.scaleAnimInProgress; + } + + /** + * Update the scale state of this snapshot + */ + public void updateScale(float scaleX, float scaleY, float scaleZ) { + scale.set(scaleX, scaleY, scaleZ); + } + + /** + * Update the offset state of this snapshot + */ + public void updateOffset(float offsetX, float offsetY, float offsetZ) { + offsetPosition.set(offsetX, offsetY, offsetZ); + } + + /** + * Update the rotation state of this snapshot + */ + public void updateRotation(float rotX, float rotY, float rotZ) { + rotation.set(rotX, rotY, rotZ); + } + + public void startPosAnim() { + this.posAnimInProgress = true; + } + + public void stopPosAnim(double tick) { + this.posAnimInProgress = false; + this.lastResetPositionTick = tick; + } + + public void startRotAnim() { + this.rotAnimInProgress = true; + } + + public void stopRotAnim(double tick) { + this.rotAnimInProgress = false; + this.lastResetRotationTick = tick; + } + + public void startScaleAnim() { + this.scaleAnimInProgress = true; + } + + public void stopScaleAnim(double tick) { + this.scaleAnimInProgress = false; + this.lastResetScaleTick = tick; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + + if (obj == null || getClass() != obj.getClass()) + return false; + + return hashCode() == obj.hashCode(); + } + + @Override + public int hashCode() { + return this.bone.getName().hashCode(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java index 2626f56f6..f5eb40ba0 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java @@ -11,6 +11,7 @@ import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneMetadata; import mod.azure.azurelib.core2.model.factory.AzBakedModelFactory; import mod.azure.azurelib.core2.model.factory.primitive.VertexSet; @@ -30,14 +31,8 @@ public AzBakedModel constructGeoModel(GeometryTree geometryTree) { @Override public AzBone constructBone(BoneStructure boneStructure, ModelProperties properties, AzBone parent) { var bone = boneStructure.self(); - var newBone = new AzBone( - parent, - bone.name(), - bone.mirror(), - bone.inflate(), - bone.neverRender(), - bone.reset() - ); + var boneMetadata = new AzBoneMetadata(bone, parent); + var newBone = new AzBone(boneMetadata); var rotation = RenderUtils.arrayToVec(bone.rotation()); var pivot = RenderUtils.arrayToVec(bone.pivot()); diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index a43730d33..702f593bd 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -413,6 +413,7 @@ protected void renderCube( if (quad == null) continue; + // TODO: Optimize Vector3f normal = normalisedPoseState.transform(new Vector3f(quad.normal())); RenderUtils.fixInvertedFlatCube(cube, normal); @@ -435,6 +436,7 @@ protected void createVerticesOfQuad( ) { for (var vertex : quad.vertices()) { var position = vertex.position(); + // TODO: Optimize var vector4f = poseState.transform(new Vector4f(position.x(), position.y(), position.z(), 1.0f)); buffer.addVertex( From 269c5c94fe6aed8b5e87f264bfd46c9d3782e204 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 10:22:09 -0500 Subject: [PATCH 064/224] perf: Avoid creating bone animation queues every frame. Signed-off-by: = --- .../core2/animation/AzAnimationProcessor.java | 3 +- .../azurelib/core2/animation/AzAnimator.java | 14 +++++ .../core2/animation/cache/AzBoneCache.java | 43 ++++++++------- .../controller/AzAnimationController.java | 54 ++++++------------- .../controller/AzAnimationQueue.java | 6 +-- .../controller/AzBoneAnimationQueueCache.java | 39 ++++++++++++++ .../keyframe/AzKeyFrameProcessor.java | 13 ++--- .../azurelib/core2/model/AzBakedModel.java | 10 +++- .../core2/render/entity/AzEntityRenderer.java | 2 +- 9 files changed, 107 insertions(+), 77 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index 5d6db5c08..6a07115d4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -27,7 +27,6 @@ public void update(AzAnimationContext context) { var timer = context.timer(); var boneCache = context.boneCache(); - boneCache.snapshot(); var boneSnapshots = boneCache.getBoneSnapshotsByName(); for (var controller : animator.getAnimationControllerContainer().getAll()) { @@ -55,7 +54,7 @@ private void updateBoneSnapshots( EasingType easingType ) { // Progresses the current bones according to the animation queue. - for (var boneAnimation : controller.getBoneAnimationQueues().values()) { + for (var boneAnimation : controller.getBoneAnimationQueues()) { var bone = boneAnimation.bone(); var snapshot = boneSnapshots.get(bone.getName()); var initialSnapshot = bone.getInitialAzSnapshot(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index cb2794f2e..0c2592b5f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -1,5 +1,6 @@ package mod.azure.azurelib.core2.animation; +import mod.azure.azurelib.core2.model.AzBakedModel; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; @@ -84,6 +85,19 @@ protected void applyMolangQueries(T animatable, double animTime) { */ public void setCustomAnimations(T animatable) {} + public void setActiveModel(AzBakedModel model) { + var modelChanged = reusableContext.boneCache().setActiveModel(model); + + if (modelChanged) { + // If the model changed, we need to clear the bone animation queue cache for every controller. + // TODO: We shouldn't have to remember to do this. If the baked model changes, then the bone cache + // should be re-instantiated. If the bone cache is re-instantiated, then so should the bone animation + // queue caches. + animationControllerContainer.getAll() + .forEach(controller -> controller.getBoneAnimationQueueCache().clear()); + } + } + /** * Get the baked animation object used for rendering from the given resource path */ diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java index d6b750119..373259a9a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java @@ -2,8 +2,8 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import java.util.Collection; import java.util.Map; +import java.util.Objects; import mod.azure.azurelib.core2.animation.AzAnimationContext; import mod.azure.azurelib.core2.animation.AzCachedBoneUpdateUtil; @@ -22,21 +22,15 @@ public AzBoneCache() { this.boneSnapshotsByName = new Object2ObjectOpenHashMap<>(); } - /** - * Create new bone {@link AzBoneSnapshot} based on the bone's initial snapshot for the currently registered - * {@link AzBone AzBones}, filtered by the bones already present in the master snapshots map - */ - public void snapshot() { - for (var bone : getRegisteredBones()) { - boneSnapshotsByName.computeIfAbsent(bone.getName(), $ -> AzBoneSnapshot.copy(bone.getInitialAzSnapshot())); + public boolean setActiveModel(AzBakedModel model) { + var willModelChange = !Objects.equals(bakedModel, model); + this.bakedModel = model; + + if (willModelChange) { + snapshot(); } - } - /** - * Sets the current model from which to - */ - public void setActiveModel(AzBakedModel model) { - this.bakedModel = model; + return willModelChange; } public void update(AzAnimationContext context) { @@ -47,7 +41,7 @@ public void update(AzAnimationContext context) { var resetTickLength = config.boneResetTime(); // Updates the cached bone snapshots (only if they have changed). - for (var bone : getRegisteredBones()) { + for (var bone : bakedModel.getBonesByName().values()) { AzCachedBoneUpdateUtil.updateCachedBoneRotation(bone, boneSnapshots, animTime, resetTickLength); AzCachedBoneUpdateUtil.updateCachedBonePosition(bone, boneSnapshots, animTime, resetTickLength); AzCachedBoneUpdateUtil.updateCachedBoneScale(bone, boneSnapshots, animTime, resetTickLength); @@ -60,18 +54,23 @@ public void update(AzAnimationContext context) { * Reset the transformation markers applied to each {@link AzBone} ready for the next render frame */ private void resetBoneTransformationMarkers() { - getRegisteredBones().forEach(AzBone::resetStateChanges); + bakedModel.getBonesByName().values().forEach(AzBone::resetStateChanges); } /** - * Get an iterable collection of the {@link AzBone AzBones} currently registered to the processor + * Create new bone {@link AzBoneSnapshot} based on the bone's initial snapshot for the currently registered + * {@link AzBone AzBones}, filtered by the bones already present in the master snapshots map */ - private Collection getRegisteredBones() { - return getBonesByName().values(); + private void snapshot() { + boneSnapshotsByName.clear(); + + for (var bone : bakedModel.getBonesByName().values()) { + boneSnapshotsByName.put(bone.getName(), AzBoneSnapshot.copy(bone.getInitialAzSnapshot())); + } } - public Map getBonesByName() { - return bakedModel.getBonesByName(); + public AzBakedModel getBakedModel() { + return bakedModel; } public Map getBoneSnapshotsByName() { @@ -79,6 +78,6 @@ public Map getBoneSnapshotsByName() { } public boolean isEmpty() { - return getRegisteredBones().isEmpty(); + return bakedModel.getBonesByName().isEmpty(); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 19c18adbb..ea1ff6a3e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -17,7 +17,6 @@ import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.core2.animation.AzAnimationContext; -import mod.azure.azurelib.core2.animation.AzAnimationProcessor; import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; @@ -27,7 +26,6 @@ import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; import mod.azure.azurelib.core2.animation.primitive.AzStage; -import mod.azure.azurelib.core2.model.AzBone; /** * The actual controller that handles the playing and usage of animations, including their various keyframes and @@ -40,14 +38,14 @@ public class AzAnimationController { protected final String name; - protected final Map boneAnimationQueues = new Object2ObjectOpenHashMap<>(); - protected final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); - private final AzAnimationQueue animationQueue; + private final AzAnimationQueue animationQueue; private final AzAnimator animator; + private final AzBoneAnimationQueueCache boneAnimationQueueCache; + private final AzBoneSnapshotCache boneSnapshotCache; private final AzKeyFrameCallbackManager keyFrameCallbackManager; @@ -95,11 +93,12 @@ public AzAnimationController(AzAnimator animator, String name, int transition this.animator = animator; this.name = name; this.transitionLength = transitionTickTime; - this.animationQueue = new AzAnimationQueue<>(); + this.animationQueue = new AzAnimationQueue(); + this.boneAnimationQueueCache = new AzBoneAnimationQueueCache(animator.context().boneCache()); this.boneSnapshotCache = new AzBoneSnapshotCache(); this.keyFrameCallbacks = AzKeyFrameCallbacks.noop(); this.keyFrameCallbackManager = new AzKeyFrameCallbackManager<>(this); - this.keyFrameProcessor = new AzKeyFrameProcessor<>(this); + this.keyFrameProcessor = new AzKeyFrameProcessor<>(this, boneAnimationQueueCache); } public AzAnimationController setKeyFrameCallbacks(@NotNull AzKeyFrameCallbacks keyFrameCallbacks) { @@ -191,8 +190,8 @@ public AzQueuedAnimation getCurrentAnimation() { /** * Gets the currently loaded animation's {@link BoneAnimationQueue BoneAnimationQueues}. */ - public Map getBoneAnimationQueues() { - return boneAnimationQueues; + public Collection getBoneAnimationQueues() { + return boneAnimationQueueCache.values(); } /** @@ -394,7 +393,7 @@ protected PlayState handleAnimationState(T animatable) { public void update(AzAnimationContext context) { var animatable = context.animatable(); var boneCache = context.boneCache(); - var bones = boneCache.getBonesByName(); + var bones = boneCache.getBakedModel().getBonesByName(); var snapshots = boneCache.getBoneSnapshotsByName(); var crashWhenCantFindBone = context.config().crashIfBoneMissing(); var timer = context.timer(); @@ -419,8 +418,6 @@ public void update(AzAnimationContext context) { return; } - createInitialQueues(bones.values()); - if (justStartedTransition && (shouldResetTick || justStopped)) { this.justStopped = false; adjustedTick = adjustTick(animatable, seekTime); @@ -439,13 +436,7 @@ public void update(AzAnimationContext context) { } if (getAnimationState() == AzAnimationControllerState.RUNNING) { - keyFrameProcessor.runCurrentAnimation( - boneAnimationQueues, - animatable, - adjustedTick, - seekTime, - crashWhenCantFindBone - ); + keyFrameProcessor.runCurrentAnimation(animatable, adjustedTick, seekTime, crashWhenCantFindBone); var canTransition = transitionLength == 0 && shouldResetTick; if (canTransition && animationState == AzAnimationControllerState.TRANSITIONING) { @@ -466,30 +457,11 @@ public void update(AzAnimationContext context) { } if (currentAnimation != null) { - keyFrameProcessor.transitionFromCurrentAnimation( - boneAnimationQueues, - bones, - crashWhenCantFindBone, - adjustedTick - ); + keyFrameProcessor.transitionFromCurrentAnimation(bones, crashWhenCantFindBone, adjustedTick); } } } - /** - * Prepare the {@link BoneAnimationQueue} map for the current render frame - * - * @param modelRendererList The bone list from the {@link AzAnimationProcessor} - */ - protected void createInitialQueues(Collection modelRendererList) { - boneAnimationQueues.clear(); - - for (var modelRenderer : modelRendererList) { - // TODO: Optimize. - boneAnimationQueues.put(modelRenderer.getName(), new AzBoneAnimationQueue(modelRenderer)); - } - } - /** * Adjust a tick value depending on the controller's current state and speed modifier.
      * Is used when starting a new animation, transitioning, and a few other key areas @@ -527,6 +499,10 @@ public AzAnimationQueue getAnimationQueue() { return animationQueue; } + public AzBoneAnimationQueueCache getBoneAnimationQueueCache() { + return boneAnimationQueueCache; + } + public AzBoneSnapshotCache getBoneSnapshotCache() { return boneSnapshotCache; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java index 20cd88b68..24b8af924 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java @@ -2,8 +2,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.LinkedList; @@ -11,9 +9,7 @@ import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; -public class AzAnimationQueue { - - private static final Logger LOGGER = LoggerFactory.getLogger(AzAnimationQueue.class); +public class AzAnimationQueue { private final Queue animationQueue; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java new file mode 100644 index 000000000..160219af9 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.core2.animation.controller; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mod.azure.azurelib.core2.animation.cache.AzBoneCache; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Map; + +public class AzBoneAnimationQueueCache { + + private final Map boneAnimationQueues; + + private final AzBoneCache boneCache; + + public AzBoneAnimationQueueCache(AzBoneCache boneCache) { + this.boneAnimationQueues = new Object2ObjectOpenHashMap<>(); + this.boneCache = boneCache; + } + + public Collection values() { + return boneAnimationQueues.values(); + } + + public @Nullable AzBoneAnimationQueue getOrNull(String boneName) { + var bone = boneCache.getBakedModel().getBoneOrNull(boneName); + + if (bone == null) { + return null; + } + + return boneAnimationQueues.computeIfAbsent(boneName, $ -> new AzBoneAnimationQueue(bone)); + } + + public void clear() { + boneAnimationQueues.clear(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java index ba7447756..168045a84 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java @@ -14,27 +14,29 @@ import mod.azure.azurelib.core.object.Axis; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerState; +import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; import mod.azure.azurelib.core2.model.AzBone; public class AzKeyFrameProcessor { private final AzAnimationController animationController; - public AzKeyFrameProcessor(AzAnimationController animationController) { + private final AzBoneAnimationQueueCache boneAnimationQueueCache; + + public AzKeyFrameProcessor(AzAnimationController animationController, AzBoneAnimationQueueCache boneAnimationQueueCache) { this.animationController = animationController; + this.boneAnimationQueueCache = boneAnimationQueueCache; } /** * Handle the current animation's state modifications and translations * - * @param boneAnimationQueues * @param adjustedTick The controller-adjusted tick for animation purposes * @param seekTime The lerped tick (current tick + partial tick) * @param crashWhenCantFindBone Whether the controller should throw an exception when unable to find the required * bone, or continue with the remaining bones */ public void runCurrentAnimation( - Map boneAnimationQueues, T animatable, double adjustedTick, double seekTime, @@ -79,7 +81,7 @@ public void runCurrentAnimation( MolangParser.INSTANCE.setMemoizedValue(MolangQueries.ANIM_TIME, () -> finalAdjustedTick / 20d); for (var boneAnimation : currentAnimation.animation().boneAnimations()) { - var boneAnimationQueue = boneAnimationQueues.get(boneAnimation.boneName()); + var boneAnimationQueue = boneAnimationQueueCache.getOrNull(boneAnimation.boneName()); if (boneAnimationQueue == null) { if (crashWhenCantFindBone) @@ -123,7 +125,6 @@ public void runCurrentAnimation( } public void transitionFromCurrentAnimation( - Map boneAnimationQueues, Map bones, boolean crashWhenCantFindBone, double adjustedTick @@ -135,7 +136,7 @@ public void transitionFromCurrentAnimation( MolangParser.INSTANCE.setValue(MolangQueries.ANIM_TIME, () -> 0); for (var boneAnimation : currentAnimation.animation().boneAnimations()) { - var boneAnimationQueue = boneAnimationQueues.get(boneAnimation.boneName()); + var boneAnimationQueue = boneAnimationQueueCache.getOrNull(boneAnimation.boneName()); var boneSnapshot = boneSnapshotCache.getOrNull(boneAnimation.boneName()); var bone = bones.get(boneAnimation.boneName()); diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java index 33c9c4c91..b7af3ef3f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java @@ -1,5 +1,7 @@ package mod.azure.azurelib.core2.model; +import org.jetbrains.annotations.Nullable; + import java.util.ArrayDeque; import java.util.Collections; import java.util.HashMap; @@ -34,8 +36,12 @@ private Map mapBonesByName(List bones) { return bonesByName; } - public Optional getBoneByName(String name) { - return Optional.ofNullable(bonesByName.get(name)); + public @Nullable AzBone getBoneOrNull(String name) { + return bonesByName.get(name); + } + + public Optional getBone(String name) { + return Optional.ofNullable(getBoneOrNull(name)); } public Map getBonesByName() { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 7f44cb220..28839bb51 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -65,7 +65,7 @@ public void render( var azBakedModel = provideBakedModel(entity); if (cachedEntityAnimator != null && azBakedModel != null) { - cachedEntityAnimator.context().boneCache().setActiveModel(azBakedModel); + cachedEntityAnimator.setActiveModel(azBakedModel); } // Point the renderer's current animator reference to the cached entity animator before rendering. From 9bf3ff710edd2834f7d52d7066bcad9fa0b1c24a Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 10:38:34 -0500 Subject: [PATCH 065/224] Lint. Signed-off-by: = --- .../java/mod/azure/azurelib/core2/animation/AzAnimator.java | 2 +- .../animation/controller/AzBoneAnimationQueueCache.java | 5 +++-- .../animation/controller/keyframe/AzKeyFrameProcessor.java | 5 ++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index 0c2592b5f..4811f7573 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -1,6 +1,5 @@ package mod.azure.azurelib.core2.animation; -import mod.azure.azurelib.core2.model.AzBakedModel; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; @@ -14,6 +13,7 @@ import mod.azure.azurelib.core2.animation.cache.AzBoneCache; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; +import mod.azure.azurelib.core2.model.AzBakedModel; public abstract class AzAnimator { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java index 160219af9..b854aded6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java @@ -1,13 +1,14 @@ package mod.azure.azurelib.core2.animation.controller; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.core2.animation.cache.AzBoneCache; -import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Map; +import mod.azure.azurelib.core2.animation.cache.AzBoneCache; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; + public class AzBoneAnimationQueueCache { private final Map boneAnimationQueues; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java index 168045a84..0f2881b25 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java @@ -23,7 +23,10 @@ public class AzKeyFrameProcessor { private final AzBoneAnimationQueueCache boneAnimationQueueCache; - public AzKeyFrameProcessor(AzAnimationController animationController, AzBoneAnimationQueueCache boneAnimationQueueCache) { + public AzKeyFrameProcessor( + AzAnimationController animationController, + AzBoneAnimationQueueCache boneAnimationQueueCache + ) { this.animationController = animationController; this.boneAnimationQueueCache = boneAnimationQueueCache; } From 2326071b08cf230f92581e2ecd5f3497a21c8a32 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 10:44:23 -0500 Subject: [PATCH 066/224] Reveal the true form of animation point queues. Signed-off-by: = --- .../keyframe/AzBoneAnimationQueue.java | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java index e83b3c2c1..40bbfd7c9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java @@ -5,8 +5,10 @@ */ package mod.azure.azurelib.core2.animation.controller.keyframe; +import java.util.LinkedList; +import java.util.Queue; + import mod.azure.azurelib.core.keyframe.AnimationPoint; -import mod.azure.azurelib.core.keyframe.AnimationPointQueue; import mod.azure.azurelib.core.keyframe.Keyframe; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.model.AzBone; @@ -18,30 +20,30 @@ */ public record AzBoneAnimationQueue( AzBone bone, - AnimationPointQueue rotationXQueue, - AnimationPointQueue rotationYQueue, - AnimationPointQueue rotationZQueue, - AnimationPointQueue positionXQueue, - AnimationPointQueue positionYQueue, - AnimationPointQueue positionZQueue, - AnimationPointQueue scaleXQueue, - AnimationPointQueue scaleYQueue, - AnimationPointQueue scaleZQueue + Queue rotationXQueue, + Queue rotationYQueue, + Queue rotationZQueue, + Queue positionXQueue, + Queue positionYQueue, + Queue positionZQueue, + Queue scaleXQueue, + Queue scaleYQueue, + Queue scaleZQueue ) { public AzBoneAnimationQueue(AzBone bone) { // TODO: Optimize this( bone, - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue() + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>() ); } From 98a181bfdd79e62c9d33d8cb8cb1bcbc21242d9b Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 14 Dec 2024 10:47:17 -0500 Subject: [PATCH 067/224] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index b683d3d1b..bf2502dce 100644 --- a/gradle.properties +++ b/gradle.properties @@ -51,5 +51,5 @@ mod_logo = azurelib.png mod_name = AzureLib mod_sources = https://github.com/AzureDoom/AzureLib mod_url = https://modrinth.com/mod/azurelib -version = 3.0.0-alpha7 +version = 3.0.0-alpha8 modrinth_id = 7zlUOZvb From 76d2182a63079283a22a5103d354fed2319b14db Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 12:10:39 -0500 Subject: [PATCH 068/224] Implemented AzKeyframeStack.java, AzKeyframe.java, AzKeyframeLocation.java, AzAnimationPoint.java and AzEasingType.java. Signed-off-by: = --- .../core2/animation/AzBoneAnimation.java | 25 ++ .../core2/animation/AzEasingType.java | 400 ++++++++++++++++++ .../azurelib/core2/animation/AzKeyframe.java | 55 +++ .../core2/animation/AzKeyframeLocation.java | 19 + .../core2/animation/AzKeyframeStack.java | 50 +++ .../controller/keyframe/AzAnimationPoint.java | 91 ++++ 6 files changed, 640 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimation.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframe.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeLocation.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeStack.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAnimationPoint.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimation.java new file mode 100644 index 000000000..924ac9ea3 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimation.java @@ -0,0 +1,25 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation; + +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.math.IValue; + +/** + * A record of a deserialized animation for a given bone.
      + * Responsible for holding the various {@link Keyframe Keyframes} for the bone's animation transformations + * + * @param boneName The name of the bone as listed in the {@code animation.json} + * @param rotationKeyFrames The deserialized rotation {@code Keyframe} stack + * @param positionKeyFrames The deserialized position {@code Keyframe} stack + * @param scaleKeyFrames The deserialized scale {@code Keyframe} stack + */ +public record AzBoneAnimation( + String boneName, + AzKeyframeStack> rotationKeyFrames, + AzKeyframeStack> positionKeyFrames, + AzKeyframeStack> scaleKeyFrames +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java new file mode 100644 index 000000000..97635d14c --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java @@ -0,0 +1,400 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; + +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.utils.Interpolations; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzAnimationPoint; + +/** + * Functional interface defining an easing function.
      + * {@code value} is the easing value provided from the keyframe's {@link Keyframe#easingArgs()}
      + *
      + * For more information on easings, see:
      + *
      Easings.net
      + * Cubic-Bezier.com
      + */ +@FunctionalInterface +public interface AzEasingType { + + Map EASING_TYPES = new ConcurrentHashMap<>(64); + + AzEasingType LINEAR = register("linear", register("none", value -> easeIn(AzEasingType::linear))); + + AzEasingType STEP = register("step", value -> easeIn(step(value))); + + AzEasingType EASE_IN_SINE = register("easeinsine", value -> easeIn(AzEasingType::sine)); + + AzEasingType EASE_OUT_SINE = register("easeoutsine", value -> easeOut(AzEasingType::sine)); + + AzEasingType EASE_IN_OUT_SINE = register("easeinoutsine", value -> easeInOut(AzEasingType::sine)); + + AzEasingType EASE_IN_QUAD = register("easeinquad", value -> easeIn(AzEasingType::quadratic)); + + AzEasingType EASE_OUT_QUAD = register("easeoutquad", value -> easeOut(AzEasingType::quadratic)); + + AzEasingType EASE_IN_OUT_QUAD = register("easeinoutquad", value -> easeInOut(AzEasingType::quadratic)); + + AzEasingType EASE_IN_CUBIC = register("easeincubic", value -> easeIn(AzEasingType::cubic)); + + AzEasingType EASE_OUT_CUBIC = register("easeoutcubic", value -> easeOut(AzEasingType::cubic)); + + AzEasingType EASE_IN_OUT_CUBIC = register("easeinoutcubic", value -> easeInOut(AzEasingType::cubic)); + + AzEasingType EASE_IN_QUART = register("easeinquart", value -> easeIn(pow(4))); + + AzEasingType EASE_OUT_QUART = register("easeoutquart", value -> easeOut(pow(4))); + + AzEasingType EASE_IN_OUT_QUART = register("easeinoutquart", value -> easeInOut(pow(4))); + + AzEasingType EASE_IN_QUINT = register("easeinquint", value -> easeIn(pow(4))); + + AzEasingType EASE_OUT_QUINT = register("easeoutquint", value -> easeOut(pow(5))); + + AzEasingType EASE_IN_OUT_QUINT = register("easeinoutquint", value -> easeInOut(pow(5))); + + AzEasingType EASE_IN_EXPO = register("easeinexpo", value -> easeIn(AzEasingType::exp)); + + AzEasingType EASE_OUT_EXPO = register("easeoutexpo", value -> easeOut(AzEasingType::exp)); + + AzEasingType EASE_IN_OUT_EXPO = register("easeinoutexpo", value -> easeInOut(AzEasingType::exp)); + + AzEasingType EASE_IN_CIRC = register("easeincirc", value -> easeIn(AzEasingType::circle)); + + AzEasingType EASE_OUT_CIRC = register("easeoutcirc", value -> easeOut(AzEasingType::circle)); + + AzEasingType EASE_IN_OUT_CIRC = register("easeinoutcirc", value -> easeInOut(AzEasingType::circle)); + + AzEasingType EASE_IN_BACK = register("easeinback", value -> easeIn(back(value))); + + AzEasingType EASE_OUT_BACK = register("easeoutback", value -> easeOut(back(value))); + + AzEasingType EASE_IN_OUT_BACK = register("easeinoutback", value -> easeInOut(back(value))); + + AzEasingType EASE_IN_ELASTIC = register("easeinelastic", value -> easeIn(elastic(value))); + + AzEasingType EASE_OUT_ELASTIC = register("easeoutelastic", value -> easeOut(elastic(value))); + + AzEasingType EASE_IN_OUT_ELASTIC = register("easeinoutelastic", value -> easeInOut(elastic(value))); + + AzEasingType EASE_IN_BOUNCE = register("easeinbounce", value -> easeIn(bounce(value))); + + AzEasingType EASE_OUT_BOUNCE = register("easeoutbounce", value -> easeOut(bounce(value))); + + AzEasingType EASE_IN_OUT_BOUNCE = register("easeinoutbounce", value -> easeInOut(bounce(value))); + + AzEasingType CATMULLROM = register("catmullrom", value -> easeInOut(AzEasingType::catmullRom)); + + static double lerpWithOverride(AzAnimationPoint animationPoint, AzEasingType override) { + AzEasingType easingType = override; + + if (override == null) + easingType = animationPoint.keyFrame() == null ? LINEAR : animationPoint.keyFrame().easingType(); + + return easingType.apply(animationPoint); + } + + /** + * Register an {@code EasingType} with AzureLib for handling animation transitions and value curves.
      + * MUST be called during mod construct
      + * It is recommended you don't call this directly, and instead call it via {@code AzureLibUtil#addCustomEasingType} + * + * @param name The name of the easing type + * @param easingType The {@code EasingType} to associate with the given name + * @return The {@code EasingType} you registered + */ + static AzEasingType register(String name, AzEasingType easingType) { + EASING_TYPES.putIfAbsent(name, easingType); + + return easingType; + } + + /** + * Retrieve an {@code EasingType} instance based on a {@link JsonElement}. Returns one of the default + * {@code EasingTypes} if the name matches, or any other registered {@code EasingType} with a matching name. + * + * @param json The {@code easing} {@link JsonElement} to attempt to parse. + * @return A usable {@code EasingType} instance + */ + static AzEasingType fromJson(JsonElement json) { + if (!(json instanceof JsonPrimitive primitive) || !primitive.isString()) + return LINEAR; + + return fromString(primitive.getAsString().toLowerCase(Locale.ROOT)); + } + + /** + * Get an existing {@code EasingType} from a given string, matching the string to its name. + * + * @param name The name of the easing function + * @return The relevant {@code EasingType}, or {@link AzEasingType#LINEAR} if none match + */ + static AzEasingType fromString(String name) { + return EASING_TYPES.getOrDefault(name, AzEasingType.LINEAR); + } + + /** + * Returns an easing function running linearly. Functionally equivalent to no easing + */ + static Double2DoubleFunction linear(Double2DoubleFunction function) { + return function; + } + + /** + * Performs a Catmull-Rom interpolation, used to get smooth interpolated motion between keyframes.
      + * CatmullRom#position + */ + static double catmullRom(double n) { + return (0.5f * (2.0f * (n + 1) + ((n + 2) - n) * 1 + + (2.0f * n - 5.0f * (n + 1) + 4.0f * (n + 2) - (n + 3)) * 1 + + (3.0f * (n + 1) - n - 3.0f * (n + 2) + (n + 3)) * 1)); + } + + /** + * Returns an easing function running forward in time + */ + static Double2DoubleFunction easeIn(Double2DoubleFunction function) { + return function; + } + + // ---> Easing Transition Type Functions <--- // + + /** + * Returns an easing function running backwards in time + */ + static Double2DoubleFunction easeOut(Double2DoubleFunction function) { + return time -> 1 - function.apply(1 - time); + } + + /** + * Returns an easing function that runs equally both forwards and backwards in time based on the halfway point, + * generating a symmetrical curve.
      + */ + static Double2DoubleFunction easeInOut(Double2DoubleFunction function) { + return time -> { + if (time < 0.5d) + return function.apply(time * 2d) / 2d; + + return 1 - function.apply((1 - time) * 2d) / 2d; + }; + } + + /** + * Returns a stepping function that returns 1 for any input value greater than 0, or otherwise returning 0 + */ + static Double2DoubleFunction stepPositive(Double2DoubleFunction function) { + return n -> n > 0 ? 1 : 0; + } + + /** + * Returns a stepping function that returns 1 for any input value greater than or equal to 0, or otherwise returning + * 0 + */ + static Double2DoubleFunction stepNonNegative(Double2DoubleFunction function) { + return n -> n >= 0 ? 1 : 0; + } + + /** + * A linear function, equivalent to a null-operation.
      + * {@code f(n) = n} + */ + static double linear(double n) { + return n; + } + + // ---> Stepping Functions <--- // + + /** + * A quadratic function, equivalent to the square (n^2) of elapsed time.
      + * {@code f(n) = n^2}
      + * Easings.net#easeInQuad + */ + static double quadratic(double n) { + return n * n; + } + + /** + * A cubic function, equivalent to cube (n^3) of elapsed time.
      + * {@code f(n) = n^3}
      + * Easings.net#easeInCubic + */ + static double cubic(double n) { + return n * n * n; + } + + // ---> Mathematical Functions <--- // + + /** + * A sinusoidal function, equivalent to a sine curve output.
      + * {@code f(n) = 1 - cos(n * π / 2)}
      + * Easings.net#easeInSine + */ + static double sine(double n) { + return 1 - Math.cos(n * Math.PI / 2f); + } + + /** + * A circular function, equivalent to a normally symmetrical curve.
      + * {@code f(n) = 1 - sqrt(1 - n^2)}
      + * Easings.net#easeInCirc + */ + static double circle(double n) { + return 1 - Math.sqrt(1 - n * n); + } + + /** + * An exponential function, equivalent to an exponential curve.
      + * {@code f(n) = 2^(10 * (n - 1))}
      + * Easings.net#easeInExpo + */ + static double exp(double n) { + return Math.pow(2, 10 * (n - 1)); + } + + /** + * An elastic function, equivalent to an oscillating curve.
      + * n defines the elasticity of the output.
      + * {@code f(t) = 1 - (cos(t * π) / 2))^3 * cos(t * n * π)}
      + * Easings.net#easeInElastic + */ + static Double2DoubleFunction elastic(Double n) { + double n2 = n == null ? 1 : n; + + return t -> 1 - Math.pow(Math.cos(t * Math.PI / 2f), 3) * Math.cos(t * n2 * Math.PI); + } + + /** + * A bouncing function, equivalent to a bouncing ball curve.
      + * n defines the bounciness of the output.
      + * Thanks to Waterded#6455 for making the bounce adjustable, and GiantLuigi4#6616 for additional + * cleanup.
      + * Easings.net#easeInBounce + */ + static Double2DoubleFunction bounce(Double n) { + final double n2 = n == null ? 0.5d : n; + + Double2DoubleFunction one = x -> 121f / 16f * x * x; + Double2DoubleFunction two = x -> 121f / 4f * n2 * Math.pow(x - 6f / 11f, 2) + 1 - n2; + Double2DoubleFunction three = x -> 121 * n2 * n2 * Math.pow(x - 9f / 11f, 2) + 1 - n2 * n2; + Double2DoubleFunction four = x -> 484 * n2 * n2 * n2 * Math.pow(x - 10.5f / 11f, 2) + 1 - n2 * n2 * n2; + + return t -> Math.min(Math.min(one.apply(t), two.apply(t)), Math.min(three.apply(t), four.apply(t))); + } + + /** + * A negative elastic function, equivalent to inverting briefly before increasing.
      + * f(t) = t^2 * ((n * 1.70158 + 1) * t - n * 1.70158)
      + * Easings.net#easeInBack + */ + static Double2DoubleFunction back(Double n) { + final double n2 = n == null ? 1.70158d : n * 1.70158d; + + return t -> t * t * ((n2 + 1) * t - n2); + } + + // ---> Easing Curve Functions <--- // + + /** + * An exponential function, equivalent to an exponential curve to the {@code n} root.
      + * f(t) = t^n + * + * @param n The exponent + */ + static Double2DoubleFunction pow(double n) { + return t -> Math.pow(t, n); + } + + /** + * The MIT License (MIT)
      + *
      + * Copyright (c) 2015 Boris Chumichev
      + *
      + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and + * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
      + *
      + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software.
      + *
      + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE.
      + *
      + * Returns a stepped value based on the nearest step to the input value.
      + * The size (grade) of the steps depends on the provided value of {@code n} + **/ + static Double2DoubleFunction step(Double n) { + double n2 = n == null ? 2 : n; + + if (n2 < 2) + throw new IllegalArgumentException("Steps must be >= 2, got: " + n2); + + final int steps = (int) n2; + + return t -> { + double result = 0; + + if (t < 0) + return result; + + double stepLength = (1 / (double) steps); + + if (t > (result = (steps - 1) * stepLength)) + return result; + + int testIndex; + int leftBorderIndex = 0; + int rightBorderIndex = steps - 1; + + while (rightBorderIndex - leftBorderIndex != 1) { + testIndex = leftBorderIndex + (rightBorderIndex - leftBorderIndex) / 2; + + if (t >= testIndex * stepLength) { + leftBorderIndex = testIndex; + } else { + rightBorderIndex = testIndex; + } + } + + return leftBorderIndex * stepLength; + }; + } + + Double2DoubleFunction buildTransformer(Double value); + + default double apply(AzAnimationPoint animationPoint) { + Double easingVariable = null; + + if (animationPoint.keyFrame() != null && animationPoint.keyFrame().easingArgs().size() > 0) + easingVariable = animationPoint.keyFrame().easingArgs().get(0).get(); + + return apply(animationPoint, easingVariable, animationPoint.currentTick() / animationPoint.transitionLength()); + } + + // The MIT license notice below applies to the function step + + default double apply(AzAnimationPoint animationPoint, Double easingValue, double lerpValue) { + if (animationPoint.currentTick() >= animationPoint.transitionLength()) + return (float) animationPoint.animationEndValue(); + + return Interpolations.lerp( + animationPoint.animationStartValue(), + animationPoint.animationEndValue(), + buildTransformer(easingValue).apply(lerpValue) + ); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframe.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframe.java new file mode 100644 index 000000000..641cae500 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframe.java @@ -0,0 +1,55 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +import java.util.List; +import java.util.Objects; + +import mod.azure.azurelib.core.math.IValue; + +/** + * Animation keyframe data + * + * @param length The length (in ticks) the keyframe lasts for + * @param startValue The value to start the keyframe's transformation with + * @param endValue The value to end the keyframe's transformation with + * @param easingType The {@code EasingType} to use for transformations + * @param easingArgs The arguments to provide to the easing calculation + */ +public record AzKeyframe( + double length, + T startValue, + T endValue, + AzEasingType easingType, + List easingArgs +) { + + public AzKeyframe(double length, T startValue, T endValue) { + this(length, startValue, endValue, AzEasingType.LINEAR); + } + + public AzKeyframe(double length, T startValue, T endValue, AzEasingType easingType) { + this(length, startValue, endValue, easingType, new ObjectArrayList<>(0)); + } + + @Override + public int hashCode() { + return Objects.hash(this.length, this.startValue, this.endValue, this.easingType, this.easingArgs); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + + if (obj == null || getClass() != obj.getClass()) + return false; + + return hashCode() == obj.hashCode(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeLocation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeLocation.java new file mode 100644 index 000000000..24dcd966b --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeLocation.java @@ -0,0 +1,19 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation; + +import mod.azure.azurelib.core.keyframe.Keyframe; + +/** + * A named pair object that stores a {@link Keyframe} and a double representing a temporally placed {@code Keyframe} + * + * @param keyframe The {@code Keyframe} at the tick time + * @param startTick The animation tick time at the start of this {@code Keyframe} + */ +public record AzKeyframeLocation>( + T keyframe, + double startTick +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeStack.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeStack.java new file mode 100644 index 000000000..b2c195205 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeStack.java @@ -0,0 +1,50 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +import java.util.List; + +import mod.azure.azurelib.core.keyframe.Keyframe; + +/** + * Stores a triplet of {@link Keyframe Keyframes} in an ordered stack + */ +public record AzKeyframeStack>( + List xKeyframes, + List yKeyframes, + List zKeyframes +) { + + public AzKeyframeStack() { + this(new ObjectArrayList<>(), new ObjectArrayList<>(), new ObjectArrayList<>()); + } + + public static > AzKeyframeStack from(AzKeyframeStack otherStack) { + return new AzKeyframeStack<>(otherStack.xKeyframes, otherStack.yKeyframes, otherStack.zKeyframes); + } + + public double getLastKeyframeTime() { + double xTime = 0; + double yTime = 0; + double zTime = 0; + + for (T frame : xKeyframes()) { + xTime += frame.length(); + } + + for (T frame : yKeyframes()) { + yTime += frame.length(); + } + + for (T frame : zKeyframes()) { + zTime += frame.length(); + } + + return Math.max(xTime, Math.max(yTime, zTime)); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAnimationPoint.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAnimationPoint.java new file mode 100644 index 000000000..ab65010a1 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAnimationPoint.java @@ -0,0 +1,91 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import mod.azure.azurelib.core2.animation.AzKeyframe; + +/** + * Animation state record that holds the state of an animation at a given point + */ +public class AzAnimationPoint { + + public static AzAnimationPoint create() { + return new AzAnimationPoint(null, 0, 0, 0, 0); + } + + private AzKeyframe keyFrame; + + private double currentTick; + + private double transitionLength; + + private double animationStartValue; + + private double animationEndValue; + + /** + * @param currentTick The lerped tick time (current tick + partial tick) of the point + * @param transitionLength The length of time (in ticks) that the point should take to transition + * @param animationStartValue The start value to provide to the animation handling system + * @param animationEndValue The end value to provide to the animation handling system + * @param keyFrame The {@code Nullable} Keyframe + */ + public AzAnimationPoint( + AzKeyframe keyFrame, + double currentTick, + double transitionLength, + double animationStartValue, + double animationEndValue + ) { + set(keyFrame, currentTick, transitionLength, animationStartValue, animationEndValue); + } + + public boolean isEmpty() { + return keyFrame == null; + } + + public void set( + AzKeyframe keyFrame, + double currentTick, + double transitionLength, + double animationStartValue, + double animationEndValue + ) { + this.keyFrame = keyFrame; + this.currentTick = currentTick; + this.transitionLength = transitionLength; + this.animationStartValue = animationStartValue; + this.animationEndValue = animationEndValue; + } + + public double animationEndValue() { + return animationEndValue; + } + + public double animationStartValue() { + return animationStartValue; + } + + public double currentTick() { + return currentTick; + } + + public AzKeyframe keyFrame() { + return keyFrame; + } + + public double transitionLength() { + return transitionLength; + } + + @Override + public String toString() { + return "Tick: " + this.currentTick + + " | Transition Length: " + this.transitionLength + + " | Start Value: " + this.animationStartValue + + " | End Value: " + this.animationEndValue; + } +} From f5c1786bf129b9ad58010e166291fe16d571c547 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 12:18:19 -0500 Subject: [PATCH 069/224] perf: Cache animation points instead of creating them every frame. Signed-off-by: = --- .../core2/animation/AzAnimationProcessor.java | 3 +- .../animation/AzBoneAnimationUpdateUtil.java | 49 ++-- .../core2/animation/AzEasingType.java | 7 +- .../controller/AzAnimationController.java | 14 +- .../keyframe/AzBoneAnimationQueue.java | 234 +++++++++++------- .../keyframe/AzKeyFrameProcessor.java | 100 +++++--- .../parse/AzBakedAnimationsAdapter.java | 145 +++++------ .../animation/primitive/AzAnimation.java | 6 +- 8 files changed, 318 insertions(+), 240 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index 6a07115d4..c2eaee796 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -2,7 +2,6 @@ import java.util.Map; -import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.model.AzBoneSnapshot; @@ -51,7 +50,7 @@ public void update(AzAnimationContext context) { private void updateBoneSnapshots( AzAnimationController controller, Map boneSnapshots, - EasingType easingType + AzEasingType easingType ) { // Progresses the current bones according to the animation queue. for (var boneAnimation : controller.getBoneAnimationQueues()) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java index bc6fcea94..58e5ba674 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java @@ -1,6 +1,5 @@ package mod.azure.azurelib.core2.animation; -import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.model.AzBoneSnapshot; @@ -10,17 +9,17 @@ public class AzBoneAnimationUpdateUtil { public static void updatePositions( AzBoneAnimationQueue boneAnimation, AzBone bone, - EasingType easingType, + AzEasingType easingType, AzBoneSnapshot snapshot ) { - var posXPoint = boneAnimation.positionXQueue().poll(); - var posYPoint = boneAnimation.positionYQueue().poll(); - var posZPoint = boneAnimation.positionZQueue().poll(); + var posXPoint = boneAnimation.positionXQueue(); + var posYPoint = boneAnimation.positionYQueue(); + var posZPoint = boneAnimation.positionZQueue(); - if (posXPoint != null && posYPoint != null && posZPoint != null) { - bone.setPosX((float) EasingType.lerpWithOverride(posXPoint, easingType)); - bone.setPosY((float) EasingType.lerpWithOverride(posYPoint, easingType)); - bone.setPosZ((float) EasingType.lerpWithOverride(posZPoint, easingType)); + if (!posXPoint.isEmpty() && !posYPoint.isEmpty() && !posZPoint.isEmpty()) { + bone.setPosX((float) AzEasingType.lerpWithOverride(posXPoint, easingType)); + bone.setPosY((float) AzEasingType.lerpWithOverride(posYPoint, easingType)); + bone.setPosZ((float) AzEasingType.lerpWithOverride(posZPoint, easingType)); snapshot.updateOffset(bone.getPosX(), bone.getPosY(), bone.getPosZ()); snapshot.startPosAnim(); bone.markPositionAsChanged(); @@ -30,23 +29,23 @@ public static void updatePositions( public static void updateRotations( AzBoneAnimationQueue boneAnimation, AzBone bone, - EasingType easingType, + AzEasingType easingType, AzBoneSnapshot initialSnapshot, AzBoneSnapshot snapshot ) { - var rotXPoint = boneAnimation.rotationXQueue().poll(); - var rotYPoint = boneAnimation.rotationYQueue().poll(); - var rotZPoint = boneAnimation.rotationZQueue().poll(); + var rotXPoint = boneAnimation.rotationXQueue(); + var rotYPoint = boneAnimation.rotationYQueue(); + var rotZPoint = boneAnimation.rotationZQueue(); - if (rotXPoint != null && rotYPoint != null && rotZPoint != null) { + if (!rotXPoint.isEmpty() && !rotYPoint.isEmpty() && !rotZPoint.isEmpty()) { bone.setRotX( - (float) EasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() + (float) AzEasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() ); bone.setRotY( - (float) EasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() + (float) AzEasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() ); bone.setRotZ( - (float) EasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() + (float) AzEasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() ); snapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); snapshot.startRotAnim(); @@ -57,17 +56,17 @@ public static void updateRotations( public static void updateScale( AzBoneAnimationQueue boneAnimation, AzBone bone, - EasingType easingType, + AzEasingType easingType, AzBoneSnapshot snapshot ) { - var scaleXPoint = boneAnimation.scaleXQueue().poll(); - var scaleYPoint = boneAnimation.scaleYQueue().poll(); - var scaleZPoint = boneAnimation.scaleZQueue().poll(); + var scaleXPoint = boneAnimation.scaleXQueue(); + var scaleYPoint = boneAnimation.scaleYQueue(); + var scaleZPoint = boneAnimation.scaleZQueue(); - if (scaleXPoint != null && scaleYPoint != null && scaleZPoint != null) { - bone.setScaleX((float) EasingType.lerpWithOverride(scaleXPoint, easingType)); - bone.setScaleY((float) EasingType.lerpWithOverride(scaleYPoint, easingType)); - bone.setScaleZ((float) EasingType.lerpWithOverride(scaleZPoint, easingType)); + if (!scaleXPoint.isEmpty() && !scaleYPoint.isEmpty() && !scaleZPoint.isEmpty()) { + bone.setScaleX((float) AzEasingType.lerpWithOverride(scaleXPoint, easingType)); + bone.setScaleY((float) AzEasingType.lerpWithOverride(scaleYPoint, easingType)); + bone.setScaleZ((float) AzEasingType.lerpWithOverride(scaleZPoint, easingType)); snapshot.updateScale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); snapshot.startScaleAnim(); bone.markScaleAsChanged(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java index 97635d14c..0414f882d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java @@ -99,8 +99,11 @@ public interface AzEasingType { static double lerpWithOverride(AzAnimationPoint animationPoint, AzEasingType override) { AzEasingType easingType = override; - if (override == null) - easingType = animationPoint.keyFrame() == null ? LINEAR : animationPoint.keyFrame().easingType(); + if (override == null) { + easingType = animationPoint.keyFrame() == null + ? LINEAR + : animationPoint.keyFrame().easingType(); + } return easingType.apply(animationPoint); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index ea1ff6a3e..0732432ed 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -13,11 +13,11 @@ import java.util.function.Function; import java.util.function.ToDoubleFunction; -import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.core2.animation.AzAnimationContext; import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzEasingType; import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; @@ -76,7 +76,7 @@ public class AzAnimationController { protected ToDoubleFunction animationSpeedModifier = obj -> 1d; - protected Function overrideEasingTypeFunction = obj -> null; + protected Function overrideEasingTypeFunction = obj -> null; protected boolean justStopped = true; @@ -127,28 +127,28 @@ public void setJustStarting(boolean justStarting) { } /** - * Sets the controller's {@link EasingType} override for animations.
      + * Sets the controller's {@link AzEasingType} override for animations.
      * By default, the controller will use whatever {@code EasingType} was defined in the animation json * * @param easingTypeFunction The new {@code EasingType} to use * @return this */ - public AzAnimationController setOverrideEasingType(EasingType easingTypeFunction) { + public AzAnimationController setOverrideEasingType(AzEasingType easingTypeFunction) { return setOverrideEasingTypeFunction(obj -> easingTypeFunction); } - public Function getOverrideEasingTypeFunction() { + public Function getOverrideEasingTypeFunction() { return overrideEasingTypeFunction; } /** - * Sets the controller's {@link EasingType} override function for animations.
      + * Sets the controller's {@link AzEasingType} override function for animations.
      * By default, the controller will use whatever {@code EasingType} was defined in the animation json * * @param easingType The new {@code EasingType} to use * @return this */ - public AzAnimationController setOverrideEasingTypeFunction(Function easingType) { + public AzAnimationController setOverrideEasingTypeFunction(Function easingType) { this.overrideEasingTypeFunction = easingType; return this; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java index 40bbfd7c9..c558b5ddf 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java @@ -5,11 +5,7 @@ */ package mod.azure.azurelib.core2.animation.controller.keyframe; -import java.util.LinkedList; -import java.util.Queue; - -import mod.azure.azurelib.core.keyframe.AnimationPoint; -import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core2.animation.AzKeyframe; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.model.AzBoneSnapshot; @@ -18,37 +14,43 @@ * A bone pseudo-stack for bone animation positions, scales, and rotations. Animation points are calculated then pushed * onto their respective queues to be used for transformations in rendering */ -public record AzBoneAnimationQueue( - AzBone bone, - Queue rotationXQueue, - Queue rotationYQueue, - Queue rotationZQueue, - Queue positionXQueue, - Queue positionYQueue, - Queue positionZQueue, - Queue scaleXQueue, - Queue scaleYQueue, - Queue scaleZQueue -) { +public class AzBoneAnimationQueue { + + private AzBone bone; + + private AzAnimationPoint rotationXQueue; + + private AzAnimationPoint rotationYQueue; + + private AzAnimationPoint rotationZQueue; + + private AzAnimationPoint positionXQueue; + + private AzAnimationPoint positionYQueue; + + private AzAnimationPoint positionZQueue; + + private AzAnimationPoint scaleXQueue; + + private AzAnimationPoint scaleYQueue; + + private AzAnimationPoint scaleZQueue; public AzBoneAnimationQueue(AzBone bone) { - // TODO: Optimize - this( - bone, - new LinkedList<>(), - new LinkedList<>(), - new LinkedList<>(), - new LinkedList<>(), - new LinkedList<>(), - new LinkedList<>(), - new LinkedList<>(), - new LinkedList<>(), - new LinkedList<>() - ); + this.bone = bone; + this.rotationXQueue = AzAnimationPoint.create(); + this.rotationYQueue = AzAnimationPoint.create(); + this.rotationZQueue = AzAnimationPoint.create(); + this.positionXQueue = AzAnimationPoint.create(); + this.positionYQueue = AzAnimationPoint.create(); + this.positionZQueue = AzAnimationPoint.create(); + this.scaleXQueue = AzAnimationPoint.create(); + this.scaleYQueue = AzAnimationPoint.create(); + this.scaleZQueue = AzAnimationPoint.create(); } /** - * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#positionXQueue} + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#positionXQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -57,17 +59,17 @@ public AzBoneAnimationQueue(AzBone bone) { * @param endValue The value of the point at the end of its transition */ public void addPosXPoint( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.positionXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + this.positionXQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); } /** - * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#positionYQueue} + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#positionYQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -76,17 +78,17 @@ public void addPosXPoint( * @param endValue The value of the point at the end of its transition */ public void addPosYPoint( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.positionYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + this.positionYQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); } /** - * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#positionZQueue} + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#positionZQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -95,17 +97,17 @@ public void addPosYPoint( * @param endValue The value of the point at the end of its transition */ public void addPosZPoint( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.positionZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + this.positionZQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); } /** - * Add a new X, Y, and Z position {@link AnimationPoint} to their respective queues + * Add a new X, Y, and Z position {@link AzAnimationPoint} to their respective queues * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -120,13 +122,13 @@ public void addPosZPoint( * new point */ public void addNextPosition( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, AzBoneSnapshot startSnapshot, - AnimationPoint nextXPoint, - AnimationPoint nextYPoint, - AnimationPoint nextZPoint + AzAnimationPoint nextXPoint, + AzAnimationPoint nextYPoint, + AzAnimationPoint nextZPoint ) { addPosXPoint( keyFrame, @@ -152,7 +154,7 @@ public void addNextPosition( } /** - * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#scaleXQueue} + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#scaleXQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -161,17 +163,17 @@ public void addNextPosition( * @param endValue The value of the point at the end of its transition */ public void addScaleXPoint( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.scaleXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + this.scaleXQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); } /** - * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#scaleYQueue} + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#scaleYQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -180,17 +182,17 @@ public void addScaleXPoint( * @param endValue The value of the point at the end of its transition */ public void addScaleYPoint( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.scaleYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + this.scaleYQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); } /** - * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#scaleZQueue} + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#scaleZQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -199,17 +201,17 @@ public void addScaleYPoint( * @param endValue The value of the point at the end of its transition */ public void addScaleZPoint( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.scaleZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + this.scaleZQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); } /** - * Add a new X, Y, and Z scale {@link AnimationPoint} to their respective queues + * Add a new X, Y, and Z scale {@link AzAnimationPoint} to their respective queues * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -224,13 +226,13 @@ public void addScaleZPoint( * new point */ public void addNextScale( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, AzBoneSnapshot startSnapshot, - AnimationPoint nextXPoint, - AnimationPoint nextYPoint, - AnimationPoint nextZPoint + AzAnimationPoint nextXPoint, + AzAnimationPoint nextYPoint, + AzAnimationPoint nextZPoint ) { addScaleXPoint( keyFrame, @@ -256,7 +258,7 @@ public void addNextScale( } /** - * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#rotationXQueue} + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#rotationXQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -265,17 +267,17 @@ public void addNextScale( * @param endValue The value of the point at the end of its transition */ public void addRotationXPoint( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.rotationXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + this.rotationXQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); } /** - * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#rotationYQueue} + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#rotationYQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -284,17 +286,17 @@ public void addRotationXPoint( * @param endValue The value of the point at the end of its transition */ public void addRotationYPoint( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.rotationYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + this.rotationYQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); } /** - * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#rotationZQueue} + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#rotationZQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -303,17 +305,17 @@ public void addRotationYPoint( * @param endValue The value of the point at the end of its transition */ public void addRotationZPoint( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.rotationZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); + this.rotationZQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); } /** - * Add a new X, Y, and Z scale {@link AnimationPoint} to their respective queues + * Add a new X, Y, and Z scale {@link AzAnimationPoint} to their respective queues * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -329,14 +331,14 @@ public void addRotationZPoint( * new point */ public void addNextRotation( - Keyframe keyFrame, + AzKeyframe keyFrame, double lerpedTick, double transitionLength, AzBoneSnapshot startSnapshot, AzBoneSnapshot initialSnapshot, - AnimationPoint nextXPoint, - AnimationPoint nextYPoint, - AnimationPoint nextZPoint + AzAnimationPoint nextXPoint, + AzAnimationPoint nextYPoint, + AzAnimationPoint nextZPoint ) { addRotationXPoint( keyFrame, @@ -362,41 +364,81 @@ public void addNextRotation( } /** - * Add an X, Y, and Z position {@link AnimationPoint} to their respective queues + * Add an X, Y, and Z position {@link AzAnimationPoint} to their respective queues * - * @param xPoint The x position {@code AnimationPoint} to add - * @param yPoint The y position {@code AnimationPoint} to add - * @param zPoint The z position {@code AnimationPoint} to add + * @param xPoint The x position {@code AzAnimationPoint} to add + * @param yPoint The y position {@code AzAnimationPoint} to add + * @param zPoint The z position {@code AzAnimationPoint} to add */ - public void addPositions(AnimationPoint xPoint, AnimationPoint yPoint, AnimationPoint zPoint) { - this.positionXQueue.add(xPoint); - this.positionYQueue.add(yPoint); - this.positionZQueue.add(zPoint); + public void addPositions(AzAnimationPoint xPoint, AzAnimationPoint yPoint, AzAnimationPoint zPoint) { + this.positionXQueue = xPoint; + this.positionYQueue = yPoint; + this.positionZQueue = zPoint; } /** - * Add an X, Y, and Z scale {@link AnimationPoint} to their respective queues + * Add an X, Y, and Z scale {@link AzAnimationPoint} to their respective queues * - * @param xPoint The x scale {@code AnimationPoint} to add - * @param yPoint The y scale {@code AnimationPoint} to add - * @param zPoint The z scale {@code AnimationPoint} to add + * @param xPoint The x scale {@code AzAnimationPoint} to add + * @param yPoint The y scale {@code AzAnimationPoint} to add + * @param zPoint The z scale {@code AzAnimationPoint} to add */ - public void addScales(AnimationPoint xPoint, AnimationPoint yPoint, AnimationPoint zPoint) { - this.scaleXQueue.add(xPoint); - this.scaleYQueue.add(yPoint); - this.scaleZQueue.add(zPoint); + public void addScales(AzAnimationPoint xPoint, AzAnimationPoint yPoint, AzAnimationPoint zPoint) { + this.scaleXQueue = xPoint; + this.scaleYQueue = yPoint; + this.scaleZQueue = zPoint; } /** - * Add an X, Y, and Z rotation {@link AnimationPoint} to their respective queues + * Add an X, Y, and Z rotation {@link AzAnimationPoint} to their respective queues * - * @param xPoint The x rotation {@code AnimationPoint} to add - * @param yPoint The y rotation {@code AnimationPoint} to add - * @param zPoint The z rotation {@code AnimationPoint} to add + * @param xPoint The x rotation {@code AzAnimationPoint} to add + * @param yPoint The y rotation {@code AzAnimationPoint} to add + * @param zPoint The z rotation {@code AzAnimationPoint} to add */ - public void addRotations(AnimationPoint xPoint, AnimationPoint yPoint, AnimationPoint zPoint) { - this.rotationXQueue.add(xPoint); - this.rotationYQueue.add(yPoint); - this.rotationZQueue.add(zPoint); + public void addRotations(AzAnimationPoint xPoint, AzAnimationPoint yPoint, AzAnimationPoint zPoint) { + this.rotationXQueue = xPoint; + this.rotationYQueue = yPoint; + this.rotationZQueue = zPoint; + } + + public AzBone bone() { + return bone; + } + + public AzAnimationPoint rotationXQueue() { + return rotationXQueue; + } + + public AzAnimationPoint rotationYQueue() { + return rotationYQueue; + } + + public AzAnimationPoint rotationZQueue() { + return rotationZQueue; + } + + public AzAnimationPoint positionXQueue() { + return positionXQueue; + } + + public AzAnimationPoint positionYQueue() { + return positionYQueue; + } + + public AzAnimationPoint positionZQueue() { + return positionZQueue; + } + + public AzAnimationPoint scaleXQueue() { + return scaleXQueue; + } + + public AzAnimationPoint scaleYQueue() { + return scaleYQueue; + } + + public AzAnimationPoint scaleZQueue() { + return scaleZQueue; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java index 0f2881b25..153f0a31a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java @@ -4,14 +4,14 @@ import java.util.Map; import java.util.NoSuchElementException; -import mod.azure.azurelib.core.keyframe.AnimationPoint; import mod.azure.azurelib.core.keyframe.Keyframe; -import mod.azure.azurelib.core.keyframe.KeyframeLocation; import mod.azure.azurelib.core.math.Constant; import mod.azure.azurelib.core.math.IValue; import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.MolangQueries; import mod.azure.azurelib.core.object.Axis; +import mod.azure.azurelib.core2.animation.AzKeyframe; +import mod.azure.azurelib.core2.animation.AzKeyframeLocation; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerState; import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; @@ -98,27 +98,33 @@ public void runCurrentAnimation( var scaleKeyFrames = boneAnimation.scaleKeyFrames(); if (!rotationKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addRotations( - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) - ); + var rotX = boneAnimationQueue.rotationXQueue(); + var rotY = boneAnimationQueue.rotationYQueue(); + var rotZ = boneAnimationQueue.rotationZQueue(); + + updateAnimationPointForTick(rotX, rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X); + updateAnimationPointForTick(rotY, rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y); + updateAnimationPointForTick(rotZ, rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z); } if (!positionKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addPositions( - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) - ); + var posX = boneAnimationQueue.positionXQueue(); + var posY = boneAnimationQueue.positionYQueue(); + var posZ = boneAnimationQueue.positionZQueue(); + + updateAnimationPointForTick(posX, positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X); + updateAnimationPointForTick(posY, positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y); + updateAnimationPointForTick(posZ, positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z); } if (!scaleKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addScales( - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) - ); + var scaleX = boneAnimationQueue.scaleXQueue(); + var scaleY = boneAnimationQueue.scaleYQueue(); + var scaleZ = boneAnimationQueue.scaleZQueue(); + + updateAnimationPointForTick(scaleX, scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X); + updateAnimationPointForTick(scaleY, scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y); + updateAnimationPointForTick(scaleZ, scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z); } } @@ -155,49 +161,71 @@ public void transitionFromCurrentAnimation( var scaleKeyFrames = boneAnimation.scaleKeyFrames(); if (!rotationKeyFrames.xKeyframes().isEmpty()) { + var rotX = boneAnimationQueue.rotationXQueue(); + var rotY = boneAnimationQueue.rotationYQueue(); + var rotZ = boneAnimationQueue.rotationZQueue(); + + updateAnimationPointForTick(rotX, rotationKeyFrames.xKeyframes(), 0, true, Axis.X); + updateAnimationPointForTick(rotY, rotationKeyFrames.yKeyframes(), 0, true, Axis.Y); + updateAnimationPointForTick(rotZ, rotationKeyFrames.zKeyframes(), 0, true, Axis.Z); + boneAnimationQueue.addNextRotation( null, adjustedTick, transitionLength, boneSnapshot, bone.getInitialAzSnapshot(), - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) + rotX, + rotY, + rotZ ); } if (!positionKeyFrames.xKeyframes().isEmpty()) { + var posX = boneAnimationQueue.positionXQueue(); + var posY = boneAnimationQueue.positionYQueue(); + var posZ = boneAnimationQueue.positionZQueue(); + + updateAnimationPointForTick(posX, positionKeyFrames.xKeyframes(), 0, false, Axis.X); + updateAnimationPointForTick(posY, positionKeyFrames.yKeyframes(), 0, false, Axis.Y); + updateAnimationPointForTick(posZ, positionKeyFrames.zKeyframes(), 0, false, Axis.Z); + boneAnimationQueue.addNextPosition( null, adjustedTick, transitionLength, boneSnapshot, - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) + posX, + posY, + posZ ); } if (!scaleKeyFrames.xKeyframes().isEmpty()) { + var scaleX = boneAnimationQueue.scaleXQueue(); + var scaleY = boneAnimationQueue.scaleYQueue(); + var scaleZ = boneAnimationQueue.scaleZQueue(); + + updateAnimationPointForTick(scaleX, scaleKeyFrames.xKeyframes(), 0, false, Axis.X); + updateAnimationPointForTick(scaleY, scaleKeyFrames.yKeyframes(), 0, false, Axis.Y); + updateAnimationPointForTick(scaleZ, scaleKeyFrames.zKeyframes(), 0, false, Axis.Z); + boneAnimationQueue.addNextScale( null, adjustedTick, transitionLength, boneSnapshot, - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) + scaleX, + scaleY, + scaleZ ); } } } - /** - * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} - */ - private AnimationPoint getAnimationPointAtTick( - List> frames, + private void updateAnimationPointForTick( + AzAnimationPoint animationPoint, + List> frames, double tick, boolean isRotation, Axis axis @@ -225,7 +253,7 @@ private AnimationPoint getAnimationPointAtTick( } } - return new AnimationPoint(currentFrame, location.startTick(), currentFrame.length(), startValue, endValue); + animationPoint.set(currentFrame, location.startTick(), currentFrame.length(), startValue, endValue); } /** @@ -235,8 +263,8 @@ private AnimationPoint getAnimationPointAtTick( * @param ageInTicks The current tick time * @return A new {@code KeyFrameLocation} containing the current {@code KeyFrame} and the tick time used to find it */ - protected KeyframeLocation> getCurrentKeyFrameLocation( - List> frames, + protected AzKeyframeLocation> getCurrentKeyFrameLocation( + List> frames, double ageInTicks ) { var totalFrameTime = 0.0; @@ -245,10 +273,10 @@ protected KeyframeLocation> getCurrentKeyFrameLocation( totalFrameTime += frame.length(); if (totalFrameTime > ageInTicks) { - return new KeyframeLocation<>(frame, (ageInTicks - (totalFrameTime - frame.length()))); + return new AzKeyframeLocation<>(frame, (ageInTicks - (totalFrameTime - frame.length()))); } } - return new KeyframeLocation<>(frames.get(frames.size() - 1), ageInTicks); + return new AzKeyframeLocation<>(frames.get(frames.size() - 1), ageInTicks); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java index 7e8c9d7f7..dde1e70b3 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java @@ -14,15 +14,14 @@ import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.util.JsonUtil; -import mod.azure.azurelib.core.animation.EasingType; -import mod.azure.azurelib.core.keyframe.BoneAnimation; -import mod.azure.azurelib.core.keyframe.Keyframe; -import mod.azure.azurelib.core.keyframe.KeyframeStack; import mod.azure.azurelib.core.math.Constant; import mod.azure.azurelib.core.math.IValue; import mod.azure.azurelib.core.molang.MolangException; import mod.azure.azurelib.core.molang.MolangParser; -import mod.azure.azurelib.core.molang.expressions.MolangValue; +import mod.azure.azurelib.core2.animation.AzBoneAnimation; +import mod.azure.azurelib.core2.animation.AzEasingType; +import mod.azure.azurelib.core2.animation.AzKeyframe; +import mod.azure.azurelib.core2.animation.AzKeyframeStack; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; import mod.azure.azurelib.core2.animation.primitive.AzKeyframes; @@ -35,11 +34,12 @@ public class AzBakedAnimationsAdapter implements JsonDeserializer { private static List> getTripletObj(JsonElement element) { - if (element == null) + if (element == null) { return List.of(); + } if (element instanceof JsonPrimitive primitive) { - JsonArray array = new JsonArray(3); + var array = new JsonArray(3); array.add(primitive); array.add(primitive); @@ -52,12 +52,11 @@ private static List> getTripletObj(JsonElement element return ObjectArrayList.of(Pair.of("0", array)); if (element instanceof JsonObject obj) { - List> list = new ObjectArrayList<>(); + var list = new ObjectArrayList>(); - for (Map.Entry entry : obj.entrySet()) { + for (var entry : obj.entrySet()) { if (entry.getValue() instanceof JsonObject entryObj && !entryObj.has("vector")) { list.add(getTripletObjBedrock(entry.getKey(), entryObj)); - continue; } @@ -74,27 +73,28 @@ private static Pair getTripletObjBedrock(String timestamp, JsonArray keyframeValues = null; if (keyframe.has("pre")) { - JsonElement pre = keyframe.get("pre"); + var pre = keyframe.get("pre"); keyframeValues = pre.isJsonArray() ? pre.getAsJsonArray() : GsonHelper.getAsJsonArray(pre.getAsJsonObject(), "vector"); } else if (keyframe.has("post")) { - JsonElement post = keyframe.get("post"); + var post = keyframe.get("post"); keyframeValues = post.isJsonArray() ? post.getAsJsonArray() : GsonHelper.getAsJsonArray(post.getAsJsonObject(), "vector"); } - if (keyframeValues != null) + if (keyframeValues != null) { return Pair.of(NumberUtils.isCreatable(timestamp) ? timestamp : "0", keyframeValues); + } throw new JsonParseException("Invalid keyframe data - expected array, found " + keyframe); } - private static double calculateAnimationLength(BoneAnimation[] boneAnimations) { - double length = 0; + private static double calculateAnimationLength(AzBoneAnimation[] boneAnimations) { + var length = 0.0; - for (BoneAnimation animation : boneAnimations) { + for (var animation : boneAnimations) { length = Math.max(length, animation.rotationKeyFrames().getLastKeyframeTime()); length = Math.max(length, animation.positionKeyFrames().getLastKeyframeTime()); length = Math.max(length, animation.scaleKeyFrames().getLastKeyframeTime()); @@ -109,18 +109,22 @@ public AzBakedAnimations deserialize( Type type, JsonDeserializationContext context ) throws JsonParseException { - JsonObject jsonObj = json.getAsJsonObject(); + var jsonObj = json.getAsJsonObject(); - JsonObject animationJsonList = jsonObj.getAsJsonObject("animations"); - JsonArray includeListJSONObj = jsonObj.getAsJsonArray("includes"); + var animationJsonList = jsonObj.getAsJsonObject("animations"); + var includeListJSONObj = jsonObj.getAsJsonArray("includes"); Map includes = null; + if (includeListJSONObj != null) { includes = new Object2ObjectOpenHashMap<>(includeListJSONObj.size()); - for (JsonElement entry : includeListJSONObj.asList()) { - JsonObject obj = entry.getAsJsonObject(); - ResourceLocation fileId = ResourceLocation.parse(obj.get("file_id").getAsString()); - for (JsonElement animName : obj.getAsJsonArray("animations")) { - String ani = animName.getAsString(); + + for (var entry : includeListJSONObj.asList()) { + var obj = entry.getAsJsonObject(); + var fileId = ResourceLocation.parse(obj.get("file_id").getAsString()); + + for (var animName : obj.getAsJsonArray("animations")) { + var ani = animName.getAsString(); + if (includes.containsKey(ani)) { AzureLib.LOGGER.warn( "Animation {} is already included! File already including: {} File trying to include from again: {}", @@ -135,9 +139,9 @@ public AzBakedAnimations deserialize( } } - Map animations = new Object2ObjectOpenHashMap<>(animationJsonList.size()); + var animations = new Object2ObjectOpenHashMap(animationJsonList.size()); - for (Map.Entry entry : animationJsonList.entrySet()) { + for (var entry : animationJsonList.entrySet()) { try { animations.put( entry.getKey(), @@ -157,109 +161,112 @@ private AzAnimation bakeAnimation( JsonObject animationObj, JsonDeserializationContext context ) throws MolangException { - double length = animationObj.has("animation_length") + var length = animationObj.has("animation_length") ? GsonHelper.getAsDouble(animationObj, "animation_length") * 20d - : -1; - AzLoopType loopType = AzLoopType.fromJson(animationObj.get("loop")); - BoneAnimation[] boneAnimations = bakeBoneAnimations( + : -1.0; + var loopType = AzLoopType.fromJson(animationObj.get("loop")); + var boneAnimations = bakeBoneAnimations( GsonHelper.getAsJsonObject(animationObj, "bones", new JsonObject()) ); - AzKeyframes keyframes = context.deserialize(animationObj, AzKeyframes.class); + var keyframes = (AzKeyframes) context.deserialize(animationObj, AzKeyframes.class); - if (length == -1) + if (length == -1) { length = calculateAnimationLength(boneAnimations); + } return new AzAnimation(name, length, loopType, boneAnimations, keyframes); } - private BoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangException { - BoneAnimation[] animations = new BoneAnimation[bonesObj.size()]; - int index = 0; + private AzBoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangException { + var animations = new AzBoneAnimation[bonesObj.size()]; + var index = 0; - for (Map.Entry entry : bonesObj.entrySet()) { - JsonObject entryObj = entry.getValue().getAsJsonObject(); - KeyframeStack> scaleFrames = buildKeyframeStack( + for (var entry : bonesObj.entrySet()) { + var entryObj = entry.getValue().getAsJsonObject(); + var scaleFrames = buildKeyframeStack( getTripletObj(entryObj.get("scale")), false ); - KeyframeStack> positionFrames = buildKeyframeStack( + var positionFrames = buildKeyframeStack( getTripletObj(entryObj.get("position")), false ); - KeyframeStack> rotationFrames = buildKeyframeStack( + var rotationFrames = buildKeyframeStack( getTripletObj(entryObj.get("rotation")), true ); - animations[index] = new BoneAnimation(entry.getKey(), rotationFrames, positionFrames, scaleFrames); + animations[index] = new AzBoneAnimation(entry.getKey(), rotationFrames, positionFrames, scaleFrames); index++; } return animations; } - private KeyframeStack> buildKeyframeStack( + private AzKeyframeStack> buildKeyframeStack( List> entries, boolean isForRotation ) throws MolangException { - if (entries.isEmpty()) - return new KeyframeStack<>(); + if (entries.isEmpty()) { + return new AzKeyframeStack<>(); + } - List> xFrames = new ObjectArrayList<>(); - List> yFrames = new ObjectArrayList<>(); - List> zFrames = new ObjectArrayList<>(); + var xFrames = new ObjectArrayList>(); + var yFrames = new ObjectArrayList>(); + var zFrames = new ObjectArrayList>(); IValue xPrev = null; IValue yPrev = null; IValue zPrev = null; Pair prevEntry = null; - for (Pair entry : entries) { - String key = entry.getFirst(); - JsonElement element = entry.getSecond(); + for (var entry : entries) { + var key = entry.getFirst(); + var element = entry.getSecond(); - if (key.equals("easing") || key.equals("easingArgs") || key.equals("lerp_mode")) + if (key.equals("easing") || key.equals("easingArgs") || key.equals("lerp_mode")) { continue; + } double prevTime = prevEntry != null ? Double.parseDouble(prevEntry.getFirst()) : 0; double curTime = NumberUtils.isCreatable(key) ? Double.parseDouble(entry.getFirst()) : 0; double timeDelta = curTime - prevTime; - JsonArray keyFrameVector = element instanceof JsonArray array + var keyFrameVector = element instanceof JsonArray array ? array : GsonHelper.getAsJsonArray(element.getAsJsonObject(), "vector"); - MolangValue rawXValue = MolangParser.parseJson(keyFrameVector.get(0)); - MolangValue rawYValue = MolangParser.parseJson(keyFrameVector.get(1)); - MolangValue rawZValue = MolangParser.parseJson(keyFrameVector.get(2)); - IValue xValue = isForRotation && rawXValue.isConstant() + var rawXValue = MolangParser.parseJson(keyFrameVector.get(0)); + var rawYValue = MolangParser.parseJson(keyFrameVector.get(1)); + var rawZValue = MolangParser.parseJson(keyFrameVector.get(2)); + var xValue = isForRotation && rawXValue.isConstant() ? new Constant(Math.toRadians(-rawXValue.get())) : rawXValue; - IValue yValue = isForRotation && rawYValue.isConstant() + var yValue = isForRotation && rawYValue.isConstant() ? new Constant(Math.toRadians(-rawYValue.get())) : rawYValue; - IValue zValue = isForRotation && rawZValue.isConstant() + var zValue = isForRotation && rawZValue.isConstant() ? new Constant(Math.toRadians(rawZValue.get())) : rawZValue; - JsonObject entryObj = element instanceof JsonObject obj ? obj : null; - EasingType easingType = entryObj != null && entryObj.has("easing") - ? EasingType.fromJson(entryObj.get("easing")) - : EasingType.LINEAR; - List easingArgs = entryObj != null && entryObj.has("easingArgs") - ? JsonUtil.jsonArrayToList( + var entryObj = element instanceof JsonObject obj ? obj : null; + var easingType = entryObj != null && entryObj.has("easing") + ? AzEasingType.fromJson(entryObj.get("easing")) + : AzEasingType.LINEAR; + var easingArgs = entryObj != null && entryObj.has("easingArgs") + ? JsonUtil.jsonArrayToList( GsonHelper.getAsJsonArray(entryObj, "easingArgs"), ele -> new Constant(ele.getAsDouble()) ) - : new ObjectArrayList<>(); + : new ObjectArrayList(); xFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) + new AzKeyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) ); yFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) + new AzKeyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) ); zFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) + new AzKeyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) ); xPrev = xValue; @@ -268,6 +275,6 @@ private KeyframeStack> buildKeyframeStack( prevEntry = entry; } - return new KeyframeStack<>(xFrames, yFrames, zFrames); + return new AzKeyframeStack<>(xFrames, yFrames, zFrames); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java index 0124c9972..8ce76a1a0 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java @@ -1,9 +1,9 @@ package mod.azure.azurelib.core2.animation.primitive; -import mod.azure.azurelib.core.keyframe.BoneAnimation; import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; +import mod.azure.azurelib.core2.animation.AzBoneAnimation; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; /** @@ -15,7 +15,7 @@ public record AzAnimation( String name, double length, AzLoopType loopType, - BoneAnimation[] boneAnimations, + AzBoneAnimation[] boneAnimations, AzKeyframes keyFrames ) { @@ -24,7 +24,7 @@ public static AzAnimation generateWaitAnimation(double length) { AzStage.WAIT, length, AzLoopType.PLAY_ONCE, - new BoneAnimation[0], + new AzBoneAnimation[0], new AzKeyframes( new SoundKeyframeData[0], new ParticleKeyframeData[0], From 09c2c8308e2ea392acfc45b327560f3aff2e1cd4 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 14 Dec 2024 12:22:20 -0500 Subject: [PATCH 070/224] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index bf2502dce..333a9a2d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -51,5 +51,5 @@ mod_logo = azurelib.png mod_name = AzureLib mod_sources = https://github.com/AzureDoom/AzureLib mod_url = https://modrinth.com/mod/azurelib -version = 3.0.0-alpha8 +version = 3.0.0-alpha9 modrinth_id = 7zlUOZvb From 5502b50b9c9c2a94b89624b7071a06a011732582 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 14 Dec 2024 12:36:23 -0500 Subject: [PATCH 071/224] Revert "perf: Cache animation points instead of creating them every frame." This reverts commit f5c1786bf129b9ad58010e166291fe16d571c547. --- .../core2/animation/AzAnimationProcessor.java | 3 +- .../animation/AzBoneAnimationUpdateUtil.java | 49 ++-- .../core2/animation/AzEasingType.java | 7 +- .../controller/AzAnimationController.java | 14 +- .../keyframe/AzBoneAnimationQueue.java | 234 +++++++----------- .../keyframe/AzKeyFrameProcessor.java | 100 +++----- .../parse/AzBakedAnimationsAdapter.java | 145 ++++++----- .../animation/primitive/AzAnimation.java | 6 +- 8 files changed, 240 insertions(+), 318 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java index c2eaee796..6a07115d4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java @@ -2,6 +2,7 @@ import java.util.Map; +import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.model.AzBoneSnapshot; @@ -50,7 +51,7 @@ public void update(AzAnimationContext context) { private void updateBoneSnapshots( AzAnimationController controller, Map boneSnapshots, - AzEasingType easingType + EasingType easingType ) { // Progresses the current bones according to the animation queue. for (var boneAnimation : controller.getBoneAnimationQueues()) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java index 58e5ba674..bc6fcea94 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java @@ -1,5 +1,6 @@ package mod.azure.azurelib.core2.animation; +import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.model.AzBoneSnapshot; @@ -9,17 +10,17 @@ public class AzBoneAnimationUpdateUtil { public static void updatePositions( AzBoneAnimationQueue boneAnimation, AzBone bone, - AzEasingType easingType, + EasingType easingType, AzBoneSnapshot snapshot ) { - var posXPoint = boneAnimation.positionXQueue(); - var posYPoint = boneAnimation.positionYQueue(); - var posZPoint = boneAnimation.positionZQueue(); + var posXPoint = boneAnimation.positionXQueue().poll(); + var posYPoint = boneAnimation.positionYQueue().poll(); + var posZPoint = boneAnimation.positionZQueue().poll(); - if (!posXPoint.isEmpty() && !posYPoint.isEmpty() && !posZPoint.isEmpty()) { - bone.setPosX((float) AzEasingType.lerpWithOverride(posXPoint, easingType)); - bone.setPosY((float) AzEasingType.lerpWithOverride(posYPoint, easingType)); - bone.setPosZ((float) AzEasingType.lerpWithOverride(posZPoint, easingType)); + if (posXPoint != null && posYPoint != null && posZPoint != null) { + bone.setPosX((float) EasingType.lerpWithOverride(posXPoint, easingType)); + bone.setPosY((float) EasingType.lerpWithOverride(posYPoint, easingType)); + bone.setPosZ((float) EasingType.lerpWithOverride(posZPoint, easingType)); snapshot.updateOffset(bone.getPosX(), bone.getPosY(), bone.getPosZ()); snapshot.startPosAnim(); bone.markPositionAsChanged(); @@ -29,23 +30,23 @@ public static void updatePositions( public static void updateRotations( AzBoneAnimationQueue boneAnimation, AzBone bone, - AzEasingType easingType, + EasingType easingType, AzBoneSnapshot initialSnapshot, AzBoneSnapshot snapshot ) { - var rotXPoint = boneAnimation.rotationXQueue(); - var rotYPoint = boneAnimation.rotationYQueue(); - var rotZPoint = boneAnimation.rotationZQueue(); + var rotXPoint = boneAnimation.rotationXQueue().poll(); + var rotYPoint = boneAnimation.rotationYQueue().poll(); + var rotZPoint = boneAnimation.rotationZQueue().poll(); - if (!rotXPoint.isEmpty() && !rotYPoint.isEmpty() && !rotZPoint.isEmpty()) { + if (rotXPoint != null && rotYPoint != null && rotZPoint != null) { bone.setRotX( - (float) AzEasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() + (float) EasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() ); bone.setRotY( - (float) AzEasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() + (float) EasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() ); bone.setRotZ( - (float) AzEasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() + (float) EasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() ); snapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); snapshot.startRotAnim(); @@ -56,17 +57,17 @@ public static void updateRotations( public static void updateScale( AzBoneAnimationQueue boneAnimation, AzBone bone, - AzEasingType easingType, + EasingType easingType, AzBoneSnapshot snapshot ) { - var scaleXPoint = boneAnimation.scaleXQueue(); - var scaleYPoint = boneAnimation.scaleYQueue(); - var scaleZPoint = boneAnimation.scaleZQueue(); + var scaleXPoint = boneAnimation.scaleXQueue().poll(); + var scaleYPoint = boneAnimation.scaleYQueue().poll(); + var scaleZPoint = boneAnimation.scaleZQueue().poll(); - if (!scaleXPoint.isEmpty() && !scaleYPoint.isEmpty() && !scaleZPoint.isEmpty()) { - bone.setScaleX((float) AzEasingType.lerpWithOverride(scaleXPoint, easingType)); - bone.setScaleY((float) AzEasingType.lerpWithOverride(scaleYPoint, easingType)); - bone.setScaleZ((float) AzEasingType.lerpWithOverride(scaleZPoint, easingType)); + if (scaleXPoint != null && scaleYPoint != null && scaleZPoint != null) { + bone.setScaleX((float) EasingType.lerpWithOverride(scaleXPoint, easingType)); + bone.setScaleY((float) EasingType.lerpWithOverride(scaleYPoint, easingType)); + bone.setScaleZ((float) EasingType.lerpWithOverride(scaleZPoint, easingType)); snapshot.updateScale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); snapshot.startScaleAnim(); bone.markScaleAsChanged(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java index 0414f882d..97635d14c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java @@ -99,11 +99,8 @@ public interface AzEasingType { static double lerpWithOverride(AzAnimationPoint animationPoint, AzEasingType override) { AzEasingType easingType = override; - if (override == null) { - easingType = animationPoint.keyFrame() == null - ? LINEAR - : animationPoint.keyFrame().easingType(); - } + if (override == null) + easingType = animationPoint.keyFrame() == null ? LINEAR : animationPoint.keyFrame().easingType(); return easingType.apply(animationPoint); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 0732432ed..ea1ff6a3e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -13,11 +13,11 @@ import java.util.function.Function; import java.util.function.ToDoubleFunction; +import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.core2.animation.AzAnimationContext; import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.AzEasingType; import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; @@ -76,7 +76,7 @@ public class AzAnimationController { protected ToDoubleFunction animationSpeedModifier = obj -> 1d; - protected Function overrideEasingTypeFunction = obj -> null; + protected Function overrideEasingTypeFunction = obj -> null; protected boolean justStopped = true; @@ -127,28 +127,28 @@ public void setJustStarting(boolean justStarting) { } /** - * Sets the controller's {@link AzEasingType} override for animations.
      + * Sets the controller's {@link EasingType} override for animations.
      * By default, the controller will use whatever {@code EasingType} was defined in the animation json * * @param easingTypeFunction The new {@code EasingType} to use * @return this */ - public AzAnimationController setOverrideEasingType(AzEasingType easingTypeFunction) { + public AzAnimationController setOverrideEasingType(EasingType easingTypeFunction) { return setOverrideEasingTypeFunction(obj -> easingTypeFunction); } - public Function getOverrideEasingTypeFunction() { + public Function getOverrideEasingTypeFunction() { return overrideEasingTypeFunction; } /** - * Sets the controller's {@link AzEasingType} override function for animations.
      + * Sets the controller's {@link EasingType} override function for animations.
      * By default, the controller will use whatever {@code EasingType} was defined in the animation json * * @param easingType The new {@code EasingType} to use * @return this */ - public AzAnimationController setOverrideEasingTypeFunction(Function easingType) { + public AzAnimationController setOverrideEasingTypeFunction(Function easingType) { this.overrideEasingTypeFunction = easingType; return this; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java index c558b5ddf..40bbfd7c9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java @@ -5,7 +5,11 @@ */ package mod.azure.azurelib.core2.animation.controller.keyframe; -import mod.azure.azurelib.core2.animation.AzKeyframe; +import java.util.LinkedList; +import java.util.Queue; + +import mod.azure.azurelib.core.keyframe.AnimationPoint; +import mod.azure.azurelib.core.keyframe.Keyframe; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.model.AzBoneSnapshot; @@ -14,43 +18,37 @@ * A bone pseudo-stack for bone animation positions, scales, and rotations. Animation points are calculated then pushed * onto their respective queues to be used for transformations in rendering */ -public class AzBoneAnimationQueue { - - private AzBone bone; - - private AzAnimationPoint rotationXQueue; - - private AzAnimationPoint rotationYQueue; - - private AzAnimationPoint rotationZQueue; - - private AzAnimationPoint positionXQueue; - - private AzAnimationPoint positionYQueue; - - private AzAnimationPoint positionZQueue; - - private AzAnimationPoint scaleXQueue; - - private AzAnimationPoint scaleYQueue; - - private AzAnimationPoint scaleZQueue; +public record AzBoneAnimationQueue( + AzBone bone, + Queue rotationXQueue, + Queue rotationYQueue, + Queue rotationZQueue, + Queue positionXQueue, + Queue positionYQueue, + Queue positionZQueue, + Queue scaleXQueue, + Queue scaleYQueue, + Queue scaleZQueue +) { public AzBoneAnimationQueue(AzBone bone) { - this.bone = bone; - this.rotationXQueue = AzAnimationPoint.create(); - this.rotationYQueue = AzAnimationPoint.create(); - this.rotationZQueue = AzAnimationPoint.create(); - this.positionXQueue = AzAnimationPoint.create(); - this.positionYQueue = AzAnimationPoint.create(); - this.positionZQueue = AzAnimationPoint.create(); - this.scaleXQueue = AzAnimationPoint.create(); - this.scaleYQueue = AzAnimationPoint.create(); - this.scaleZQueue = AzAnimationPoint.create(); + // TODO: Optimize + this( + bone, + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>() + ); } /** - * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#positionXQueue} + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#positionXQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -59,17 +57,17 @@ public AzBoneAnimationQueue(AzBone bone) { * @param endValue The value of the point at the end of its transition */ public void addPosXPoint( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.positionXQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); + this.positionXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } /** - * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#positionYQueue} + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#positionYQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -78,17 +76,17 @@ public void addPosXPoint( * @param endValue The value of the point at the end of its transition */ public void addPosYPoint( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.positionYQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); + this.positionYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } /** - * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#positionZQueue} + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#positionZQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -97,17 +95,17 @@ public void addPosYPoint( * @param endValue The value of the point at the end of its transition */ public void addPosZPoint( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.positionZQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); + this.positionZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } /** - * Add a new X, Y, and Z position {@link AzAnimationPoint} to their respective queues + * Add a new X, Y, and Z position {@link AnimationPoint} to their respective queues * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -122,13 +120,13 @@ public void addPosZPoint( * new point */ public void addNextPosition( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, AzBoneSnapshot startSnapshot, - AzAnimationPoint nextXPoint, - AzAnimationPoint nextYPoint, - AzAnimationPoint nextZPoint + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint ) { addPosXPoint( keyFrame, @@ -154,7 +152,7 @@ public void addNextPosition( } /** - * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#scaleXQueue} + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#scaleXQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -163,17 +161,17 @@ public void addNextPosition( * @param endValue The value of the point at the end of its transition */ public void addScaleXPoint( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.scaleXQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); + this.scaleXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } /** - * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#scaleYQueue} + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#scaleYQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -182,17 +180,17 @@ public void addScaleXPoint( * @param endValue The value of the point at the end of its transition */ public void addScaleYPoint( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.scaleYQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); + this.scaleYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } /** - * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#scaleZQueue} + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#scaleZQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -201,17 +199,17 @@ public void addScaleYPoint( * @param endValue The value of the point at the end of its transition */ public void addScaleZPoint( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.scaleZQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); + this.scaleZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } /** - * Add a new X, Y, and Z scale {@link AzAnimationPoint} to their respective queues + * Add a new X, Y, and Z scale {@link AnimationPoint} to their respective queues * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -226,13 +224,13 @@ public void addScaleZPoint( * new point */ public void addNextScale( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, AzBoneSnapshot startSnapshot, - AzAnimationPoint nextXPoint, - AzAnimationPoint nextYPoint, - AzAnimationPoint nextZPoint + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint ) { addScaleXPoint( keyFrame, @@ -258,7 +256,7 @@ public void addNextScale( } /** - * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#rotationXQueue} + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#rotationXQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -267,17 +265,17 @@ public void addNextScale( * @param endValue The value of the point at the end of its transition */ public void addRotationXPoint( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.rotationXQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); + this.rotationXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } /** - * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#rotationYQueue} + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#rotationYQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -286,17 +284,17 @@ public void addRotationXPoint( * @param endValue The value of the point at the end of its transition */ public void addRotationYPoint( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.rotationYQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); + this.rotationYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } /** - * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#rotationZQueue} + * Add a new {@link AnimationPoint} to the {@link AzBoneAnimationQueue#rotationZQueue} * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -305,17 +303,17 @@ public void addRotationYPoint( * @param endValue The value of the point at the end of its transition */ public void addRotationZPoint( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, double startValue, double endValue ) { - this.rotationZQueue.set(keyFrame, lerpedTick, transitionLength, startValue, endValue); + this.rotationZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } /** - * Add a new X, Y, and Z scale {@link AzAnimationPoint} to their respective queues + * Add a new X, Y, and Z scale {@link AnimationPoint} to their respective queues * * @param keyFrame The {@code Nullable} Keyframe relevant to the animation point * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at @@ -331,14 +329,14 @@ public void addRotationZPoint( * new point */ public void addNextRotation( - AzKeyframe keyFrame, + Keyframe keyFrame, double lerpedTick, double transitionLength, AzBoneSnapshot startSnapshot, AzBoneSnapshot initialSnapshot, - AzAnimationPoint nextXPoint, - AzAnimationPoint nextYPoint, - AzAnimationPoint nextZPoint + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint ) { addRotationXPoint( keyFrame, @@ -364,81 +362,41 @@ public void addNextRotation( } /** - * Add an X, Y, and Z position {@link AzAnimationPoint} to their respective queues + * Add an X, Y, and Z position {@link AnimationPoint} to their respective queues * - * @param xPoint The x position {@code AzAnimationPoint} to add - * @param yPoint The y position {@code AzAnimationPoint} to add - * @param zPoint The z position {@code AzAnimationPoint} to add + * @param xPoint The x position {@code AnimationPoint} to add + * @param yPoint The y position {@code AnimationPoint} to add + * @param zPoint The z position {@code AnimationPoint} to add */ - public void addPositions(AzAnimationPoint xPoint, AzAnimationPoint yPoint, AzAnimationPoint zPoint) { - this.positionXQueue = xPoint; - this.positionYQueue = yPoint; - this.positionZQueue = zPoint; + public void addPositions(AnimationPoint xPoint, AnimationPoint yPoint, AnimationPoint zPoint) { + this.positionXQueue.add(xPoint); + this.positionYQueue.add(yPoint); + this.positionZQueue.add(zPoint); } /** - * Add an X, Y, and Z scale {@link AzAnimationPoint} to their respective queues + * Add an X, Y, and Z scale {@link AnimationPoint} to their respective queues * - * @param xPoint The x scale {@code AzAnimationPoint} to add - * @param yPoint The y scale {@code AzAnimationPoint} to add - * @param zPoint The z scale {@code AzAnimationPoint} to add + * @param xPoint The x scale {@code AnimationPoint} to add + * @param yPoint The y scale {@code AnimationPoint} to add + * @param zPoint The z scale {@code AnimationPoint} to add */ - public void addScales(AzAnimationPoint xPoint, AzAnimationPoint yPoint, AzAnimationPoint zPoint) { - this.scaleXQueue = xPoint; - this.scaleYQueue = yPoint; - this.scaleZQueue = zPoint; + public void addScales(AnimationPoint xPoint, AnimationPoint yPoint, AnimationPoint zPoint) { + this.scaleXQueue.add(xPoint); + this.scaleYQueue.add(yPoint); + this.scaleZQueue.add(zPoint); } /** - * Add an X, Y, and Z rotation {@link AzAnimationPoint} to their respective queues + * Add an X, Y, and Z rotation {@link AnimationPoint} to their respective queues * - * @param xPoint The x rotation {@code AzAnimationPoint} to add - * @param yPoint The y rotation {@code AzAnimationPoint} to add - * @param zPoint The z rotation {@code AzAnimationPoint} to add + * @param xPoint The x rotation {@code AnimationPoint} to add + * @param yPoint The y rotation {@code AnimationPoint} to add + * @param zPoint The z rotation {@code AnimationPoint} to add */ - public void addRotations(AzAnimationPoint xPoint, AzAnimationPoint yPoint, AzAnimationPoint zPoint) { - this.rotationXQueue = xPoint; - this.rotationYQueue = yPoint; - this.rotationZQueue = zPoint; - } - - public AzBone bone() { - return bone; - } - - public AzAnimationPoint rotationXQueue() { - return rotationXQueue; - } - - public AzAnimationPoint rotationYQueue() { - return rotationYQueue; - } - - public AzAnimationPoint rotationZQueue() { - return rotationZQueue; - } - - public AzAnimationPoint positionXQueue() { - return positionXQueue; - } - - public AzAnimationPoint positionYQueue() { - return positionYQueue; - } - - public AzAnimationPoint positionZQueue() { - return positionZQueue; - } - - public AzAnimationPoint scaleXQueue() { - return scaleXQueue; - } - - public AzAnimationPoint scaleYQueue() { - return scaleYQueue; - } - - public AzAnimationPoint scaleZQueue() { - return scaleZQueue; + public void addRotations(AnimationPoint xPoint, AnimationPoint yPoint, AnimationPoint zPoint) { + this.rotationXQueue.add(xPoint); + this.rotationYQueue.add(yPoint); + this.rotationZQueue.add(zPoint); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java index 153f0a31a..0f2881b25 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java @@ -4,14 +4,14 @@ import java.util.Map; import java.util.NoSuchElementException; +import mod.azure.azurelib.core.keyframe.AnimationPoint; import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.keyframe.KeyframeLocation; import mod.azure.azurelib.core.math.Constant; import mod.azure.azurelib.core.math.IValue; import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.MolangQueries; import mod.azure.azurelib.core.object.Axis; -import mod.azure.azurelib.core2.animation.AzKeyframe; -import mod.azure.azurelib.core2.animation.AzKeyframeLocation; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerState; import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; @@ -98,33 +98,27 @@ public void runCurrentAnimation( var scaleKeyFrames = boneAnimation.scaleKeyFrames(); if (!rotationKeyFrames.xKeyframes().isEmpty()) { - var rotX = boneAnimationQueue.rotationXQueue(); - var rotY = boneAnimationQueue.rotationYQueue(); - var rotZ = boneAnimationQueue.rotationZQueue(); - - updateAnimationPointForTick(rotX, rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X); - updateAnimationPointForTick(rotY, rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y); - updateAnimationPointForTick(rotZ, rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z); + boneAnimationQueue.addRotations( + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) + ); } if (!positionKeyFrames.xKeyframes().isEmpty()) { - var posX = boneAnimationQueue.positionXQueue(); - var posY = boneAnimationQueue.positionYQueue(); - var posZ = boneAnimationQueue.positionZQueue(); - - updateAnimationPointForTick(posX, positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X); - updateAnimationPointForTick(posY, positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y); - updateAnimationPointForTick(posZ, positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z); + boneAnimationQueue.addPositions( + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + ); } if (!scaleKeyFrames.xKeyframes().isEmpty()) { - var scaleX = boneAnimationQueue.scaleXQueue(); - var scaleY = boneAnimationQueue.scaleYQueue(); - var scaleZ = boneAnimationQueue.scaleZQueue(); - - updateAnimationPointForTick(scaleX, scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X); - updateAnimationPointForTick(scaleY, scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y); - updateAnimationPointForTick(scaleZ, scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z); + boneAnimationQueue.addScales( + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + ); } } @@ -161,71 +155,49 @@ public void transitionFromCurrentAnimation( var scaleKeyFrames = boneAnimation.scaleKeyFrames(); if (!rotationKeyFrames.xKeyframes().isEmpty()) { - var rotX = boneAnimationQueue.rotationXQueue(); - var rotY = boneAnimationQueue.rotationYQueue(); - var rotZ = boneAnimationQueue.rotationZQueue(); - - updateAnimationPointForTick(rotX, rotationKeyFrames.xKeyframes(), 0, true, Axis.X); - updateAnimationPointForTick(rotY, rotationKeyFrames.yKeyframes(), 0, true, Axis.Y); - updateAnimationPointForTick(rotZ, rotationKeyFrames.zKeyframes(), 0, true, Axis.Z); - boneAnimationQueue.addNextRotation( null, adjustedTick, transitionLength, boneSnapshot, bone.getInitialAzSnapshot(), - rotX, - rotY, - rotZ + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) ); } if (!positionKeyFrames.xKeyframes().isEmpty()) { - var posX = boneAnimationQueue.positionXQueue(); - var posY = boneAnimationQueue.positionYQueue(); - var posZ = boneAnimationQueue.positionZQueue(); - - updateAnimationPointForTick(posX, positionKeyFrames.xKeyframes(), 0, false, Axis.X); - updateAnimationPointForTick(posY, positionKeyFrames.yKeyframes(), 0, false, Axis.Y); - updateAnimationPointForTick(posZ, positionKeyFrames.zKeyframes(), 0, false, Axis.Z); - boneAnimationQueue.addNextPosition( null, adjustedTick, transitionLength, boneSnapshot, - posX, - posY, - posZ + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) ); } if (!scaleKeyFrames.xKeyframes().isEmpty()) { - var scaleX = boneAnimationQueue.scaleXQueue(); - var scaleY = boneAnimationQueue.scaleYQueue(); - var scaleZ = boneAnimationQueue.scaleZQueue(); - - updateAnimationPointForTick(scaleX, scaleKeyFrames.xKeyframes(), 0, false, Axis.X); - updateAnimationPointForTick(scaleY, scaleKeyFrames.yKeyframes(), 0, false, Axis.Y); - updateAnimationPointForTick(scaleZ, scaleKeyFrames.zKeyframes(), 0, false, Axis.Z); - boneAnimationQueue.addNextScale( null, adjustedTick, transitionLength, boneSnapshot, - scaleX, - scaleY, - scaleZ + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) ); } } } - private void updateAnimationPointForTick( - AzAnimationPoint animationPoint, - List> frames, + /** + * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} + */ + private AnimationPoint getAnimationPointAtTick( + List> frames, double tick, boolean isRotation, Axis axis @@ -253,7 +225,7 @@ private void updateAnimationPointForTick( } } - animationPoint.set(currentFrame, location.startTick(), currentFrame.length(), startValue, endValue); + return new AnimationPoint(currentFrame, location.startTick(), currentFrame.length(), startValue, endValue); } /** @@ -263,8 +235,8 @@ private void updateAnimationPointForTick( * @param ageInTicks The current tick time * @return A new {@code KeyFrameLocation} containing the current {@code KeyFrame} and the tick time used to find it */ - protected AzKeyframeLocation> getCurrentKeyFrameLocation( - List> frames, + protected KeyframeLocation> getCurrentKeyFrameLocation( + List> frames, double ageInTicks ) { var totalFrameTime = 0.0; @@ -273,10 +245,10 @@ protected AzKeyframeLocation> getCurrentKeyFrameLocation( totalFrameTime += frame.length(); if (totalFrameTime > ageInTicks) { - return new AzKeyframeLocation<>(frame, (ageInTicks - (totalFrameTime - frame.length()))); + return new KeyframeLocation<>(frame, (ageInTicks - (totalFrameTime - frame.length()))); } } - return new AzKeyframeLocation<>(frames.get(frames.size() - 1), ageInTicks); + return new KeyframeLocation<>(frames.get(frames.size() - 1), ageInTicks); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java index dde1e70b3..7e8c9d7f7 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java @@ -14,14 +14,15 @@ import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.util.JsonUtil; +import mod.azure.azurelib.core.animation.EasingType; +import mod.azure.azurelib.core.keyframe.BoneAnimation; +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.keyframe.KeyframeStack; import mod.azure.azurelib.core.math.Constant; import mod.azure.azurelib.core.math.IValue; import mod.azure.azurelib.core.molang.MolangException; import mod.azure.azurelib.core.molang.MolangParser; -import mod.azure.azurelib.core2.animation.AzBoneAnimation; -import mod.azure.azurelib.core2.animation.AzEasingType; -import mod.azure.azurelib.core2.animation.AzKeyframe; -import mod.azure.azurelib.core2.animation.AzKeyframeStack; +import mod.azure.azurelib.core.molang.expressions.MolangValue; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; import mod.azure.azurelib.core2.animation.primitive.AzKeyframes; @@ -34,12 +35,11 @@ public class AzBakedAnimationsAdapter implements JsonDeserializer { private static List> getTripletObj(JsonElement element) { - if (element == null) { + if (element == null) return List.of(); - } if (element instanceof JsonPrimitive primitive) { - var array = new JsonArray(3); + JsonArray array = new JsonArray(3); array.add(primitive); array.add(primitive); @@ -52,11 +52,12 @@ private static List> getTripletObj(JsonElement element return ObjectArrayList.of(Pair.of("0", array)); if (element instanceof JsonObject obj) { - var list = new ObjectArrayList>(); + List> list = new ObjectArrayList<>(); - for (var entry : obj.entrySet()) { + for (Map.Entry entry : obj.entrySet()) { if (entry.getValue() instanceof JsonObject entryObj && !entryObj.has("vector")) { list.add(getTripletObjBedrock(entry.getKey(), entryObj)); + continue; } @@ -73,28 +74,27 @@ private static Pair getTripletObjBedrock(String timestamp, JsonArray keyframeValues = null; if (keyframe.has("pre")) { - var pre = keyframe.get("pre"); + JsonElement pre = keyframe.get("pre"); keyframeValues = pre.isJsonArray() ? pre.getAsJsonArray() : GsonHelper.getAsJsonArray(pre.getAsJsonObject(), "vector"); } else if (keyframe.has("post")) { - var post = keyframe.get("post"); + JsonElement post = keyframe.get("post"); keyframeValues = post.isJsonArray() ? post.getAsJsonArray() : GsonHelper.getAsJsonArray(post.getAsJsonObject(), "vector"); } - if (keyframeValues != null) { + if (keyframeValues != null) return Pair.of(NumberUtils.isCreatable(timestamp) ? timestamp : "0", keyframeValues); - } throw new JsonParseException("Invalid keyframe data - expected array, found " + keyframe); } - private static double calculateAnimationLength(AzBoneAnimation[] boneAnimations) { - var length = 0.0; + private static double calculateAnimationLength(BoneAnimation[] boneAnimations) { + double length = 0; - for (var animation : boneAnimations) { + for (BoneAnimation animation : boneAnimations) { length = Math.max(length, animation.rotationKeyFrames().getLastKeyframeTime()); length = Math.max(length, animation.positionKeyFrames().getLastKeyframeTime()); length = Math.max(length, animation.scaleKeyFrames().getLastKeyframeTime()); @@ -109,22 +109,18 @@ public AzBakedAnimations deserialize( Type type, JsonDeserializationContext context ) throws JsonParseException { - var jsonObj = json.getAsJsonObject(); + JsonObject jsonObj = json.getAsJsonObject(); - var animationJsonList = jsonObj.getAsJsonObject("animations"); - var includeListJSONObj = jsonObj.getAsJsonArray("includes"); + JsonObject animationJsonList = jsonObj.getAsJsonObject("animations"); + JsonArray includeListJSONObj = jsonObj.getAsJsonArray("includes"); Map includes = null; - if (includeListJSONObj != null) { includes = new Object2ObjectOpenHashMap<>(includeListJSONObj.size()); - - for (var entry : includeListJSONObj.asList()) { - var obj = entry.getAsJsonObject(); - var fileId = ResourceLocation.parse(obj.get("file_id").getAsString()); - - for (var animName : obj.getAsJsonArray("animations")) { - var ani = animName.getAsString(); - + for (JsonElement entry : includeListJSONObj.asList()) { + JsonObject obj = entry.getAsJsonObject(); + ResourceLocation fileId = ResourceLocation.parse(obj.get("file_id").getAsString()); + for (JsonElement animName : obj.getAsJsonArray("animations")) { + String ani = animName.getAsString(); if (includes.containsKey(ani)) { AzureLib.LOGGER.warn( "Animation {} is already included! File already including: {} File trying to include from again: {}", @@ -139,9 +135,9 @@ public AzBakedAnimations deserialize( } } - var animations = new Object2ObjectOpenHashMap(animationJsonList.size()); + Map animations = new Object2ObjectOpenHashMap<>(animationJsonList.size()); - for (var entry : animationJsonList.entrySet()) { + for (Map.Entry entry : animationJsonList.entrySet()) { try { animations.put( entry.getKey(), @@ -161,112 +157,109 @@ private AzAnimation bakeAnimation( JsonObject animationObj, JsonDeserializationContext context ) throws MolangException { - var length = animationObj.has("animation_length") + double length = animationObj.has("animation_length") ? GsonHelper.getAsDouble(animationObj, "animation_length") * 20d - : -1.0; - var loopType = AzLoopType.fromJson(animationObj.get("loop")); - var boneAnimations = bakeBoneAnimations( + : -1; + AzLoopType loopType = AzLoopType.fromJson(animationObj.get("loop")); + BoneAnimation[] boneAnimations = bakeBoneAnimations( GsonHelper.getAsJsonObject(animationObj, "bones", new JsonObject()) ); - var keyframes = (AzKeyframes) context.deserialize(animationObj, AzKeyframes.class); + AzKeyframes keyframes = context.deserialize(animationObj, AzKeyframes.class); - if (length == -1) { + if (length == -1) length = calculateAnimationLength(boneAnimations); - } return new AzAnimation(name, length, loopType, boneAnimations, keyframes); } - private AzBoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangException { - var animations = new AzBoneAnimation[bonesObj.size()]; - var index = 0; + private BoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangException { + BoneAnimation[] animations = new BoneAnimation[bonesObj.size()]; + int index = 0; - for (var entry : bonesObj.entrySet()) { - var entryObj = entry.getValue().getAsJsonObject(); - var scaleFrames = buildKeyframeStack( + for (Map.Entry entry : bonesObj.entrySet()) { + JsonObject entryObj = entry.getValue().getAsJsonObject(); + KeyframeStack> scaleFrames = buildKeyframeStack( getTripletObj(entryObj.get("scale")), false ); - var positionFrames = buildKeyframeStack( + KeyframeStack> positionFrames = buildKeyframeStack( getTripletObj(entryObj.get("position")), false ); - var rotationFrames = buildKeyframeStack( + KeyframeStack> rotationFrames = buildKeyframeStack( getTripletObj(entryObj.get("rotation")), true ); - animations[index] = new AzBoneAnimation(entry.getKey(), rotationFrames, positionFrames, scaleFrames); + animations[index] = new BoneAnimation(entry.getKey(), rotationFrames, positionFrames, scaleFrames); index++; } return animations; } - private AzKeyframeStack> buildKeyframeStack( + private KeyframeStack> buildKeyframeStack( List> entries, boolean isForRotation ) throws MolangException { - if (entries.isEmpty()) { - return new AzKeyframeStack<>(); - } + if (entries.isEmpty()) + return new KeyframeStack<>(); - var xFrames = new ObjectArrayList>(); - var yFrames = new ObjectArrayList>(); - var zFrames = new ObjectArrayList>(); + List> xFrames = new ObjectArrayList<>(); + List> yFrames = new ObjectArrayList<>(); + List> zFrames = new ObjectArrayList<>(); IValue xPrev = null; IValue yPrev = null; IValue zPrev = null; Pair prevEntry = null; - for (var entry : entries) { - var key = entry.getFirst(); - var element = entry.getSecond(); + for (Pair entry : entries) { + String key = entry.getFirst(); + JsonElement element = entry.getSecond(); - if (key.equals("easing") || key.equals("easingArgs") || key.equals("lerp_mode")) { + if (key.equals("easing") || key.equals("easingArgs") || key.equals("lerp_mode")) continue; - } double prevTime = prevEntry != null ? Double.parseDouble(prevEntry.getFirst()) : 0; double curTime = NumberUtils.isCreatable(key) ? Double.parseDouble(entry.getFirst()) : 0; double timeDelta = curTime - prevTime; - var keyFrameVector = element instanceof JsonArray array + JsonArray keyFrameVector = element instanceof JsonArray array ? array : GsonHelper.getAsJsonArray(element.getAsJsonObject(), "vector"); - var rawXValue = MolangParser.parseJson(keyFrameVector.get(0)); - var rawYValue = MolangParser.parseJson(keyFrameVector.get(1)); - var rawZValue = MolangParser.parseJson(keyFrameVector.get(2)); - var xValue = isForRotation && rawXValue.isConstant() + MolangValue rawXValue = MolangParser.parseJson(keyFrameVector.get(0)); + MolangValue rawYValue = MolangParser.parseJson(keyFrameVector.get(1)); + MolangValue rawZValue = MolangParser.parseJson(keyFrameVector.get(2)); + IValue xValue = isForRotation && rawXValue.isConstant() ? new Constant(Math.toRadians(-rawXValue.get())) : rawXValue; - var yValue = isForRotation && rawYValue.isConstant() + IValue yValue = isForRotation && rawYValue.isConstant() ? new Constant(Math.toRadians(-rawYValue.get())) : rawYValue; - var zValue = isForRotation && rawZValue.isConstant() + IValue zValue = isForRotation && rawZValue.isConstant() ? new Constant(Math.toRadians(rawZValue.get())) : rawZValue; - var entryObj = element instanceof JsonObject obj ? obj : null; - var easingType = entryObj != null && entryObj.has("easing") - ? AzEasingType.fromJson(entryObj.get("easing")) - : AzEasingType.LINEAR; - var easingArgs = entryObj != null && entryObj.has("easingArgs") - ? JsonUtil.jsonArrayToList( + JsonObject entryObj = element instanceof JsonObject obj ? obj : null; + EasingType easingType = entryObj != null && entryObj.has("easing") + ? EasingType.fromJson(entryObj.get("easing")) + : EasingType.LINEAR; + List easingArgs = entryObj != null && entryObj.has("easingArgs") + ? JsonUtil.jsonArrayToList( GsonHelper.getAsJsonArray(entryObj, "easingArgs"), ele -> new Constant(ele.getAsDouble()) ) - : new ObjectArrayList(); + : new ObjectArrayList<>(); xFrames.add( - new AzKeyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) ); yFrames.add( - new AzKeyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) ); zFrames.add( - new AzKeyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) ); xPrev = xValue; @@ -275,6 +268,6 @@ private AzKeyframeStack> buildKeyframeStack( prevEntry = entry; } - return new AzKeyframeStack<>(xFrames, yFrames, zFrames); + return new KeyframeStack<>(xFrames, yFrames, zFrames); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java index 8ce76a1a0..0124c9972 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzAnimation.java @@ -1,9 +1,9 @@ package mod.azure.azurelib.core2.animation.primitive; +import mod.azure.azurelib.core.keyframe.BoneAnimation; import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; -import mod.azure.azurelib.core2.animation.AzBoneAnimation; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; /** @@ -15,7 +15,7 @@ public record AzAnimation( String name, double length, AzLoopType loopType, - AzBoneAnimation[] boneAnimations, + BoneAnimation[] boneAnimations, AzKeyframes keyFrames ) { @@ -24,7 +24,7 @@ public static AzAnimation generateWaitAnimation(double length) { AzStage.WAIT, length, AzLoopType.PLAY_ONCE, - new AzBoneAnimation[0], + new BoneAnimation[0], new AzKeyframes( new SoundKeyframeData[0], new ParticleKeyframeData[0], From 73f29d9b128e01b6f9e58d5208b5b7fcffc5b584 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 14 Dec 2024 12:36:27 -0500 Subject: [PATCH 072/224] Revert "Implemented AzKeyframeStack.java, AzKeyframe.java, AzKeyframeLocation.java, AzAnimationPoint.java and AzEasingType.java." This reverts commit 76d2182a63079283a22a5103d354fed2319b14db. --- .../core2/animation/AzBoneAnimation.java | 25 -- .../core2/animation/AzEasingType.java | 400 ------------------ .../azurelib/core2/animation/AzKeyframe.java | 55 --- .../core2/animation/AzKeyframeLocation.java | 19 - .../core2/animation/AzKeyframeStack.java | 50 --- .../controller/keyframe/AzAnimationPoint.java | 91 ---- 6 files changed, 640 deletions(-) delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimation.java delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframe.java delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeLocation.java delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeStack.java delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAnimationPoint.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimation.java deleted file mode 100644 index 924ac9ea3..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimation.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * This class is a fork of the matching class found in the Geckolib repository. Original source: - * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. - * https://github.com/bernie-g/geckolib/blob/main/LICENSE - */ -package mod.azure.azurelib.core2.animation; - -import mod.azure.azurelib.core.keyframe.Keyframe; -import mod.azure.azurelib.core.math.IValue; - -/** - * A record of a deserialized animation for a given bone.
      - * Responsible for holding the various {@link Keyframe Keyframes} for the bone's animation transformations - * - * @param boneName The name of the bone as listed in the {@code animation.json} - * @param rotationKeyFrames The deserialized rotation {@code Keyframe} stack - * @param positionKeyFrames The deserialized position {@code Keyframe} stack - * @param scaleKeyFrames The deserialized scale {@code Keyframe} stack - */ -public record AzBoneAnimation( - String boneName, - AzKeyframeStack> rotationKeyFrames, - AzKeyframeStack> positionKeyFrames, - AzKeyframeStack> scaleKeyFrames -) {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java deleted file mode 100644 index 97635d14c..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzEasingType.java +++ /dev/null @@ -1,400 +0,0 @@ -/** - * This class is a fork of the matching class found in the Geckolib repository. Original source: - * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. - * https://github.com/bernie-g/geckolib/blob/main/LICENSE - */ -package mod.azure.azurelib.core2.animation; - -import com.google.gson.JsonElement; -import com.google.gson.JsonPrimitive; -import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; - -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import mod.azure.azurelib.core.keyframe.Keyframe; -import mod.azure.azurelib.core.utils.Interpolations; -import mod.azure.azurelib.core2.animation.controller.keyframe.AzAnimationPoint; - -/** - * Functional interface defining an easing function.
      - * {@code value} is the easing value provided from the keyframe's {@link Keyframe#easingArgs()}
      - *
      - * For more information on easings, see:
      - * Easings.net
      - * Cubic-Bezier.com
      - */ -@FunctionalInterface -public interface AzEasingType { - - Map EASING_TYPES = new ConcurrentHashMap<>(64); - - AzEasingType LINEAR = register("linear", register("none", value -> easeIn(AzEasingType::linear))); - - AzEasingType STEP = register("step", value -> easeIn(step(value))); - - AzEasingType EASE_IN_SINE = register("easeinsine", value -> easeIn(AzEasingType::sine)); - - AzEasingType EASE_OUT_SINE = register("easeoutsine", value -> easeOut(AzEasingType::sine)); - - AzEasingType EASE_IN_OUT_SINE = register("easeinoutsine", value -> easeInOut(AzEasingType::sine)); - - AzEasingType EASE_IN_QUAD = register("easeinquad", value -> easeIn(AzEasingType::quadratic)); - - AzEasingType EASE_OUT_QUAD = register("easeoutquad", value -> easeOut(AzEasingType::quadratic)); - - AzEasingType EASE_IN_OUT_QUAD = register("easeinoutquad", value -> easeInOut(AzEasingType::quadratic)); - - AzEasingType EASE_IN_CUBIC = register("easeincubic", value -> easeIn(AzEasingType::cubic)); - - AzEasingType EASE_OUT_CUBIC = register("easeoutcubic", value -> easeOut(AzEasingType::cubic)); - - AzEasingType EASE_IN_OUT_CUBIC = register("easeinoutcubic", value -> easeInOut(AzEasingType::cubic)); - - AzEasingType EASE_IN_QUART = register("easeinquart", value -> easeIn(pow(4))); - - AzEasingType EASE_OUT_QUART = register("easeoutquart", value -> easeOut(pow(4))); - - AzEasingType EASE_IN_OUT_QUART = register("easeinoutquart", value -> easeInOut(pow(4))); - - AzEasingType EASE_IN_QUINT = register("easeinquint", value -> easeIn(pow(4))); - - AzEasingType EASE_OUT_QUINT = register("easeoutquint", value -> easeOut(pow(5))); - - AzEasingType EASE_IN_OUT_QUINT = register("easeinoutquint", value -> easeInOut(pow(5))); - - AzEasingType EASE_IN_EXPO = register("easeinexpo", value -> easeIn(AzEasingType::exp)); - - AzEasingType EASE_OUT_EXPO = register("easeoutexpo", value -> easeOut(AzEasingType::exp)); - - AzEasingType EASE_IN_OUT_EXPO = register("easeinoutexpo", value -> easeInOut(AzEasingType::exp)); - - AzEasingType EASE_IN_CIRC = register("easeincirc", value -> easeIn(AzEasingType::circle)); - - AzEasingType EASE_OUT_CIRC = register("easeoutcirc", value -> easeOut(AzEasingType::circle)); - - AzEasingType EASE_IN_OUT_CIRC = register("easeinoutcirc", value -> easeInOut(AzEasingType::circle)); - - AzEasingType EASE_IN_BACK = register("easeinback", value -> easeIn(back(value))); - - AzEasingType EASE_OUT_BACK = register("easeoutback", value -> easeOut(back(value))); - - AzEasingType EASE_IN_OUT_BACK = register("easeinoutback", value -> easeInOut(back(value))); - - AzEasingType EASE_IN_ELASTIC = register("easeinelastic", value -> easeIn(elastic(value))); - - AzEasingType EASE_OUT_ELASTIC = register("easeoutelastic", value -> easeOut(elastic(value))); - - AzEasingType EASE_IN_OUT_ELASTIC = register("easeinoutelastic", value -> easeInOut(elastic(value))); - - AzEasingType EASE_IN_BOUNCE = register("easeinbounce", value -> easeIn(bounce(value))); - - AzEasingType EASE_OUT_BOUNCE = register("easeoutbounce", value -> easeOut(bounce(value))); - - AzEasingType EASE_IN_OUT_BOUNCE = register("easeinoutbounce", value -> easeInOut(bounce(value))); - - AzEasingType CATMULLROM = register("catmullrom", value -> easeInOut(AzEasingType::catmullRom)); - - static double lerpWithOverride(AzAnimationPoint animationPoint, AzEasingType override) { - AzEasingType easingType = override; - - if (override == null) - easingType = animationPoint.keyFrame() == null ? LINEAR : animationPoint.keyFrame().easingType(); - - return easingType.apply(animationPoint); - } - - /** - * Register an {@code EasingType} with AzureLib for handling animation transitions and value curves.
      - * MUST be called during mod construct
      - * It is recommended you don't call this directly, and instead call it via {@code AzureLibUtil#addCustomEasingType} - * - * @param name The name of the easing type - * @param easingType The {@code EasingType} to associate with the given name - * @return The {@code EasingType} you registered - */ - static AzEasingType register(String name, AzEasingType easingType) { - EASING_TYPES.putIfAbsent(name, easingType); - - return easingType; - } - - /** - * Retrieve an {@code EasingType} instance based on a {@link JsonElement}. Returns one of the default - * {@code EasingTypes} if the name matches, or any other registered {@code EasingType} with a matching name. - * - * @param json The {@code easing} {@link JsonElement} to attempt to parse. - * @return A usable {@code EasingType} instance - */ - static AzEasingType fromJson(JsonElement json) { - if (!(json instanceof JsonPrimitive primitive) || !primitive.isString()) - return LINEAR; - - return fromString(primitive.getAsString().toLowerCase(Locale.ROOT)); - } - - /** - * Get an existing {@code EasingType} from a given string, matching the string to its name. - * - * @param name The name of the easing function - * @return The relevant {@code EasingType}, or {@link AzEasingType#LINEAR} if none match - */ - static AzEasingType fromString(String name) { - return EASING_TYPES.getOrDefault(name, AzEasingType.LINEAR); - } - - /** - * Returns an easing function running linearly. Functionally equivalent to no easing - */ - static Double2DoubleFunction linear(Double2DoubleFunction function) { - return function; - } - - /** - * Performs a Catmull-Rom interpolation, used to get smooth interpolated motion between keyframes.
      - * CatmullRom#position - */ - static double catmullRom(double n) { - return (0.5f * (2.0f * (n + 1) + ((n + 2) - n) * 1 - + (2.0f * n - 5.0f * (n + 1) + 4.0f * (n + 2) - (n + 3)) * 1 - + (3.0f * (n + 1) - n - 3.0f * (n + 2) + (n + 3)) * 1)); - } - - /** - * Returns an easing function running forward in time - */ - static Double2DoubleFunction easeIn(Double2DoubleFunction function) { - return function; - } - - // ---> Easing Transition Type Functions <--- // - - /** - * Returns an easing function running backwards in time - */ - static Double2DoubleFunction easeOut(Double2DoubleFunction function) { - return time -> 1 - function.apply(1 - time); - } - - /** - * Returns an easing function that runs equally both forwards and backwards in time based on the halfway point, - * generating a symmetrical curve.
      - */ - static Double2DoubleFunction easeInOut(Double2DoubleFunction function) { - return time -> { - if (time < 0.5d) - return function.apply(time * 2d) / 2d; - - return 1 - function.apply((1 - time) * 2d) / 2d; - }; - } - - /** - * Returns a stepping function that returns 1 for any input value greater than 0, or otherwise returning 0 - */ - static Double2DoubleFunction stepPositive(Double2DoubleFunction function) { - return n -> n > 0 ? 1 : 0; - } - - /** - * Returns a stepping function that returns 1 for any input value greater than or equal to 0, or otherwise returning - * 0 - */ - static Double2DoubleFunction stepNonNegative(Double2DoubleFunction function) { - return n -> n >= 0 ? 1 : 0; - } - - /** - * A linear function, equivalent to a null-operation.
      - * {@code f(n) = n} - */ - static double linear(double n) { - return n; - } - - // ---> Stepping Functions <--- // - - /** - * A quadratic function, equivalent to the square (n^2) of elapsed time.
      - * {@code f(n) = n^2}
      - * Easings.net#easeInQuad - */ - static double quadratic(double n) { - return n * n; - } - - /** - * A cubic function, equivalent to cube (n^3) of elapsed time.
      - * {@code f(n) = n^3}
      - * Easings.net#easeInCubic - */ - static double cubic(double n) { - return n * n * n; - } - - // ---> Mathematical Functions <--- // - - /** - * A sinusoidal function, equivalent to a sine curve output.
      - * {@code f(n) = 1 - cos(n * π / 2)}
      - * Easings.net#easeInSine - */ - static double sine(double n) { - return 1 - Math.cos(n * Math.PI / 2f); - } - - /** - * A circular function, equivalent to a normally symmetrical curve.
      - * {@code f(n) = 1 - sqrt(1 - n^2)}
      - * Easings.net#easeInCirc - */ - static double circle(double n) { - return 1 - Math.sqrt(1 - n * n); - } - - /** - * An exponential function, equivalent to an exponential curve.
      - * {@code f(n) = 2^(10 * (n - 1))}
      - * Easings.net#easeInExpo - */ - static double exp(double n) { - return Math.pow(2, 10 * (n - 1)); - } - - /** - * An elastic function, equivalent to an oscillating curve.
      - * n defines the elasticity of the output.
      - * {@code f(t) = 1 - (cos(t * π) / 2))^3 * cos(t * n * π)}
      - * Easings.net#easeInElastic - */ - static Double2DoubleFunction elastic(Double n) { - double n2 = n == null ? 1 : n; - - return t -> 1 - Math.pow(Math.cos(t * Math.PI / 2f), 3) * Math.cos(t * n2 * Math.PI); - } - - /** - * A bouncing function, equivalent to a bouncing ball curve.
      - * n defines the bounciness of the output.
      - * Thanks to Waterded#6455 for making the bounce adjustable, and GiantLuigi4#6616 for additional - * cleanup.
      - * Easings.net#easeInBounce - */ - static Double2DoubleFunction bounce(Double n) { - final double n2 = n == null ? 0.5d : n; - - Double2DoubleFunction one = x -> 121f / 16f * x * x; - Double2DoubleFunction two = x -> 121f / 4f * n2 * Math.pow(x - 6f / 11f, 2) + 1 - n2; - Double2DoubleFunction three = x -> 121 * n2 * n2 * Math.pow(x - 9f / 11f, 2) + 1 - n2 * n2; - Double2DoubleFunction four = x -> 484 * n2 * n2 * n2 * Math.pow(x - 10.5f / 11f, 2) + 1 - n2 * n2 * n2; - - return t -> Math.min(Math.min(one.apply(t), two.apply(t)), Math.min(three.apply(t), four.apply(t))); - } - - /** - * A negative elastic function, equivalent to inverting briefly before increasing.
      - * f(t) = t^2 * ((n * 1.70158 + 1) * t - n * 1.70158)
      - * Easings.net#easeInBack - */ - static Double2DoubleFunction back(Double n) { - final double n2 = n == null ? 1.70158d : n * 1.70158d; - - return t -> t * t * ((n2 + 1) * t - n2); - } - - // ---> Easing Curve Functions <--- // - - /** - * An exponential function, equivalent to an exponential curve to the {@code n} root.
      - * f(t) = t^n - * - * @param n The exponent - */ - static Double2DoubleFunction pow(double n) { - return t -> Math.pow(t, n); - } - - /** - * The MIT License (MIT)
      - *
      - * Copyright (c) 2015 Boris Chumichev
      - *
      - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and - * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
      - *
      - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of - * the Software.
      - *
      - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO - * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE.
      - *
      - * Returns a stepped value based on the nearest step to the input value.
      - * The size (grade) of the steps depends on the provided value of {@code n} - **/ - static Double2DoubleFunction step(Double n) { - double n2 = n == null ? 2 : n; - - if (n2 < 2) - throw new IllegalArgumentException("Steps must be >= 2, got: " + n2); - - final int steps = (int) n2; - - return t -> { - double result = 0; - - if (t < 0) - return result; - - double stepLength = (1 / (double) steps); - - if (t > (result = (steps - 1) * stepLength)) - return result; - - int testIndex; - int leftBorderIndex = 0; - int rightBorderIndex = steps - 1; - - while (rightBorderIndex - leftBorderIndex != 1) { - testIndex = leftBorderIndex + (rightBorderIndex - leftBorderIndex) / 2; - - if (t >= testIndex * stepLength) { - leftBorderIndex = testIndex; - } else { - rightBorderIndex = testIndex; - } - } - - return leftBorderIndex * stepLength; - }; - } - - Double2DoubleFunction buildTransformer(Double value); - - default double apply(AzAnimationPoint animationPoint) { - Double easingVariable = null; - - if (animationPoint.keyFrame() != null && animationPoint.keyFrame().easingArgs().size() > 0) - easingVariable = animationPoint.keyFrame().easingArgs().get(0).get(); - - return apply(animationPoint, easingVariable, animationPoint.currentTick() / animationPoint.transitionLength()); - } - - // The MIT license notice below applies to the function step - - default double apply(AzAnimationPoint animationPoint, Double easingValue, double lerpValue) { - if (animationPoint.currentTick() >= animationPoint.transitionLength()) - return (float) animationPoint.animationEndValue(); - - return Interpolations.lerp( - animationPoint.animationStartValue(), - animationPoint.animationEndValue(), - buildTransformer(easingValue).apply(lerpValue) - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframe.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframe.java deleted file mode 100644 index 641cae500..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframe.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * This class is a fork of the matching class found in the Geckolib repository. Original source: - * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. - * https://github.com/bernie-g/geckolib/blob/main/LICENSE - */ -package mod.azure.azurelib.core2.animation; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; - -import java.util.List; -import java.util.Objects; - -import mod.azure.azurelib.core.math.IValue; - -/** - * Animation keyframe data - * - * @param length The length (in ticks) the keyframe lasts for - * @param startValue The value to start the keyframe's transformation with - * @param endValue The value to end the keyframe's transformation with - * @param easingType The {@code EasingType} to use for transformations - * @param easingArgs The arguments to provide to the easing calculation - */ -public record AzKeyframe( - double length, - T startValue, - T endValue, - AzEasingType easingType, - List easingArgs -) { - - public AzKeyframe(double length, T startValue, T endValue) { - this(length, startValue, endValue, AzEasingType.LINEAR); - } - - public AzKeyframe(double length, T startValue, T endValue, AzEasingType easingType) { - this(length, startValue, endValue, easingType, new ObjectArrayList<>(0)); - } - - @Override - public int hashCode() { - return Objects.hash(this.length, this.startValue, this.endValue, this.easingType, this.easingArgs); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - - if (obj == null || getClass() != obj.getClass()) - return false; - - return hashCode() == obj.hashCode(); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeLocation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeLocation.java deleted file mode 100644 index 24dcd966b..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeLocation.java +++ /dev/null @@ -1,19 +0,0 @@ -/** - * This class is a fork of the matching class found in the Geckolib repository. Original source: - * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. - * https://github.com/bernie-g/geckolib/blob/main/LICENSE - */ -package mod.azure.azurelib.core2.animation; - -import mod.azure.azurelib.core.keyframe.Keyframe; - -/** - * A named pair object that stores a {@link Keyframe} and a double representing a temporally placed {@code Keyframe} - * - * @param keyframe The {@code Keyframe} at the tick time - * @param startTick The animation tick time at the start of this {@code Keyframe} - */ -public record AzKeyframeLocation>( - T keyframe, - double startTick -) {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeStack.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeStack.java deleted file mode 100644 index b2c195205..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzKeyframeStack.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * This class is a fork of the matching class found in the Geckolib repository. Original source: - * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. - * https://github.com/bernie-g/geckolib/blob/main/LICENSE - */ -package mod.azure.azurelib.core2.animation; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; - -import java.util.List; - -import mod.azure.azurelib.core.keyframe.Keyframe; - -/** - * Stores a triplet of {@link Keyframe Keyframes} in an ordered stack - */ -public record AzKeyframeStack>( - List xKeyframes, - List yKeyframes, - List zKeyframes -) { - - public AzKeyframeStack() { - this(new ObjectArrayList<>(), new ObjectArrayList<>(), new ObjectArrayList<>()); - } - - public static > AzKeyframeStack from(AzKeyframeStack otherStack) { - return new AzKeyframeStack<>(otherStack.xKeyframes, otherStack.yKeyframes, otherStack.zKeyframes); - } - - public double getLastKeyframeTime() { - double xTime = 0; - double yTime = 0; - double zTime = 0; - - for (T frame : xKeyframes()) { - xTime += frame.length(); - } - - for (T frame : yKeyframes()) { - yTime += frame.length(); - } - - for (T frame : zKeyframes()) { - zTime += frame.length(); - } - - return Math.max(xTime, Math.max(yTime, zTime)); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAnimationPoint.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAnimationPoint.java deleted file mode 100644 index ab65010a1..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAnimationPoint.java +++ /dev/null @@ -1,91 +0,0 @@ -/** - * This class is a fork of the matching class found in the Geckolib repository. Original source: - * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. - * https://github.com/bernie-g/geckolib/blob/main/LICENSE - */ -package mod.azure.azurelib.core2.animation.controller.keyframe; - -import mod.azure.azurelib.core2.animation.AzKeyframe; - -/** - * Animation state record that holds the state of an animation at a given point - */ -public class AzAnimationPoint { - - public static AzAnimationPoint create() { - return new AzAnimationPoint(null, 0, 0, 0, 0); - } - - private AzKeyframe keyFrame; - - private double currentTick; - - private double transitionLength; - - private double animationStartValue; - - private double animationEndValue; - - /** - * @param currentTick The lerped tick time (current tick + partial tick) of the point - * @param transitionLength The length of time (in ticks) that the point should take to transition - * @param animationStartValue The start value to provide to the animation handling system - * @param animationEndValue The end value to provide to the animation handling system - * @param keyFrame The {@code Nullable} Keyframe - */ - public AzAnimationPoint( - AzKeyframe keyFrame, - double currentTick, - double transitionLength, - double animationStartValue, - double animationEndValue - ) { - set(keyFrame, currentTick, transitionLength, animationStartValue, animationEndValue); - } - - public boolean isEmpty() { - return keyFrame == null; - } - - public void set( - AzKeyframe keyFrame, - double currentTick, - double transitionLength, - double animationStartValue, - double animationEndValue - ) { - this.keyFrame = keyFrame; - this.currentTick = currentTick; - this.transitionLength = transitionLength; - this.animationStartValue = animationStartValue; - this.animationEndValue = animationEndValue; - } - - public double animationEndValue() { - return animationEndValue; - } - - public double animationStartValue() { - return animationStartValue; - } - - public double currentTick() { - return currentTick; - } - - public AzKeyframe keyFrame() { - return keyFrame; - } - - public double transitionLength() { - return transitionLength; - } - - @Override - public String toString() { - return "Tick: " + this.currentTick + - " | Transition Length: " + this.transitionLength + - " | Start Value: " + this.animationStartValue + - " | End Value: " + this.animationEndValue; - } -} From 09a2f67bd24c6f4c891ecdb2b693122d85d4e5ab Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 17:42:57 -0500 Subject: [PATCH 073/224] Rewrote animation controller state handling to use a state machine, because... duh. Signed-off-by: = --- .../controller/AzAnimationController.java | 198 +++++------------- .../AzAnimationControllerState.java | 8 - .../keyframe/AzKeyFrameProcessor.java | 92 +++++--- .../controller/state/AzAnimationState.java | 27 +++ .../state/impl/AzAnimationPauseState.java | 24 +++ .../state/impl/AzAnimationPlayState.java | 44 ++++ .../state/impl/AzAnimationStopState.java | 24 +++ .../impl/AzAnimationTransitionState.java | 70 +++++++ .../AzAnimationControllerStateMachine.java | 126 +++++++++++ .../core2/animation/primitive/AzLoopType.java | 3 +- .../mod/azure/azurelib/core2/util/State.java | 10 + .../azurelib/core2/util/StateMachine.java | 33 +++ .../core2/util/StateMachineContext.java | 3 + .../azurelib/fabric/core2/example/Drone.java | 12 +- .../fabric/core2/example/DroneAnimator.java | 7 +- 15 files changed, 498 insertions(+), 183 deletions(-) delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/AzAnimationState.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationStopState.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/util/State.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/util/StateMachine.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/util/StateMachineContext.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index ea1ff6a3e..b5af96f1c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -2,6 +2,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,14 +15,17 @@ import java.util.function.ToDoubleFunction; import mod.azure.azurelib.core.animation.EasingType; -import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; -import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.core2.animation.AzAnimationContext; import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameProcessor; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPauseState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPlayState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationStopState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationTransitionState; +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; import mod.azure.azurelib.core2.animation.primitive.AzAnimation; import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; @@ -36,12 +40,14 @@ public class AzAnimationController { protected static final Logger LOGGER = LoggerFactory.getLogger(AzAnimationController.class); - protected final String name; + private final String name; - protected final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); + private final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); private final AzAnimationQueue animationQueue; + private final AzAnimationControllerStateMachine stateMachine; + private final AzAnimator animator; private final AzBoneAnimationQueueCache boneAnimationQueueCache; @@ -52,14 +58,8 @@ public class AzAnimationController { private final AzKeyFrameProcessor keyFrameProcessor; - protected boolean isJustStarting = false; - protected boolean needsAnimationReload = false; - protected boolean shouldResetTick = false; - - protected boolean justStartedTransition = false; - protected AzKeyFrameCallbacks keyFrameCallbacks; protected AzRawAnimation triggeredAnimation = null; @@ -70,16 +70,12 @@ public class AzAnimationController { protected AzQueuedAnimation currentAnimation; - protected AzAnimationControllerState animationState = AzAnimationControllerState.STOPPED; - protected double tickOffset; protected ToDoubleFunction animationSpeedModifier = obj -> 1d; protected Function overrideEasingTypeFunction = obj -> null; - protected boolean justStopped = true; - // FIXME: There used to be more constructors here. We should bring those back as a builder pattern. /** @@ -99,6 +95,15 @@ public AzAnimationController(AzAnimator animator, String name, int transition this.keyFrameCallbacks = AzKeyFrameCallbacks.noop(); this.keyFrameCallbackManager = new AzKeyFrameCallbackManager<>(this); this.keyFrameProcessor = new AzKeyFrameProcessor<>(this, boneAnimationQueueCache); + + var stateHolder = new AzAnimationControllerStateMachine.StateHolder( + new AzAnimationPlayState<>(), + new AzAnimationPauseState<>(), + new AzAnimationStopState<>(), + new AzAnimationTransitionState<>() + ); + + this.stateMachine = new AzAnimationControllerStateMachine<>(stateHolder, this, animator.context()); } public AzAnimationController setKeyFrameCallbacks(@NotNull AzKeyFrameCallbacks keyFrameCallbacks) { @@ -122,10 +127,6 @@ public AzAnimationController setAnimationSpeedHandler(ToDoubleFunction spe return this; } - public void setJustStarting(boolean justStarting) { - isJustStarting = justStarting; - } - /** * Sets the controller's {@link EasingType} override for animations.
      * By default, the controller will use whatever {@code EasingType} was defined in the animation json @@ -168,28 +169,14 @@ public AzAnimationController triggerableAnim(String name, AzRawAnimation anim return this; } - /** - * Gets the controller's name. - * - * @return The name - */ public String getName() { return name; } - /** - * Gets the currently loaded {@link AzAnimation}. Can be null
      - * An animation returned here does not guarantee it is currently playing, just that it is the currently loaded - * animation for this controller - */ - - public AzQueuedAnimation getCurrentAnimation() { + public @Nullable AzQueuedAnimation getCurrentAnimation() { return currentAnimation; } - /** - * Gets the currently loaded animation's {@link BoneAnimationQueue BoneAnimationQueues}. - */ public Collection getBoneAnimationQueues() { return boneAnimationQueueCache.values(); } @@ -228,23 +215,6 @@ public void forceAnimationReset() { this.needsAnimationReload = true; } - /** - * Tells the controller to stop all animations until told otherwise.
      - * Calling this will prevent the controller from continuing to play the currently loaded animation until either - * {@link AzAnimationController#forceAnimationReset()} is called, or - * {@link AzAnimationController#setAnimation(T, AzRawAnimation)} is called with a different animation - */ - public void stop() { - this.animationState = AzAnimationControllerState.STOPPED; - } - - /** - * Overrides the animation transition time for the controller - */ - public void setTransitionLength(int ticks) { - this.transitionLength = ticks; - } - /** * Checks whether the last animation that was playing on this controller has finished or not.
      * This will return true if the controller has had an animation set previously, and it has finished playing and @@ -253,7 +223,7 @@ public void setTransitionLength(int ticks) { * @return Whether the previous animation finished or not */ public boolean hasAnimationFinished() { - return currentRawAnimation != null && animationState == AzAnimationControllerState.STOPPED; + return currentRawAnimation != null && stateMachine.isStopped(); } /** @@ -314,7 +284,7 @@ public List tryCreateAnimationQueue(T animatable, AzRawAnimat */ public void setAnimation(T animatable, AzRawAnimation rawAnimation) { if (rawAnimation == null || rawAnimation.getAnimationStages().isEmpty()) { - stop(); + stateMachine.stop(); return; } @@ -326,15 +296,13 @@ public void setAnimation(T animatable, AzRawAnimation rawAnimation) { animationQueue.clear(); animationQueue.addAll(animations); this.currentRawAnimation = rawAnimation; - this.shouldResetTick = true; - this.animationState = AzAnimationControllerState.TRANSITIONING; - this.justStartedTransition = true; + stateMachine.transition(); this.needsAnimationReload = false; return; } - stop(); + stateMachine.stop(); } } @@ -354,10 +322,8 @@ public boolean tryTriggerAnimation(String animName) { this.triggeredAnimation = anim; - if (animationState == AzAnimationControllerState.STOPPED) { - this.animationState = AzAnimationControllerState.TRANSITIONING; - this.shouldResetTick = true; - this.justStartedTransition = true; + if (stateMachine.isStopped()) { + stateMachine.transition(); } return true; @@ -366,7 +332,7 @@ public boolean tryTriggerAnimation(String animName) { /** * Handle a given AnimationState, alongside the current triggered animation if applicable */ - protected PlayState handleAnimationState(T animatable) { + private void handleAnimationState(T animatable) { if (triggeredAnimation != null) { if (currentRawAnimation != triggeredAnimation) { this.currentAnimation = null; @@ -375,15 +341,12 @@ protected PlayState handleAnimationState(T animatable) { setAnimation(animatable, triggeredAnimation); if (!hasAnimationFinished()) { - return PlayState.CONTINUE; + return; } this.triggeredAnimation = null; this.needsAnimationReload = true; } - - // TODO: Revisit this. - return PlayState.CONTINUE; } /** @@ -392,73 +355,25 @@ protected PlayState handleAnimationState(T animatable) { */ public void update(AzAnimationContext context) { var animatable = context.animatable(); - var boneCache = context.boneCache(); - var bones = boneCache.getBakedModel().getBonesByName(); - var snapshots = boneCache.getBoneSnapshotsByName(); - var crashWhenCantFindBone = context.config().crashIfBoneMissing(); var timer = context.timer(); var seekTime = timer.getAnimTime(); - setJustStarting(timer.isFirstTick()); - - double adjustedTick = adjustTick(animatable, seekTime); - - if (animationState == AzAnimationControllerState.TRANSITIONING && adjustedTick >= transitionLength) { - this.shouldResetTick = true; - this.animationState = AzAnimationControllerState.RUNNING; - adjustedTick = adjustTick(animatable, seekTime); - } - - PlayState playState = handleAnimationState(animatable); - - if (playState == PlayState.STOP || (currentAnimation == null && animationQueue.isEmpty())) { - this.animationState = AzAnimationControllerState.STOPPED; - this.justStopped = true; - - return; - } - - if (justStartedTransition && (shouldResetTick || justStopped)) { - this.justStopped = false; - adjustedTick = adjustTick(animatable, seekTime); - - if (currentAnimation == null) { - this.animationState = AzAnimationControllerState.TRANSITIONING; - } - } else if (currentAnimation == null) { - this.shouldResetTick = true; - this.animationState = AzAnimationControllerState.TRANSITIONING; - this.justStartedTransition = true; - this.needsAnimationReload = false; - adjustedTick = adjustTick(animatable, seekTime); - } else if (animationState != AzAnimationControllerState.TRANSITIONING) { - this.animationState = AzAnimationControllerState.RUNNING; - } - - if (getAnimationState() == AzAnimationControllerState.RUNNING) { - keyFrameProcessor.runCurrentAnimation(animatable, adjustedTick, seekTime, crashWhenCantFindBone); - var canTransition = transitionLength == 0 && shouldResetTick; - - if (canTransition && animationState == AzAnimationControllerState.TRANSITIONING) { - this.currentAnimation = this.animationQueue.next(); - } - } else if (animationState == AzAnimationControllerState.TRANSITIONING) { - if (adjustedTick == 0 || isJustStarting) { - this.justStartedTransition = false; - this.currentAnimation = animationQueue.next(); - - keyFrameCallbackManager.reset(); + handleAnimationState(animatable); - if (currentAnimation == null) { - return; - } + // Adjust the tick before making any updates. + stateMachine.getContext().adjustedTick = adjustTick(animatable, seekTime); + // Run state machine updates. + stateMachine.update(); - boneSnapshotCache.put(currentAnimation, snapshots.values()); + if (currentAnimation == null) { + if (animationQueue.isEmpty()) { + // If there is no animation to play, stop. + stateMachine.stop(); + return; } - if (currentAnimation != null) { - keyFrameProcessor.transitionFromCurrentAnimation(bones, crashWhenCantFindBone, adjustedTick); - } + this.needsAnimationReload = false; + stateMachine.getContext().adjustedTick = adjustTick(animatable, seekTime); } } @@ -467,34 +382,23 @@ public void update(AzAnimationContext context) { * Is used when starting a new animation, transitioning, and a few other key areas * * @param tick The currently used tick value - * @return 0 if {@link AzAnimationController#shouldResetTick} is set to false, or a + * @return 0 if {@link AzAnimationControllerStateMachine#shouldResetTick()} is set to false, or a * {@link AzAnimationController#animationSpeedModifier} modified value otherwise */ public double adjustTick(T animatable, double tick) { - if (!shouldResetTick) { + if (!stateMachine.shouldResetTick()) { return animationSpeedModifier.applyAsDouble(animatable) * Math.max(tick - tickOffset, 0); } - if (getAnimationState() != AzAnimationControllerState.STOPPED) { + if (!stateMachine.isStopped()) { this.tickOffset = tick; } - this.shouldResetTick = false; + stateMachine.setShouldResetTick(false); return 0; } - /** - * Returns the current state of this controller. - */ - public AzAnimationControllerState getAnimationState() { - return animationState; - } - - public void setAnimationState(AzAnimationControllerState animationState) { - this.animationState = animationState; - } - public AzAnimationQueue getAnimationQueue() { return animationQueue; } @@ -515,16 +419,20 @@ public AzKeyFrameCallbackManager getKeyFrameCallbackManager() { return keyFrameCallbackManager; } - public double getTransitionLength() { - return transitionLength; + public AzKeyFrameProcessor getKeyFrameProcessor() { + return keyFrameProcessor; } - public boolean shouldResetTick() { - return shouldResetTick; + public AzAnimationControllerStateMachine getStateMachine() { + return stateMachine; + } + + public double getTransitionLength() { + return transitionLength; } public void setShouldResetTick(boolean shouldResetTick) { - this.shouldResetTick = shouldResetTick; + stateMachine.setShouldResetTick(shouldResetTick); } public void setCurrentAnimation(AzQueuedAnimation currentAnimation) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java deleted file mode 100644 index 63224aace..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerState.java +++ /dev/null @@ -1,8 +0,0 @@ -package mod.azure.azurelib.core2.animation.controller; - -public enum AzAnimationControllerState { - RUNNING, - TRANSITIONING, - PAUSED, - STOPPED; -} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java index 0f2881b25..0c6a75040 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java @@ -13,7 +13,6 @@ import mod.azure.azurelib.core.molang.MolangQueries; import mod.azure.azurelib.core.object.Axis; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; -import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerState; import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; import mod.azure.azurelib.core2.model.AzBone; @@ -34,32 +33,28 @@ public AzKeyFrameProcessor( /** * Handle the current animation's state modifications and translations * - * @param adjustedTick The controller-adjusted tick for animation purposes * @param seekTime The lerped tick (current tick + partial tick) * @param crashWhenCantFindBone Whether the controller should throw an exception when unable to find the required * bone, or continue with the remaining bones */ - public void runCurrentAnimation( - T animatable, - double adjustedTick, - double seekTime, - boolean crashWhenCantFindBone - ) { + public void runCurrentAnimation(T animatable, double seekTime, boolean crashWhenCantFindBone) { var animationQueue = animationController.getAnimationQueue(); - var animationState = animationController.getAnimationState(); + var animationState = animationController.getStateMachine().getState(); var currentAnimation = animationController.getCurrentAnimation(); var keyFrameCallbackManager = animationController.getKeyFrameCallbackManager(); + var stateMachine = animationController.getStateMachine(); + var stateMachineContext = stateMachine.getContext(); var transitionLength = animationController.getTransitionLength(); - if (adjustedTick >= currentAnimation.animation().length()) { + if (stateMachineContext.adjustedTick >= currentAnimation.animation().length()) { if ( currentAnimation.loopType() .shouldPlayAgain(animatable, animationController, currentAnimation.animation()) ) { - if (animationState != AzAnimationControllerState.PAUSED) { + if (!stateMachine.isPaused()) { animationController.setShouldResetTick(true); - adjustedTick = animationController.adjustTick(animatable, seekTime); + stateMachineContext.adjustedTick = animationController.adjustTick(animatable, seekTime); keyFrameCallbackManager.reset(); } } else { @@ -68,18 +63,18 @@ public void runCurrentAnimation( keyFrameCallbackManager.reset(); if (nextAnimation == null) { - animationController.setAnimationState(AzAnimationControllerState.STOPPED); + stateMachine.stop(); return; } else { - animationController.setAnimationState(AzAnimationControllerState.TRANSITIONING); + stateMachine.transition(); animationController.setShouldResetTick(true); animationController.setCurrentAnimation(nextAnimation); } } } - final double finalAdjustedTick = adjustedTick; + final double finalAdjustedTick = stateMachineContext.adjustedTick; MolangParser.INSTANCE.setMemoizedValue(MolangQueries.ANIM_TIME, () -> finalAdjustedTick / 20d); @@ -99,32 +94,77 @@ public void runCurrentAnimation( if (!rotationKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addRotations( - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) + getAnimationPointAtTick( + rotationKeyFrames.xKeyframes(), + stateMachineContext.adjustedTick, + true, + Axis.X + ), + getAnimationPointAtTick( + rotationKeyFrames.yKeyframes(), + stateMachineContext.adjustedTick, + true, + Axis.Y + ), + getAnimationPointAtTick( + rotationKeyFrames.zKeyframes(), + stateMachineContext.adjustedTick, + true, + Axis.Z + ) ); } if (!positionKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addPositions( - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + getAnimationPointAtTick( + positionKeyFrames.xKeyframes(), + stateMachineContext.adjustedTick, + false, + Axis.X + ), + getAnimationPointAtTick( + positionKeyFrames.yKeyframes(), + stateMachineContext.adjustedTick, + false, + Axis.Y + ), + getAnimationPointAtTick( + positionKeyFrames.zKeyframes(), + stateMachineContext.adjustedTick, + false, + Axis.Z + ) ); } if (!scaleKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addScales( - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + getAnimationPointAtTick( + scaleKeyFrames.xKeyframes(), + stateMachineContext.adjustedTick, + false, + Axis.X + ), + getAnimationPointAtTick( + scaleKeyFrames.yKeyframes(), + stateMachineContext.adjustedTick, + false, + Axis.Y + ), + getAnimationPointAtTick( + scaleKeyFrames.zKeyframes(), + stateMachineContext.adjustedTick, + false, + Axis.Z + ) ); } } - adjustedTick += transitionLength; + stateMachineContext.adjustedTick += transitionLength; - keyFrameCallbackManager.handle(animatable, adjustedTick); + keyFrameCallbackManager.handle(animatable, stateMachineContext.adjustedTick); } public void transitionFromCurrentAnimation( diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/AzAnimationState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/AzAnimationState.java new file mode 100644 index 000000000..34e71f7e3 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/AzAnimationState.java @@ -0,0 +1,27 @@ +package mod.azure.azurelib.core2.animation.controller.state; + +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; +import mod.azure.azurelib.core2.util.State; + +public abstract class AzAnimationState implements State> { + + private boolean isActive; + + protected AzAnimationState() { + this.isActive = false; + } + + @Override + public void onEnter(AzAnimationControllerStateMachine.Context context) { + this.isActive = true; + } + + public boolean isActive() { + return isActive; + } + + @Override + public void onExit(AzAnimationControllerStateMachine.Context context) { + this.isActive = false; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java new file mode 100644 index 000000000..87bcf5b5a --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java @@ -0,0 +1,24 @@ +package mod.azure.azurelib.core2.animation.controller.state.impl; + +import mod.azure.azurelib.core2.animation.controller.state.AzAnimationState; +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; + +public final class AzAnimationPauseState extends AzAnimationState { + + public AzAnimationPauseState() {} + + @Override + public void onEnter(AzAnimationControllerStateMachine.Context context) { + super.onEnter(context); + } + + @Override + public void onUpdate(AzAnimationControllerStateMachine.Context context) { + // Pause state does not need to do anything. + } + + @Override + public void onExit(AzAnimationControllerStateMachine.Context context) { + super.onExit(context); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java new file mode 100644 index 000000000..b61e5c358 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java @@ -0,0 +1,44 @@ +package mod.azure.azurelib.core2.animation.controller.state.impl; + +import mod.azure.azurelib.core2.animation.controller.state.AzAnimationState; +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; + +public final class AzAnimationPlayState extends AzAnimationState { + + public AzAnimationPlayState() {} + + @Override + public void onEnter(AzAnimationControllerStateMachine.Context context) { + super.onEnter(context); + } + + @Override + public void onUpdate(AzAnimationControllerStateMachine.Context context) { + var controller = context.getAnimationController(); + var keyFrameProcessor = controller.getKeyFrameProcessor(); + var animContext = context.getAnimationContext(); + var timer = animContext.timer(); + var animatable = animContext.animatable(); + var animTime = timer.getAnimTime(); + var crashWhenCantFindBone = animContext.config().crashIfBoneMissing(); + + var stateMachine = context.getStateMachine(); + + // Run the current animation. + keyFrameProcessor.runCurrentAnimation(animatable, animTime, crashWhenCantFindBone); + + // Can we transition? + var canTransition = controller.getTransitionLength() == 0 && stateMachine.shouldResetTick(); + + // TODO: Remove the transition state check here, potentially. + if (canTransition && stateMachine.isTransitioning()) { + // Then transition. + controller.setCurrentAnimation(controller.getAnimationQueue().next()); + } + } + + @Override + public void onExit(AzAnimationControllerStateMachine.Context context) { + super.onExit(context); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationStopState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationStopState.java new file mode 100644 index 000000000..e2c81211c --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationStopState.java @@ -0,0 +1,24 @@ +package mod.azure.azurelib.core2.animation.controller.state.impl; + +import mod.azure.azurelib.core2.animation.controller.state.AzAnimationState; +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; + +public final class AzAnimationStopState extends AzAnimationState { + + public AzAnimationStopState() {} + + @Override + public void onEnter(AzAnimationControllerStateMachine.Context context) { + super.onEnter(context); + } + + @Override + public void onUpdate(AzAnimationControllerStateMachine.Context context) { + // Stop state does not need to do anything. + } + + @Override + public void onExit(AzAnimationControllerStateMachine.Context context) { + super.onExit(context); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java new file mode 100644 index 000000000..2c99afce4 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java @@ -0,0 +1,70 @@ +package mod.azure.azurelib.core2.animation.controller.state.impl; + +import mod.azure.azurelib.core2.animation.controller.state.AzAnimationState; +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; + +public final class AzAnimationTransitionState extends AzAnimationState { + + public AzAnimationTransitionState() {} + + @Override + public void onEnter(AzAnimationControllerStateMachine.Context context) { + super.onEnter(context); + context.getStateMachine().setShouldResetTick(true); + } + + @Override + public void onUpdate(AzAnimationControllerStateMachine.Context context) { + var controller = context.getAnimationController(); + var boneSnapshotCache = controller.getBoneSnapshotCache(); + var animContext = context.getAnimationContext(); + var timer = animContext.timer(); + var animatable = animContext.animatable(); + var animTime = timer.getAnimTime(); + + var stateMachine = context.getStateMachine(); + var boneCache = animContext.boneCache(); + + if (context.adjustedTick >= controller.getTransitionLength()) { + // If we've exceeded the amount of time we should be transitioning, then switch to play state. + + stateMachine.setShouldResetTick(true); + stateMachine.play(); + context.adjustedTick = controller.adjustTick(animatable, animTime); + return; + } + + if (stateMachine.shouldResetTick() /* || justStopped */) { + // TODO: + context.adjustedTick = controller.adjustTick(animatable, animTime); + } + + if (context.adjustedTick == 0 || stateMachine.isJustStarting()) { + // FIXME: POTENTIAL REGRESSION + // this.justStartedTransition = false; + controller.setCurrentAnimation(controller.getAnimationQueue().next()); + + controller.getKeyFrameCallbackManager().reset(); + + if (controller.getCurrentAnimation() == null) { + return; + } + + var snapshots = boneCache.getBoneSnapshotsByName(); + + boneSnapshotCache.put(controller.getCurrentAnimation(), snapshots.values()); + } + + if (controller.getCurrentAnimation() != null) { + var bones = boneCache.getBakedModel().getBonesByName(); + var crashWhenCantFindBone = animContext.config().crashIfBoneMissing(); + var keyFrameProcessor = controller.getKeyFrameProcessor(); + keyFrameProcessor.transitionFromCurrentAnimation(bones, crashWhenCantFindBone, context.adjustedTick); + } + } + + @Override + public void onExit(AzAnimationControllerStateMachine.Context context) { + super.onExit(context); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java new file mode 100644 index 000000000..d4da36b83 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java @@ -0,0 +1,126 @@ +package mod.azure.azurelib.core2.animation.controller.state.machine; + +import mod.azure.azurelib.core2.animation.AzAnimationContext; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.state.AzAnimationState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPauseState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPlayState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationStopState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationTransitionState; +import mod.azure.azurelib.core2.util.StateMachine; +import mod.azure.azurelib.core2.util.StateMachineContext; + +public class AzAnimationControllerStateMachine extends StateMachine, AzAnimationState> { + + private final StateHolder stateHolder; + + private boolean isJustStarting; + + private boolean shouldResetTick = false; + + public AzAnimationControllerStateMachine( + StateHolder stateHolder, + AzAnimationController animationController, + AzAnimationContext animationContext + ) { + super(stateHolder.stopState()); + this.stateHolder = stateHolder; + getContext().stateMachine = this; + getContext().animationController = animationController; + getContext().animationContext = animationContext; + } + + @Override + public Context createContext() { + return new Context<>(); + } + + public void update() { + super.update(getContext()); + + var animContext = getContext().animationContext; + var timer = animContext.timer(); + + setJustStarting(timer.isFirstTick()); + } + + public void pause() { + setState(stateHolder.pauseState); + } + + public void play() { + setState(stateHolder.playState); + } + + public void transition() { + setState(stateHolder.transitionState); + } + + public void stop() { + this.setState(stateHolder.stopState); + } + + public boolean isPlaying() { + return getState() == stateHolder.playState; + } + + public boolean isPaused() { + return getState() == stateHolder.pauseState; + } + + public boolean isStopped() { + return getState() == stateHolder.stopState; + } + + public boolean isTransitioning() { + return getState() == stateHolder.transitionState; + } + + public void setShouldResetTick(boolean shouldResetTick) { + this.shouldResetTick = shouldResetTick; + } + + public boolean shouldResetTick() { + return shouldResetTick; + } + + public boolean isJustStarting() { + return isJustStarting; + } + + public void setJustStarting(boolean justStarting) { + isJustStarting = justStarting; + } + + public record StateHolder( + AzAnimationPlayState playState, + AzAnimationPauseState pauseState, + AzAnimationStopState stopState, + AzAnimationTransitionState transitionState + ) {} + + public static class Context implements StateMachineContext { + + private AzAnimationContext animationContext; + + private AzAnimationController animationController; + + private AzAnimationControllerStateMachine stateMachine; + + public double adjustedTick; + + private Context() {} + + public AzAnimationContext getAnimationContext() { + return animationContext; + } + + public AzAnimationController getAnimationController() { + return animationController; + } + + public AzAnimationControllerStateMachine getStateMachine() { + return stateMachine; + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java index 818b6fa67..bbad2a290 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java @@ -6,7 +6,6 @@ import java.util.concurrent.ConcurrentHashMap; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; -import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerState; /** * Loop type functional interface to define post-play handling for a given animation.
      @@ -27,7 +26,7 @@ public interface AzLoopType { ); AzLoopType HOLD_ON_LAST_FRAME = register("hold_on_last_frame", (animatable, controller, currentAnimation) -> { - controller.setAnimationState(AzAnimationControllerState.PAUSED); + // controller.setState(DEPRECATED_AzAnimationPlayState.PAUSED); return true; }); diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/State.java b/common/src/main/java/mod/azure/azurelib/core2/util/State.java new file mode 100644 index 000000000..32f9e496a --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/State.java @@ -0,0 +1,10 @@ +package mod.azure.azurelib.core2.util; + +public interface State { + + void onEnter(C context); + + void onUpdate(C context); + + void onExit(C context); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/StateMachine.java b/common/src/main/java/mod/azure/azurelib/core2/util/StateMachine.java new file mode 100644 index 000000000..99522a2e5 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/StateMachine.java @@ -0,0 +1,33 @@ +package mod.azure.azurelib.core2.util; + +public abstract class StateMachine> { + + private final C reusableContext; + + private T state; + + public StateMachine(T initialState) { + this.state = initialState; + this.reusableContext = createContext(); + } + + public abstract C createContext(); + + public void update(C context) { + state.onUpdate(context); + } + + public C getContext() { + return reusableContext; + } + + public T getState() { + return state; + } + + public void setState(T newState) { + state.onExit(reusableContext); + this.state = newState; + newState.onEnter(reusableContext); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/StateMachineContext.java b/common/src/main/java/mod/azure/azurelib/core2/util/StateMachineContext.java new file mode 100644 index 000000000..9fab72c87 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/StateMachineContext.java @@ -0,0 +1,3 @@ +package mod.azure.azurelib.core2.util; + +public interface StateMachineContext {} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java index 5baf980b7..fb115f690 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java @@ -15,11 +15,21 @@ public Drone(EntityType entityType, Level level) { this.animationDispatcher = new AzAnimationDispatcher<>(this); } + private boolean walk; + public void tick() { super.tick(); if (this.level().isClientSide) { - animationDispatcher.dispatchFromClient("base_controller", "animation.idle"); + if (this.tickCount % 40 == 0) { + walk = !walk; + } + + var animName = walk + ? "animation.walk" + : "animation.idle"; + + animationDispatcher.dispatchFromClient("base_controller", animName); } } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java index ec7674283..8df263d8e 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java @@ -16,8 +16,12 @@ public class DroneAnimator extends AzEntityAnimator { private static final String IDLE_ANIMATION_NAME = "animation.idle"; + private static final String WALK_ANIMATION_NAME = "animation.walk"; + private static final AzRawAnimation IDLE_ANIMATION = AzRawAnimation.begin().thenLoop(IDLE_ANIMATION_NAME); + private static final AzRawAnimation WALK_ANIMATION = AzRawAnimation.begin().thenLoop(WALK_ANIMATION_NAME); + public DroneAnimator() { super(AzAnimatorConfig.defaultConfig()); } @@ -25,8 +29,9 @@ public DroneAnimator() { @Override public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( - new AzAnimationController<>(this, "base_controller", 0) + new AzAnimationController<>(this, "base_controller", 5) .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) + .triggerableAnim(WALK_ANIMATION_NAME, WALK_ANIMATION) ); } From 92a2ec902695de1d34009f5b51e28e99dda55750 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 17:58:08 -0500 Subject: [PATCH 074/224] Fixed regression in HOLD_ON_LAST_FRAME state pausing. Signed-off-by: = --- .../azure/azurelib/core2/animation/primitive/AzLoopType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java index bbad2a290..9d564eb61 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java @@ -26,7 +26,7 @@ public interface AzLoopType { ); AzLoopType HOLD_ON_LAST_FRAME = register("hold_on_last_frame", (animatable, controller, currentAnimation) -> { - // controller.setState(DEPRECATED_AzAnimationPlayState.PAUSED); + controller.getStateMachine().pause(); return true; }); From 503816ae51b77f9105a4889b7e52edc414179817 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 14 Dec 2024 18:02:32 -0500 Subject: [PATCH 075/224] Port color changes from a geckolib pr that was left to die --- .../mod/azure/azurelib/core/object/Color.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/common/src/main/java/mod/azure/azurelib/core/object/Color.java b/common/src/main/java/mod/azure/azurelib/core/object/Color.java index 969544043..cb5ba31b3 100644 --- a/common/src/main/java/mod/azure/azurelib/core/object/Color.java +++ b/common/src/main/java/mod/azure/azurelib/core/object/Color.java @@ -4,11 +4,43 @@ */ package mod.azure.azurelib.core.object; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import java.util.List; + /** * Color holder object for storing a packed int argb value. */ public record Color(int argbInt) { + public static Codec RGBA_CODEC = RecordCodecBuilder.create((instance) -> { // float? + return instance.group( + Codec.INT.fieldOf("r").forGetter(Color::getRed), + Codec.INT.fieldOf("g").forGetter(Color::getGreen), + Codec.INT.fieldOf("b").forGetter(Color::getBlue), + Codec.INT.fieldOf("a").orElse(255).forGetter(Color::getAlpha) + ).apply(instance, Color::ofRGBA); + }); + + public static Codec STRING_CODEC = Codec.STRING.comapFlatMap( + Color::tryHexString, + Color::toString + ); + + public static final Codec INT_CODEC = Codec.INT.xmap( + Color::new, + color -> color.argbInt + ); + + public static final Codec CODEC = Codec.either(STRING_CODEC, RGBA_CODEC) + .comapFlatMap( + either -> either.map(DataResult::success, DataResult::success), + Either::left + ); + public static final Color WHITE = new Color(0xFFFFFFFF); public static final Color LIGHT_GRAY = new Color(0xFFC0C0C0); @@ -136,6 +168,34 @@ public static int HSBtoARGB(float hue, float saturation, float brightness) { return 0xFF000000 | (r << 16) | (g << 8) | b; } + /** + * Creates a new {@code Color} instance from a hexadecimal color + */ + public static Color ofHexString(String hexColor) { + if (hexColor.startsWith("#")) { + hexColor = hexColor.substring(1); + } + if (hexColor.length() == 3) { + StringBuilder expanded = new StringBuilder(); + for (char c : hexColor.toCharArray()) { + expanded.append(c).append(c); + } + hexColor = expanded.toString(); + } + return new Color(Integer.parseInt(hexColor, 16)); + } + + /** + * Creates a new {@code Color} instance from a hexadecimal color + */ + public static DataResult tryHexString(String hexColor) { + try { + return DataResult.success(ofHexString(hexColor)); + } catch (Exception err) { + return DataResult.error(err::toString); + } + } + public int getColor() { return this.argbInt; } @@ -172,6 +232,10 @@ public float getBlueFloat() { return getBlue() / 255f; } + public List getList() { + return List.of(getRed(), getGreen(), getBlue(), getAlpha()); + } + /** * Returns a brighter variant of the same color.
      * From 85167328c9e868f73c301907acbc468e35830d78 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 14 Dec 2024 18:03:10 -0500 Subject: [PATCH 076/224] Port UV Face Rotation support --- .../internal/common/cache/object/GeoQuad.java | 14 +++++--- .../cache/texture/GeoGlowingTextureMeta.java | 4 +-- .../common/loading/json/raw/FaceUV.java | 35 +++++++++++++++++-- .../loading/object/BakedModelFactory.java | 2 ++ .../model/factory/AzBakedModelFactory.java | 2 ++ 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java index 2a432f4b3..154aba466 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java @@ -8,6 +8,8 @@ import net.minecraft.core.Direction; import org.joml.Vector3f; +import mod.azure.azurelib.common.internal.common.loading.json.raw.FaceUV; + /** * Quad data holder * @@ -23,6 +25,7 @@ public static GeoQuad build( GeoVertex[] vertices, double[] uvCoords, double[] uvSize, + FaceUV.Rotation uvRotation, float texWidth, float texHeight, boolean mirror, @@ -34,6 +37,7 @@ public static GeoQuad build( (float) uvCoords[1], (float) uvSize[0], (float) uvSize[1], + uvRotation, texWidth, texHeight, mirror, @@ -47,6 +51,7 @@ public static GeoQuad build( float v, float uSize, float vSize, + FaceUV.Rotation uvRotation, float texWidth, float texHeight, boolean mirror, @@ -66,10 +71,11 @@ public static GeoQuad build( normal.mul(-1, 1, 1); } - vertices[0] = vertices[0].withUVs(u, v); - vertices[1] = vertices[1].withUVs(uWidth, v); - vertices[2] = vertices[2].withUVs(uWidth, vHeight); - vertices[3] = vertices[3].withUVs(u, vHeight); + float[] uvs = uvRotation.rotateUvs(u, v, uWidth, vHeight); + vertices[0] = vertices[0].withUVs(uvs[0], uvs[1]); + vertices[1] = vertices[1].withUVs(uvs[2], uvs[3]); + vertices[2] = vertices[2].withUVs(uvs[4], uvs[5]); + vertices[3] = vertices[3].withUVs(uvs[6], uvs[7]); return new GeoQuad(vertices, normal, direction); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java index 99c633be9..87db2d28b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java @@ -122,9 +122,9 @@ public void createImageMask(NativeImage originalImage, NativeImage newImage) { if (pixel.alpha > 0) color = FastColor.ABGR32.color( pixel.alpha, - FastColor.ABGR32.blue(color), + FastColor.ABGR32.red(color), FastColor.ABGR32.green(color), - FastColor.ABGR32.red(color) + FastColor.ABGR32.blue(color) ); newImage.setPixelRGBA(pixel.x, pixel.y, color); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java index a62ec79ef..370c4f940 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java @@ -9,8 +9,10 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import net.minecraft.util.GsonHelper; +import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.util.JsonUtil; /** @@ -19,7 +21,8 @@ public record FaceUV( @Nullable String materialInstance, double[] uv, - double[] uvSize + double[] uvSize, + Rotation uvRotation ) { public static JsonDeserializer deserializer() throws JsonParseException { @@ -28,8 +31,36 @@ public static JsonDeserializer deserializer() throws JsonParseException String materialInstance = GsonHelper.getAsString(obj, "material_instance", null); double[] uv = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "uv", null)); double[] uvSize = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "uv_size", null)); + Rotation uvRotation = Rotation.fromValue(GsonHelper.getAsInt(obj, "uv_rotation", 0)); - return new FaceUV(materialInstance, uv, uvSize); + return new FaceUV(materialInstance, uv, uvSize, uvRotation); }; } + + public enum Rotation { + + NONE, + CLOCKWISE_90, + CLOCKWISE_180, + CLOCKWISE_270; + + public static Rotation fromValue(int value) throws JsonParseException { + try { + return Rotation.values()[(value % 360) / 90]; + } catch (Exception e) { + AzureLib.LOGGER.error("Invalid Face UV rotation: " + value); + + return fromValue(Mth.floor(Math.abs(value) / 90f) * 90); + } + } + + public float[] rotateUvs(float u, float v, float uWidth, float vHeight) { + return switch (this) { + case NONE -> new float[] { u, v, uWidth, v, uWidth, vHeight, u, vHeight }; + case CLOCKWISE_90 -> new float[] { uWidth, v, uWidth, vHeight, u, vHeight, u, v }; + case CLOCKWISE_180 -> new float[] { uWidth, vHeight, u, vHeight, u, v, uWidth, v }; + case CLOCKWISE_270 -> new float[] { u, vHeight, u, v, uWidth, v, uWidth, vHeight }; + }; + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java index bea1c1372..59db763ee 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java @@ -117,6 +117,7 @@ default GeoQuad buildQuad( vertices.verticesForQuad(direction, false, mirror || cube.mirror() == Boolean.TRUE), faceUV.uv(), faceUV.uvSize(), + faceUV.uvRotation(), textureWidth, textureHeight, mirror, @@ -158,6 +159,7 @@ default GeoQuad buildQuad( vertices.verticesForQuad(direction, true, mirror || cube.mirror() == Boolean.TRUE), uvData[0], uvData[1], + FaceUV.Rotation.NONE, textureWidth, textureHeight, mirror, diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java index 5573ff13f..d2b0743ca 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java @@ -91,6 +91,7 @@ public GeoQuad buildQuad( vertices.verticesForQuad(direction, false, mirror || cube.mirror() == Boolean.TRUE), faceUV.uv(), faceUV.uvSize(), + faceUV.uvRotation(), textureWidth, textureHeight, mirror, @@ -132,6 +133,7 @@ public GeoQuad buildQuad( vertices.verticesForQuad(direction, true, mirror || cube.mirror() == Boolean.TRUE), uvData[0], uvData[1], + FaceUV.Rotation.NONE, textureWidth, textureHeight, mirror, From a2d9233a813bd8b6d962d39f3dfd2f8f54c28f8a Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 20:27:35 -0500 Subject: [PATCH 077/224] Refactor. Signed-off-by: = --- .../state/machine/AzAnimationControllerStateMachine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java index d4da36b83..c2d5e1670 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java @@ -57,7 +57,7 @@ public void transition() { } public void stop() { - this.setState(stateHolder.stopState); + setState(stateHolder.stopState); } public boolean isPlaying() { From e93f92640eb72bd659e56d31a2cd26ea99d3a5b2 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 20:28:00 -0500 Subject: [PATCH 078/224] Remove unnecessary code in play state. Signed-off-by: = --- .../state/impl/AzAnimationPlayState.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java index b61e5c358..af71bde89 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java @@ -15,26 +15,16 @@ public void onEnter(AzAnimationControllerStateMachine.Context context) { @Override public void onUpdate(AzAnimationControllerStateMachine.Context context) { var controller = context.getAnimationController(); - var keyFrameProcessor = controller.getKeyFrameProcessor(); + var keyFrameProcessor = controller.getKeyFrameManager().getKeyFrameProcessor(); var animContext = context.getAnimationContext(); var timer = animContext.timer(); + var animatable = animContext.animatable(); var animTime = timer.getAnimTime(); var crashWhenCantFindBone = animContext.config().crashIfBoneMissing(); - var stateMachine = context.getStateMachine(); - // Run the current animation. keyFrameProcessor.runCurrentAnimation(animatable, animTime, crashWhenCantFindBone); - - // Can we transition? - var canTransition = controller.getTransitionLength() == 0 && stateMachine.shouldResetTick(); - - // TODO: Remove the transition state check here, potentially. - if (canTransition && stateMachine.isTransitioning()) { - // Then transition. - controller.setCurrentAnimation(controller.getAnimationQueue().next()); - } } @Override From f27acdc32c27d33a2e27b8360948a1c8129e9689 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 20:36:03 -0500 Subject: [PATCH 079/224] Fixed transition state switching to the play state too quickly when transition length is 0. Signed-off-by: = --- .../impl/AzAnimationTransitionState.java | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java index 2c99afce4..8c21310a0 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java @@ -25,26 +25,14 @@ public void onUpdate(AzAnimationControllerStateMachine.Context context) { var stateMachine = context.getStateMachine(); var boneCache = animContext.boneCache(); - if (context.adjustedTick >= controller.getTransitionLength()) { - // If we've exceeded the amount of time we should be transitioning, then switch to play state. - - stateMachine.setShouldResetTick(true); - stateMachine.play(); - context.adjustedTick = controller.adjustTick(animatable, animTime); - return; - } - - if (stateMachine.shouldResetTick() /* || justStopped */) { - // TODO: + if (stateMachine.shouldResetTick()) { context.adjustedTick = controller.adjustTick(animatable, animTime); } if (context.adjustedTick == 0 || stateMachine.isJustStarting()) { - // FIXME: POTENTIAL REGRESSION - // this.justStartedTransition = false; controller.setCurrentAnimation(controller.getAnimationQueue().next()); - controller.getKeyFrameCallbackManager().reset(); + controller.getKeyFrameManager().keyFrameCallbackHandler().reset(); if (controller.getCurrentAnimation() == null) { return; @@ -55,10 +43,18 @@ public void onUpdate(AzAnimationControllerStateMachine.Context context) { boneSnapshotCache.put(controller.getCurrentAnimation(), snapshots.values()); } + if (context.adjustedTick >= controller.getTransitionLength()) { + // If we've exceeded the amount of time we should be transitioning, then switch to play state. + stateMachine.setShouldResetTick(true); + stateMachine.play(); + context.adjustedTick = controller.adjustTick(animatable, animTime); + return; + } + if (controller.getCurrentAnimation() != null) { var bones = boneCache.getBakedModel().getBonesByName(); var crashWhenCantFindBone = animContext.config().crashIfBoneMissing(); - var keyFrameProcessor = controller.getKeyFrameProcessor(); + var keyFrameProcessor = controller.getKeyFrameManager().getKeyFrameProcessor(); keyFrameProcessor.transitionFromCurrentAnimation(bones, crashWhenCantFindBone, context.adjustedTick); } } From e76d59448247bb47f6a4e93810e0afaa26ca0f29 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 20:36:40 -0500 Subject: [PATCH 080/224] Refactored AzAnimationController to use a builder pattern. Signed-off-by: = --- .../controller/AzAnimationController.java | 201 +++++------------- .../AzAnimationControllerBuilder.java | 87 ++++++++ ...er.java => AzKeyFrameCallbackHandler.java} | 22 +- .../keyframe/AzKeyFrameManager.java | 28 +++ .../keyframe/AzKeyFrameProcessor.java | 9 +- .../fabric/core2/example/DroneAnimator.java | 4 +- .../core2/example/FacehuggerAnimator.java | 3 +- .../example/azure/DoomHunterAnimator.java | 3 +- 8 files changed, 193 insertions(+), 164 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerBuilder.java rename common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/{AzKeyFrameCallbackManager.java => AzKeyFrameCallbackHandler.java} (88%) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index b5af96f1c..5a79e1db5 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -1,7 +1,5 @@ package mod.azure.azurelib.core2.animation.controller; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,9 +16,8 @@ import mod.azure.azurelib.core2.animation.AzAnimationContext; import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; -import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbackManager; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; -import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameProcessor; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameManager; import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPauseState; import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPlayState; import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationStopState; @@ -40,9 +37,13 @@ public class AzAnimationController { protected static final Logger LOGGER = LoggerFactory.getLogger(AzAnimationController.class); + public static AzAnimationControllerBuilder builder(AzAnimator animator, String name) { + return new AzAnimationControllerBuilder<>(animator, name); + } + private final String name; - private final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); + private final ToDoubleFunction animationSpeedModifier; private final AzAnimationQueue animationQueue; @@ -54,29 +55,23 @@ public class AzAnimationController { private final AzBoneSnapshotCache boneSnapshotCache; - private final AzKeyFrameCallbackManager keyFrameCallbackManager; + private final AzKeyFrameManager keyFrameManager; - private final AzKeyFrameProcessor keyFrameProcessor; + private final Function overrideEasingTypeFunction; - protected boolean needsAnimationReload = false; + private final double transitionLength; - protected AzKeyFrameCallbacks keyFrameCallbacks; + private final Map triggerableAnimations; - protected AzRawAnimation triggeredAnimation = null; - - protected double transitionLength; + protected AzQueuedAnimation currentAnimation; protected AzRawAnimation currentRawAnimation; - protected AzQueuedAnimation currentAnimation; + protected boolean needsAnimationReload = false; protected double tickOffset; - protected ToDoubleFunction animationSpeedModifier = obj -> 1d; - - protected Function overrideEasingTypeFunction = obj -> null; - - // FIXME: There used to be more constructors here. We should bring those back as a builder pattern. + protected AzRawAnimation triggeredAnimation = null; /** * Instantiates a new {@code AnimationController}.
      @@ -85,16 +80,26 @@ public class AzAnimationController { * @param transitionTickTime The amount of time (in ticks) that the controller should take to transition * between animations. Lerping is automatically applied where possible */ - public AzAnimationController(AzAnimator animator, String name, int transitionTickTime) { - this.animator = animator; + AzAnimationController( + String name, + AzAnimator animator, + int transitionTickTime, + ToDoubleFunction animationSpeedModifier, + AzKeyFrameCallbacks keyFrameCallbacks, + Function overrideEasingTypeFunction, + Map triggerableAnimations + ) { this.name = name; + this.animator = animator; this.transitionLength = transitionTickTime; + this.animationSpeedModifier = animationSpeedModifier; + this.overrideEasingTypeFunction = overrideEasingTypeFunction; + this.triggerableAnimations = triggerableAnimations; + this.animationQueue = new AzAnimationQueue(); this.boneAnimationQueueCache = new AzBoneAnimationQueueCache(animator.context().boneCache()); this.boneSnapshotCache = new AzBoneSnapshotCache(); - this.keyFrameCallbacks = AzKeyFrameCallbacks.noop(); - this.keyFrameCallbackManager = new AzKeyFrameCallbackManager<>(this); - this.keyFrameProcessor = new AzKeyFrameProcessor<>(this, boneAnimationQueueCache); + this.keyFrameManager = new AzKeyFrameManager<>(this, boneAnimationQueueCache, keyFrameCallbacks); var stateHolder = new AzAnimationControllerStateMachine.StateHolder( new AzAnimationPlayState<>(), @@ -106,104 +111,17 @@ public AzAnimationController(AzAnimator animator, String name, int transition this.stateMachine = new AzAnimationControllerStateMachine<>(stateHolder, this, animator.context()); } - public AzAnimationController setKeyFrameCallbacks(@NotNull AzKeyFrameCallbacks keyFrameCallbacks) { - Objects.requireNonNull(keyFrameCallbacks); - this.keyFrameCallbacks = keyFrameCallbacks; - return this; - } - - /** - * Applies the given modifier function to this controller, for handling the speed that the controller should play - * its animations at.
      - * An output value of 1 is considered neutral, with 2 playing an animation twice as fast, 0.5 playing half as fast, - * etc. - * - * @param speedModFunction The function to apply to this controller to handle animation speed - * @return this - */ - public AzAnimationController setAnimationSpeedHandler(ToDoubleFunction speedModFunction) { - this.animationSpeedModifier = speedModFunction; - - return this; - } - - /** - * Sets the controller's {@link EasingType} override for animations.
      - * By default, the controller will use whatever {@code EasingType} was defined in the animation json - * - * @param easingTypeFunction The new {@code EasingType} to use - * @return this - */ - public AzAnimationController setOverrideEasingType(EasingType easingTypeFunction) { - return setOverrideEasingTypeFunction(obj -> easingTypeFunction); - } - - public Function getOverrideEasingTypeFunction() { - return overrideEasingTypeFunction; - } - - /** - * Sets the controller's {@link EasingType} override function for animations.
      - * By default, the controller will use whatever {@code EasingType} was defined in the animation json - * - * @param easingType The new {@code EasingType} to use - * @return this - */ - public AzAnimationController setOverrideEasingTypeFunction(Function easingType) { - this.overrideEasingTypeFunction = easingType; - - return this; - } - - /** - * Registers a triggerable {@link AzRawAnimation} with the controller.
      - * These can then be triggered by the various {@code triggerAnim} methods in {@code GeoAnimatable's} subclasses - * - * @param name The name of the triggerable animation - * @param animation The RawAnimation for this triggerable animation - * @return this - */ - public AzAnimationController triggerableAnim(String name, AzRawAnimation animation) { - this.triggerableAnimations.put(name, animation); - - return this; - } - - public String getName() { - return name; - } - - public @Nullable AzQueuedAnimation getCurrentAnimation() { - return currentAnimation; - } - - public Collection getBoneAnimationQueues() { - return boneAnimationQueueCache.values(); - } - /** - * Gets the current animation speed modifier.
      + * Computes the current animation speed modifier.
      * This modifier defines the relative speed in which animations will be played based on the current state of the * game. * * @return The computed current animation speed modifier */ - public double getAnimationSpeed(T animatable) { + public double computeAnimationSpeed(T animatable) { return animationSpeedModifier.applyAsDouble(animatable); } - /** - * Applies the given modifier value to this controller, for handlign the speed that the controller hsould play its - * animations at.
      - * A value of 1 is considered neutral, with 2 playing an animation twice as fast, 0.5 playing half as fast, etc. - * - * @param speed The speed modifier to apply to this controller to handle animation speed. - * @return this - */ - public AzAnimationController setAnimationSpeed(double speed) { - return setAnimationSpeedHandler(obj -> speed); - } - /** * Marks the controller as needing to reset its animation and state the next time * {@link AzAnimationController#setAnimation(T, AzRawAnimation)} is called.
      @@ -215,34 +133,6 @@ public void forceAnimationReset() { this.needsAnimationReload = true; } - /** - * Checks whether the last animation that was playing on this controller has finished or not.
      - * This will return true if the controller has had an animation set previously, and it has finished playing and - * isn't going to loop or proceed to another animation.
      - * - * @return Whether the previous animation finished or not - */ - public boolean hasAnimationFinished() { - return currentRawAnimation != null && stateMachine.isStopped(); - } - - /** - * Returns the currently cached {@link AzRawAnimation}.
      - * This animation may or may not still be playing, but it is the last one to be set in - * {@link AzAnimationController#setAnimation} - */ - public AzRawAnimation getCurrentRawAnimation() { - return currentRawAnimation; - } - - /** - * Returns whether the controller is currently playing a triggered animation registered in - * {@link AzAnimationController#triggerableAnim}
      - */ - public boolean isPlayingTriggeredAnimation() { - return triggeredAnimation != null && !hasAnimationFinished(); - } - /** * Populates the animation queue with the given {@link AzRawAnimation} * @@ -407,20 +297,28 @@ public AzBoneAnimationQueueCache getBoneAnimationQueueCache() { return boneAnimationQueueCache; } + public Collection getBoneAnimationQueues() { + return boneAnimationQueueCache.values(); + } + public AzBoneSnapshotCache getBoneSnapshotCache() { return boneSnapshotCache; } - public AzKeyFrameCallbacks getKeyFrameCallbacks() { - return keyFrameCallbacks; + public @Nullable AzQueuedAnimation getCurrentAnimation() { + return currentAnimation; } - public AzKeyFrameCallbackManager getKeyFrameCallbackManager() { - return keyFrameCallbackManager; + public AzKeyFrameManager getKeyFrameManager() { + return keyFrameManager; } - public AzKeyFrameProcessor getKeyFrameProcessor() { - return keyFrameProcessor; + public String getName() { + return name; + } + + public Function getOverrideEasingTypeFunction() { + return overrideEasingTypeFunction; } public AzAnimationControllerStateMachine getStateMachine() { @@ -431,6 +329,17 @@ public double getTransitionLength() { return transitionLength; } + /** + * Checks whether the last animation that was playing on this controller has finished or not.
      + * This will return true if the controller has had an animation set previously, and it has finished playing and + * isn't going to loop or proceed to another animation.
      + * + * @return Whether the previous animation finished or not + */ + public boolean hasAnimationFinished() { + return currentRawAnimation != null && stateMachine.isStopped(); + } + public void setShouldResetTick(boolean shouldResetTick) { stateMachine.setShouldResetTick(shouldResetTick); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerBuilder.java new file mode 100644 index 000000000..427497191 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerBuilder.java @@ -0,0 +1,87 @@ +package mod.azure.azurelib.core2.animation.controller; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; + +import mod.azure.azurelib.core.animation.EasingType; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; + +public class AzAnimationControllerBuilder { + + private final AzAnimator animator; + + private final String name; + + private final Map triggerableAnimations; + + private ToDoubleFunction animationSpeedModifier; + + private AzKeyFrameCallbacks keyFrameCallbacks; + + private Function overrideEasingTypeFunction; + + private int transitionLength; + + public AzAnimationControllerBuilder(AzAnimator animator, String name) { + this.animator = animator; + this.name = name; + this.animationSpeedModifier = obj -> 1d; + this.keyFrameCallbacks = AzKeyFrameCallbacks.noop(); + this.overrideEasingTypeFunction = obj -> null; + this.transitionLength = 0; + this.triggerableAnimations = new Object2ObjectOpenHashMap<>(0); + } + + public AzAnimationControllerBuilder setAnimationSpeed(double speed) { + return setAnimationSpeedHandler(obj -> speed); + } + + public AzAnimationControllerBuilder setAnimationSpeedHandler(ToDoubleFunction speedModFunction) { + this.animationSpeedModifier = speedModFunction; + return this; + } + + public AzAnimationControllerBuilder setKeyFrameCallbacks(@NotNull AzKeyFrameCallbacks keyFrameCallbacks) { + Objects.requireNonNull(keyFrameCallbacks); + this.keyFrameCallbacks = keyFrameCallbacks; + return this; + } + + public AzAnimationControllerBuilder setOverrideEasingType(EasingType easingTypeFunction) { + return setOverrideEasingTypeFunction(obj -> easingTypeFunction); + } + + public AzAnimationControllerBuilder setOverrideEasingTypeFunction(Function easingType) { + this.overrideEasingTypeFunction = easingType; + return this; + } + + public AzAnimationControllerBuilder setTransitionLength(int transitionLength) { + this.transitionLength = transitionLength; + return this; + } + + public AzAnimationControllerBuilder triggerableAnim(String name, AzRawAnimation animation) { + this.triggerableAnimations.put(name, animation); + return this; + } + + public AzAnimationController build() { + return new AzAnimationController<>( + name, + animator, + transitionLength, + animationSpeedModifier, + keyFrameCallbacks, + overrideEasingTypeFunction, + triggerableAnimations + ); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackHandler.java similarity index 88% rename from common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java rename to common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackHandler.java index 8419415b5..48afc7c4b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackManager.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameCallbackHandler.java @@ -14,17 +14,23 @@ import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; // TODO: reduce the boilerplate of the specialized handle functions in this class. -public class AzKeyFrameCallbackManager { +public class AzKeyFrameCallbackHandler { - private static final Logger LOGGER = LoggerFactory.getLogger(AzKeyFrameCallbackManager.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AzKeyFrameCallbackHandler.class); private final AzAnimationController animationController; private final Set executedKeyFrames; - public AzKeyFrameCallbackManager(AzAnimationController animationController) { + private final AzKeyFrameCallbacks keyFrameCallbacks; + + public AzKeyFrameCallbackHandler( + AzAnimationController animationController, + AzKeyFrameCallbacks keyFrameCallbacks + ) { this.animationController = animationController; this.executedKeyFrames = new ObjectOpenHashSet<>(); + this.keyFrameCallbacks = keyFrameCallbacks; } public void handle(T animatable, double adjustedTick) { @@ -34,7 +40,7 @@ public void handle(T animatable, double adjustedTick) { } private void handleCustomKeyframes(T animatable, double adjustedTick) { - var customKeyframeHandler = getCallbacks().getCustomKeyframeHandler(); + var customKeyframeHandler = keyFrameCallbacks.getCustomKeyframeHandler(); var customInstructions = getCurrentAnimation().animation().keyFrames().customInstructions(); for (var keyframeData : customInstructions) { @@ -56,7 +62,7 @@ private void handleCustomKeyframes(T animatable, double adjustedTick) { } private void handleParticleKeyframes(T animatable, double adjustedTick) { - var particleKeyframeHandler = getCallbacks().getParticleKeyframeHandler(); + var particleKeyframeHandler = keyFrameCallbacks.getParticleKeyframeHandler(); var particleInstructions = getCurrentAnimation().animation().keyFrames().particles(); for (var keyframeData : particleInstructions) { @@ -78,7 +84,7 @@ private void handleParticleKeyframes(T animatable, double adjustedTick) { } private void handleSoundKeyframes(T animatable, double adjustedTick) { - var soundKeyframeHandler = getCallbacks().getSoundKeyframeHandler(); + var soundKeyframeHandler = keyFrameCallbacks.getSoundKeyframeHandler(); var soundInstructions = getCurrentAnimation().animation().keyFrames().sounds(); for (var keyframeData : soundInstructions) { @@ -106,10 +112,6 @@ public void reset() { executedKeyFrames.clear(); } - private AzKeyFrameCallbacks getCallbacks() { - return animationController.getKeyFrameCallbacks(); - } - private AzQueuedAnimation getCurrentAnimation() { return animationController.getCurrentAnimation(); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java new file mode 100644 index 000000000..3c96e2941 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java @@ -0,0 +1,28 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; + +public class AzKeyFrameManager { + + private final AzKeyFrameCallbackHandler keyFrameCallbackHandler; + + private final AzKeyFrameProcessor keyFrameProcessor; + + public AzKeyFrameManager( + AzAnimationController animationController, + AzBoneAnimationQueueCache boneAnimationQueueCache, + AzKeyFrameCallbacks keyFrameCallbacks + ) { + this.keyFrameCallbackHandler = new AzKeyFrameCallbackHandler<>(animationController, keyFrameCallbacks); + this.keyFrameProcessor = new AzKeyFrameProcessor<>(animationController, boneAnimationQueueCache); + } + + public AzKeyFrameCallbackHandler keyFrameCallbackHandler() { + return keyFrameCallbackHandler; + } + + public AzKeyFrameProcessor getKeyFrameProcessor() { + return keyFrameProcessor; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java index 0c6a75040..5d725cb2b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java @@ -39,9 +39,8 @@ public AzKeyFrameProcessor( */ public void runCurrentAnimation(T animatable, double seekTime, boolean crashWhenCantFindBone) { var animationQueue = animationController.getAnimationQueue(); - var animationState = animationController.getStateMachine().getState(); var currentAnimation = animationController.getCurrentAnimation(); - var keyFrameCallbackManager = animationController.getKeyFrameCallbackManager(); + var keyFrameCallbackHandler = animationController.getKeyFrameManager().keyFrameCallbackHandler(); var stateMachine = animationController.getStateMachine(); var stateMachineContext = stateMachine.getContext(); var transitionLength = animationController.getTransitionLength(); @@ -55,12 +54,12 @@ public void runCurrentAnimation(T animatable, double seekTime, boolean crashWhen animationController.setShouldResetTick(true); stateMachineContext.adjustedTick = animationController.adjustTick(animatable, seekTime); - keyFrameCallbackManager.reset(); + keyFrameCallbackHandler.reset(); } } else { var nextAnimation = animationQueue.peek(); - keyFrameCallbackManager.reset(); + keyFrameCallbackHandler.reset(); if (nextAnimation == null) { stateMachine.stop(); @@ -164,7 +163,7 @@ public void runCurrentAnimation(T animatable, double seekTime, boolean crashWhen stateMachineContext.adjustedTick += transitionLength; - keyFrameCallbackManager.handle(animatable, stateMachineContext.adjustedTick); + keyFrameCallbackHandler.handle(animatable, stateMachineContext.adjustedTick); } public void transitionFromCurrentAnimation( diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java index 8df263d8e..d24bf5edd 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java @@ -29,9 +29,11 @@ public DroneAnimator() { @Override public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( - new AzAnimationController<>(this, "base_controller", 5) + AzAnimationController.builder(this, "base_controller") + .setTransitionLength(5) .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) .triggerableAnim(WALK_ANIMATION_NAME, WALK_ANIMATION) + .build() ); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java index 09b7b1c56..61f208409 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java @@ -27,8 +27,9 @@ public FacehuggerAnimator() { @Override public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( - new AzAnimationController<>(this, "base_controller", 0) + AzAnimationController.builder(this, "base_controller") .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) + .build() ); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java index 92afddaf8..e9e324dd4 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java @@ -31,9 +31,10 @@ public DoomHunterAnimator() { @Override public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( - new AzAnimationController<>(this, "base_controller", 0) + AzAnimationController.builder(this, "base_controller") .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) .triggerableAnim(MELEE_ANIMATION_NAME, MELEE_ANIMATION) + .build() ); } From c4cbe3edd2c9bbf1c90675a94c86505cc0640437 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 14 Dec 2024 21:15:45 -0500 Subject: [PATCH 081/224] Add drone walking example --- .../azurelib/fabric/core2/example/Drone.java | 28 +++++---- .../fabric/core2/example/MoveAnalysis.java | 57 +++++++++++++++++++ 2 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/MoveAnalysis.java diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java index fb115f690..aefdfbc63 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java @@ -1,7 +1,11 @@ package mod.azure.azurelib.fabric.core2.example; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; +import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; +import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; @@ -9,27 +13,31 @@ public class Drone extends Monster { private final AzAnimationDispatcher animationDispatcher; + private final MoveAnalysis moveAnalysis; public Drone(EntityType entityType, Level level) { super(entityType, level); this.animationDispatcher = new AzAnimationDispatcher<>(this); + this.moveAnalysis = new MoveAnalysis(this); } - private boolean walk; - public void tick() { super.tick(); + moveAnalysis.update(); if (this.level().isClientSide) { - if (this.tickCount % 40 == 0) { - walk = !walk; - } - - var animName = walk - ? "animation.walk" - : "animation.idle"; - + var isMovingOnGround = moveAnalysis.isMovingHorizontally() && onGround(); + var animName = isMovingOnGround + ? "animation.walk" + : "animation.idle"; animationDispatcher.dispatchFromClient("base_controller", animName); + } else { + // Doing other stuff server-side... } } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.25F)); + } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/MoveAnalysis.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/MoveAnalysis.java new file mode 100644 index 000000000..bbefaaa38 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/MoveAnalysis.java @@ -0,0 +1,57 @@ +package mod.azure.azurelib.fabric.core2.example; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; + +public class MoveAnalysis { + + private final Entity entity; + + private int lastTick; + private Vec3 lastPosition; + + private double deltaX; + private double deltaY; + private double deltaZ; + + public MoveAnalysis(Entity entity) { + this.entity = entity; + this.lastPosition = entity.position(); + } + + public void update() { + if (entity.tickCount == lastTick) { + // Only update on tick differences. + return; + } + + var prevPos = lastPosition; + var prevPosX = prevPos.x; + var prevPosY = prevPos.y; + var prevPosZ = prevPos.z; + + var pos = entity.position(); + var posX = pos.x; + var posY = pos.y; + var posZ = pos.z; + + this.deltaX = posX - prevPosX; + this.deltaY = posY - prevPosY; + this.deltaZ = posZ - prevPosZ; + + this.lastPosition = entity.position(); + this.lastTick = entity.tickCount; + } + + public boolean isMovingHorizontally() { + return deltaX != 0 || deltaZ != 0; + } + + public boolean isMovingVertically() { + return deltaY != 0; + } + + public boolean isMoving() { + return isMovingHorizontally() || isMovingVertically(); + } +} \ No newline at end of file From 2f0310a168158a075f90d0c221313869f2bfb985 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 14 Dec 2024 21:15:55 -0500 Subject: [PATCH 082/224] alpha12 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 333a9a2d9..85d36b323 100644 --- a/gradle.properties +++ b/gradle.properties @@ -51,5 +51,5 @@ mod_logo = azurelib.png mod_name = AzureLib mod_sources = https://github.com/AzureDoom/AzureLib mod_url = https://modrinth.com/mod/azurelib -version = 3.0.0-alpha9 +version = 3.0.0-alpha12 modrinth_id = 7zlUOZvb From bd7e34973a6ae8aa963bc3aff7329adeb45413f7 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 14 Dec 2024 21:55:40 -0500 Subject: [PATCH 083/224] AzAnimationDispatcher no longer requires type argument. Signed-off-by: = --- .../azurelib/core2/animation/AzAnimationDispatcher.java | 6 +++--- .../java/mod/azure/azurelib/fabric/core2/example/Drone.java | 4 ++-- .../mod/azure/azurelib/fabric/core2/example/Facehugger.java | 4 ++-- .../azurelib/fabric/core2/example/azure/DoomHunter.java | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java index 150e8aa28..6c8ade291 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java @@ -7,11 +7,11 @@ import mod.azure.azurelib.common.internal.common.network.packet.AzEntityAnimTriggerPacket; import mod.azure.azurelib.common.platform.Services; -public class AzAnimationDispatcher { +public class AzAnimationDispatcher { - private final T entity; + private final Entity entity; - public AzAnimationDispatcher(T entity) { + public AzAnimationDispatcher(Entity entity) { this.entity = entity; } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java index fb115f690..47bb82c99 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java @@ -8,11 +8,11 @@ public class Drone extends Monster { - private final AzAnimationDispatcher animationDispatcher; + private final AzAnimationDispatcher animationDispatcher; public Drone(EntityType entityType, Level level) { super(entityType, level); - this.animationDispatcher = new AzAnimationDispatcher<>(this); + this.animationDispatcher = new AzAnimationDispatcher(this); } private boolean walk; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java index 2ad156e23..ee4d9f721 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java @@ -8,11 +8,11 @@ public class Facehugger extends Monster { - private final AzAnimationDispatcher animationDispatcher; + private final AzAnimationDispatcher animationDispatcher; public Facehugger(EntityType entityType, Level level) { super(entityType, level); - this.animationDispatcher = new AzAnimationDispatcher<>(this); + this.animationDispatcher = new AzAnimationDispatcher(this); } public void tick() { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java index 24f437905..6a434bf4a 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java @@ -18,11 +18,11 @@ public class DoomHunter extends Monster { - private final AzAnimationDispatcher animationDispatcher; + private final AzAnimationDispatcher animationDispatcher; public DoomHunter(EntityType entityType, Level level) { super(entityType, level); - this.animationDispatcher = new AzAnimationDispatcher<>(this); + this.animationDispatcher = new AzAnimationDispatcher(this); } @Override From d92ffe01d4d9e6c888ba61612daa144690c6f673 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sun, 15 Dec 2024 00:54:26 -0500 Subject: [PATCH 084/224] Remove facehugger example --- .../core2/example/ExampleEntityTypes.java | 5 --- .../fabric/core2/example/Facehugger.java | 25 ------------ .../core2/example/FacehuggerAnimator.java | 40 ------------------- .../core2/example/FacehuggerRenderer.java | 36 ----------------- 4 files changed, 106 deletions(-) delete mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java delete mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java delete mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java index e179dd80d..2ee0943d1 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java @@ -17,11 +17,6 @@ public class ExampleEntityTypes { EntityType.Builder.of(Drone::new, MobCategory.MONSTER).sized(0.8f, 1.98f) ); - public static final EntityType FACEHUGGER = register( - "facehugger", - EntityType.Builder.of(Facehugger::new, MobCategory.MONSTER).sized(0.75f, 0.25f) - ); - public static final EntityType DOOMHUNTER = register( "doomhunter", EntityType.Builder.of(DoomHunter::new, MobCategory.MONSTER).sized(3.0f, 7.0f) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java deleted file mode 100644 index 2ad156e23..000000000 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java +++ /dev/null @@ -1,25 +0,0 @@ -package mod.azure.azurelib.fabric.core2.example; - -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.monster.Monster; -import net.minecraft.world.level.Level; - -import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; - -public class Facehugger extends Monster { - - private final AzAnimationDispatcher animationDispatcher; - - public Facehugger(EntityType entityType, Level level) { - super(entityType, level); - this.animationDispatcher = new AzAnimationDispatcher<>(this); - } - - public void tick() { - super.tick(); - - if (this.level().isClientSide) { - animationDispatcher.dispatchFromClient("base_controller", "animation.run"); - } - } -} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java deleted file mode 100644 index 61f208409..000000000 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerAnimator.java +++ /dev/null @@ -1,40 +0,0 @@ -package mod.azure.azurelib.fabric.core2.example; - -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; - -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.AzAnimatorConfig; -import mod.azure.azurelib.core2.animation.controller.AzAnimationController; -import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; -import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; -import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; - -public class FacehuggerAnimator extends AzEntityAnimator { - - private static final ResourceLocation ANIMATIONS = AzureLib.modResource( - "animations/entity/facehugger.animation.json" - ); - - private static final String IDLE_ANIMATION_NAME = "animation.run"; - - private static final AzRawAnimation IDLE_ANIMATION = AzRawAnimation.begin().thenLoop(IDLE_ANIMATION_NAME); - - public FacehuggerAnimator() { - super(AzAnimatorConfig.defaultConfig()); - } - - @Override - public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { - animationControllerContainer.add( - AzAnimationController.builder(this, "base_controller") - .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) - .build() - ); - } - - @Override - public @NotNull ResourceLocation getAnimationLocation(Facehugger facehugger) { - return ANIMATIONS; - } -} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java deleted file mode 100644 index 62a96b134..000000000 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/FacehuggerRenderer.java +++ /dev/null @@ -1,36 +0,0 @@ -package mod.azure.azurelib.fabric.core2.example; - -import net.minecraft.client.renderer.entity.EntityRendererProvider; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; -import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; - -public class FacehuggerRenderer extends AzEntityRenderer { - - private static final ResourceLocation MODEL = AzureLib.modResource("geo/entity/facehugger.geo.json"); - - private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/facehugger.png"); - - public FacehuggerRenderer(EntityRendererProvider.Context context) { - super(context); - } - - @Override - protected @Nullable AzEntityAnimator createAnimator() { - return new FacehuggerAnimator(); - } - - @Override - protected @NotNull ResourceLocation getModelLocation(Facehugger facehugger) { - return MODEL; - } - - @Override - public @NotNull ResourceLocation getTextureLocation(@NotNull Facehugger facehugger) { - return TEXTURE; - } -} From ba1ad19e974c71633909a1ebbc6e9e4f5af163b6 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sun, 15 Dec 2024 00:55:19 -0500 Subject: [PATCH 085/224] Move Drone/Doom Hunter Examples --- .../fabric/core2/example/blocks/Stargate.java | 31 +++++++++++++++++++ .../doomhunter}/DoomHunter.java | 2 +- .../doomhunter}/DoomHunterAnimator.java | 2 +- .../doomhunter}/DoomHunterRenderer.java | 2 +- .../example/{ => entities/drone}/Drone.java | 11 +++---- .../{ => entities/drone}/DroneAnimator.java | 2 +- .../{ => entities/drone}/DroneRenderer.java | 2 +- 7 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java rename fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/{azure => entities/doomhunter}/DoomHunter.java (97%) rename fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/{azure => entities/doomhunter}/DoomHunterAnimator.java (96%) rename fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/{azure => entities/doomhunter}/DoomHunterRenderer.java (94%) rename fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/{ => entities/drone}/Drone.java (80%) rename fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/{ => entities/drone}/DroneAnimator.java (96%) rename fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/{ => entities/drone}/DroneRenderer.java (94%) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java new file mode 100644 index 000000000..5ee7a42eb --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java @@ -0,0 +1,31 @@ +package mod.azure.azurelib.fabric.core2.example.blocks; + +import com.mojang.serialization.MapCodec; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; + +public class Stargate extends BaseEntityBlock implements EntityBlock { + + public static final MapCodec CODEC = simpleCodec(Stargate::new); + + public Stargate(Properties properties) { + super(properties); + } + + @Override + protected @NotNull MapCodec codec() { + return CODEC; + } + + @Override + public @Nullable BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + return ExampleEntityTypes.STARGATE.create(pos, state); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunter.java similarity index 97% rename from fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java rename to fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunter.java index 24f437905..a20bf3347 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunter.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunter.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.fabric.core2.example.azure; +package mod.azure.azurelib.fabric.core2.example.entities.doomhunter; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.EntityType; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimator.java similarity index 96% rename from fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java rename to fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimator.java index e9e324dd4..b8445233f 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimator.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.fabric.core2.example.azure; +package mod.azure.azurelib.fabric.core2.example.entities.doomhunter; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java similarity index 94% rename from fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterRenderer.java rename to fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java index 6807fc8f2..795ca7acc 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/azure/DoomHunterRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.fabric.core2.example.azure; +package mod.azure.azurelib.fabric.core2.example.entities.doomhunter; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/Drone.java similarity index 80% rename from fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java rename to fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/Drone.java index aefdfbc63..90266e292 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Drone.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/Drone.java @@ -1,18 +1,17 @@ -package mod.azure.azurelib.fabric.core2.example; +package mod.azure.azurelib.fabric.core2.example.entities.drone; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; -import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; import net.minecraft.world.entity.monster.Monster; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; +import mod.azure.azurelib.fabric.core2.example.MoveAnalysis; public class Drone extends Monster { private final AzAnimationDispatcher animationDispatcher; + private final MoveAnalysis moveAnalysis; public Drone(EntityType entityType, Level level) { @@ -28,8 +27,8 @@ public void tick() { if (this.level().isClientSide) { var isMovingOnGround = moveAnalysis.isMovingHorizontally() && onGround(); var animName = isMovingOnGround - ? "animation.walk" - : "animation.idle"; + ? "animation.walk" + : "animation.idle"; animationDispatcher.dispatchFromClient("base_controller", animName); } else { // Doing other stuff server-side... diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimator.java similarity index 96% rename from fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java rename to fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimator.java index d24bf5edd..09fdd52f0 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimator.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.fabric.core2.example; +package mod.azure.azurelib.fabric.core2.example.entities.drone; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneRenderer.java similarity index 94% rename from fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneRenderer.java rename to fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneRenderer.java index 953218b68..9fbc83b36 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/DroneRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneRenderer.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.fabric.core2.example; +package mod.azure.azurelib.fabric.core2.example.entities.drone; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; From 8c36e5c4a5b1694674b09d0071e474fee38c1288 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sun, 15 Dec 2024 00:55:32 -0500 Subject: [PATCH 086/224] Lint --- .../azure/azurelib/fabric/core2/example/MoveAnalysis.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/MoveAnalysis.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/MoveAnalysis.java index bbefaaa38..30c51d2d0 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/MoveAnalysis.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/MoveAnalysis.java @@ -8,10 +8,13 @@ public class MoveAnalysis { private final Entity entity; private int lastTick; + private Vec3 lastPosition; private double deltaX; + private double deltaY; + private double deltaZ; public MoveAnalysis(Entity entity) { @@ -54,4 +57,4 @@ public boolean isMovingVertically() { public boolean isMoving() { return isMovingHorizontally() || isMovingVertically(); } -} \ No newline at end of file +} From fc463d5f40dfd9b62199ada7ce2a16efad6654a2 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sun, 15 Dec 2024 01:18:13 -0500 Subject: [PATCH 087/224] Missed --- .../entity/facehugger.animation.json | 86 ------------------ .../azurelib/geo/entity/facehugger.geo.json | 48 ---------- .../azurelib/textures/entity/facehugger.png | Bin 3201 -> 0 bytes 3 files changed, 134 deletions(-) delete mode 100644 common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json delete mode 100644 common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json delete mode 100644 common/src/main/resources/assets/azurelib/textures/entity/facehugger.png diff --git a/common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json b/common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json deleted file mode 100644 index 3341a4bbe..000000000 --- a/common/src/main/resources/assets/azurelib/animations/entity/facehugger.animation.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "format_version": "1.8.0", - "animations": { - "animation.run": { - "loop": true, - "animation_length": 0.5, - "bones": { - "gRFrontLegMid": { - "rotation": { - "0.0": { - "vector": [0, 0, 1] - }, - "0.0417": { - "vector": [0, 0, 21] - }, - "0.0833": { - "vector": [0, 0, 30] - }, - "0.125": { - "vector": [0, 0, 32.5] - }, - "0.1667": { - "vector": [0, 0, 16] - }, - "0.25": { - "vector": [0, 0, 1] - }, - "0.2917": { - "vector": [0, 0, 21] - }, - "0.3333": { - "vector": [0, 0, 30] - }, - "0.375": { - "vector": [0, 0, 32.5] - }, - "0.4167": { - "vector": [0, 0, 16] - }, - "0.5": { - "vector": [0, 0, 1] - } - } - }, - "gRFrontLegBottom": { - "rotation": { - "0.0": { - "vector": [0, 0, 33.5] - }, - "0.0417": { - "vector": [0, 0, 3.5] - }, - "0.0833": { - "vector": [0, 0, -25.5] - }, - "0.125": { - "vector": [0, 0, 32.5] - }, - "0.1667": { - "vector": [0, 0, 32] - }, - "0.25": { - "vector": [0, 0, 33.5] - }, - "0.2917": { - "vector": [0, 0, 3.5] - }, - "0.3333": { - "vector": [0, 0, -25.5] - }, - "0.375": { - "vector": [0, 0, 32.5] - }, - "0.4167": { - "vector": [0, 0, 32] - }, - "0.5": { - "vector": [0, 0, 33.5] - } - } - } - } - } - }, - "azurelib_format_version": 2 -} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json b/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json deleted file mode 100644 index cbcf42197..000000000 --- a/common/src/main/resources/assets/azurelib/geo/entity/facehugger.geo.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "format_version": "1.21.20", - "minecraft:geometry": [ - { - "description": { - "identifier": "geometry.unknown", - "texture_width": 40, - "texture_height": 35, - "visible_bounds_width": 5, - "visible_bounds_height": 1.5, - "visible_bounds_offset": [0, 0.25, 0] - }, - "bones": [ - { - "name": "root", - "pivot": [0, 4, 0] - }, - { - "name": "gRFrontLeg", - "parent": "root", - "pivot": [-1.03227, 3.85146, -2.40085], - "rotation": [0, -47.5, 12.5], - "cubes": [ - {"origin": [-2.36561, 2.95146, -2.90085], "size": [2, 1, 1], "inflate": -0.05, "uv": [16, 15], "mirror": true} - ] - }, - { - "name": "gRFrontLegMid", - "parent": "gRFrontLeg", - "pivot": [-2.06732, 3.37757, -2.40085], - "rotation": [0, 0, -7.5], - "cubes": [ - {"origin": [-2.50206, 2.97329, -5.30085], "size": [1, 1, 3], "inflate": -0.1, "pivot": [-2.00206, 3.87329, -2.40085], "rotation": [0, 90, 0], "uv": [15, 18]} - ] - }, - { - "name": "gRFrontLegBottom", - "parent": "gRFrontLegMid", - "pivot": [-4.50361, 3.42542, -2.44872], - "rotation": [0, 0, -75], - "cubes": [ - {"origin": [-4.91895, 2.90714, -5.00085], "size": [1, 1, 3], "inflate": -0.15, "pivot": [-4.41895, 3.30714, -2.40085], "rotation": [0, 90, 0], "uv": [15, 23]} - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/textures/entity/facehugger.png b/common/src/main/resources/assets/azurelib/textures/entity/facehugger.png deleted file mode 100644 index edb0ae86beabcc3b97b1af96963f2d4e6d32f997..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3201 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 From 7d9dacc9e780a4ba8ea7259225965cfd521abf95 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sun, 15 Dec 2024 01:20:00 -0500 Subject: [PATCH 088/224] Adds Block, Item, and Armor examples to be converted and tested. --- .../animations/block/stargate.animation.json | 249 + .../animations/item/doomicorn.animation.json | 741 + .../animations/item/pistol.animation.json | 80 + .../assets/azurelib/blockstates/stargate.json | 5 + .../azurelib/geo/block/stargate.geo.json | 877 + .../azurelib/geo/item/doomicorn.geo.json | 17113 ++++++++++++++++ .../assets/azurelib/geo/item/pistol.geo.json | 3690 ++++ .../azurelib/models/block/stargate.json | 96 + .../azurelib/models/item/doomicorn_boots.json | 6 + .../models/item/doomicorn_chestplate.json | 6 + .../models/item/doomicorn_helmet.json | 6 + .../models/item/doomicorn_leggings.json | 6 + .../assets/azurelib/models/item/pistol.json | 96 + .../assets/azurelib/models/item/stargate.json | 6 + .../azurelib/textures/block/stargate.png | Bin 0 -> 8667 bytes .../azurelib/textures/item/doomicorn.png | Bin 0 -> 1189 bytes .../textures/item/doomicorn_boots.png | Bin 0 -> 136 bytes .../textures/item/doomicorn_chestplate.png | Bin 0 -> 338 bytes .../textures/item/doomicorn_helmet.png | Bin 0 -> 503 bytes .../textures/item/doomicorn_leggings.png | Bin 0 -> 139 bytes .../assets/azurelib/textures/item/pistol.png | Bin 0 -> 1486 bytes .../azure/azurelib/fabric/ClientListener.java | 16 +- .../azurelib/fabric/FabricAzureLibMod.java | 47 +- .../core2/example/ExampleEntityTypes.java | 14 +- .../core2/example/armors/ArmorRenderer.java | 37 + .../core2/example/armors/DoomArmor.java | 69 + .../example/blocks/StargateBlockEntity.java | 42 + .../core2/example/blocks/StargateRender.java | 12 + .../fabric/core2/example/items/Pistol.java | 93 + .../core2/example/items/PistolRender.java | 12 + 30 files changed, 23312 insertions(+), 7 deletions(-) create mode 100644 common/src/main/resources/assets/azurelib/animations/block/stargate.animation.json create mode 100644 common/src/main/resources/assets/azurelib/animations/item/doomicorn.animation.json create mode 100644 common/src/main/resources/assets/azurelib/animations/item/pistol.animation.json create mode 100644 common/src/main/resources/assets/azurelib/blockstates/stargate.json create mode 100644 common/src/main/resources/assets/azurelib/geo/block/stargate.geo.json create mode 100644 common/src/main/resources/assets/azurelib/geo/item/doomicorn.geo.json create mode 100644 common/src/main/resources/assets/azurelib/geo/item/pistol.geo.json create mode 100644 common/src/main/resources/assets/azurelib/models/block/stargate.json create mode 100644 common/src/main/resources/assets/azurelib/models/item/doomicorn_boots.json create mode 100644 common/src/main/resources/assets/azurelib/models/item/doomicorn_chestplate.json create mode 100644 common/src/main/resources/assets/azurelib/models/item/doomicorn_helmet.json create mode 100644 common/src/main/resources/assets/azurelib/models/item/doomicorn_leggings.json create mode 100644 common/src/main/resources/assets/azurelib/models/item/pistol.json create mode 100644 common/src/main/resources/assets/azurelib/models/item/stargate.json create mode 100644 common/src/main/resources/assets/azurelib/textures/block/stargate.png create mode 100644 common/src/main/resources/assets/azurelib/textures/item/doomicorn.png create mode 100644 common/src/main/resources/assets/azurelib/textures/item/doomicorn_boots.png create mode 100644 common/src/main/resources/assets/azurelib/textures/item/doomicorn_chestplate.png create mode 100644 common/src/main/resources/assets/azurelib/textures/item/doomicorn_helmet.png create mode 100644 common/src/main/resources/assets/azurelib/textures/item/doomicorn_leggings.png create mode 100644 common/src/main/resources/assets/azurelib/textures/item/pistol.png create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/ArmorRenderer.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/DoomArmor.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/Pistol.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/PistolRender.java diff --git a/common/src/main/resources/assets/azurelib/animations/block/stargate.animation.json b/common/src/main/resources/assets/azurelib/animations/block/stargate.animation.json new file mode 100644 index 000000000..fac7d0e36 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/block/stargate.animation.json @@ -0,0 +1,249 @@ +{ + "format_version": "1.8.0", + "animations": { + "spinning": { + "loop": true, + "animation_length": 14.4, + "bones": { + "bone2": { + "position": { + "1.0": { + "vector": [0, 0, 0] + }, + "1.08": { + "vector": [0, "math.sin(query.anim_time * 360) * -3", 0] + }, + "1.12": { + "vector": [0, 0, 0] + }, + "1.56": { + "vector": [0, 0, 0] + }, + "2.64": { + "vector": [0, 0, 0] + }, + "2.72": { + "vector": [0, "math.cos(query.anim_time * 360) * -3", 0] + }, + "2.76": { + "vector": [0, 0, 0] + }, + "3.2": { + "vector": [0, 0, 0] + }, + "4.32": { + "vector": [0, 0, 0] + }, + "4.4": { + "vector": [0, "math.sin(query.anim_time * 360) * -2", 0] + }, + "4.44": { + "vector": [0, 0, 0] + }, + "4.88": { + "vector": [0, 0, 0] + }, + "6.0": { + "vector": [0, 0, 0] + }, + "6.08": { + "vector": [0, "math.sin(query.anim_time * 360) * -3", 0] + }, + "6.12": { + "vector": [0, 0, 0] + }, + "6.56": { + "vector": [0, 0, 0] + }, + "7.68": { + "vector": [0, 0, 0] + }, + "7.76": { + "vector": [0, "math.cos(query.anim_time * 360) * -3", 0] + }, + "7.8": { + "vector": [0, 0, 0] + }, + "8.24": { + "vector": [0, 0, 0] + }, + "9.36": { + "vector": [0, 0, 0] + }, + "9.44": { + "vector": [0, "math.sin(query.anim_time * 360) * -3", 0] + }, + "9.48": { + "vector": [0, 0, 0] + }, + "9.92": { + "vector": [0, 0, 0] + }, + "10.96": { + "vector": [0, 0, 0] + }, + "11.04": { + "vector": [0, "math.sin(query.anim_time * 360) * -3", 0] + }, + "11.08": { + "vector": [0, 0, 0] + }, + "11.52": { + "vector": [0, 0, 0] + } + } + }, + "inner_ring": { + "rotation": { + "0.0": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "1.04": { + "vector": [0, 0, 360] + }, + "1.48": { + "vector": [0, 0, 359] + }, + "1.52": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * -360"] + }, + "2.56": { + "vector": [0, 0, 1] + }, + "3.16": { + "vector": [0, 0, 1] + }, + "3.2": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "4.32": { + "vector": [0, 0, 1] + }, + "5.24": { + "vector": [0, 0, 1] + }, + "5.28": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "5.88": { + "vector": [0, 0, 1] + }, + "5.92": { + "vector": [0, 0, 0] + }, + "6.92": { + "vector": [0, 0, 0] + }, + "6.96": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "7.56": { + "vector": [0, 0, 1] + }, + "7.6": { + "vector": [0, 0, 0] + }, + "8.12": { + "vector": [0, 0, 0] + }, + "8.16": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "9.2": { + "vector": [0, 0, 1] + }, + "9.28": { + "vector": [0, 0, 0] + }, + "9.84": { + "vector": [0, 0, 0] + }, + "10.88": { + "vector": [0, 0, 359] + }, + "10.96": { + "vector": [0, 0, 360] + } + } + }, + "portal": { + "scale": { + "0.0": { + "vector": [0, 0, 0] + }, + "11.48": { + "vector": [0, 0, 0] + }, + "11.52": { + "vector": [1, 1, 1] + }, + "12.4": { + "vector": [1, 1, 1] + } + } + }, + "portal2": { + "rotation": { + "11.52": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "13.44": { + "vector": [0, 0, 359] + } + }, + "position": { + "11.52": { + "vector": [0, 0, 0] + }, + "12.4": { + "vector": [0, 0, "-30.83+math.sin(query.anim_time * 200) * 10"] + }, + "13.44": { + "vector": [0, 0, 0] + } + }, + "scale": { + "0.0": { + "vector": [0, 0, 0] + }, + "11.52": { + "vector": [0, 0, 0] + }, + "12.4": { + "vector": [0.5, 0.5, 37.3] + }, + "13.44": { + "vector": [0, 0, 0] + } + } + } + } + }, + "idle": { + "loop": true, + "bones": { + "portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "portal2": { + "scale": { + "vector": [0, 0, 0] + } + } + } + }, + "open": { + "loop": true, + "bones": { + "bone9": { + "scale": { + "vector": [1, 1, 1] + } + } + } + } + }, + "azurelib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/animations/item/doomicorn.animation.json b/common/src/main/resources/assets/azurelib/animations/item/doomicorn.animation.json new file mode 100644 index 000000000..c7d87a8e1 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/item/doomicorn.animation.json @@ -0,0 +1,741 @@ +{ + "format_version": "1.8.0", + "animations": { + "equipping": { + "loop": true, + "animation_length": 1.84, + "bones": { + "bipedHead": { + "rotation": { + "0.0": { + "vector": [ + -90, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + -78.65, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + 0, + 10, + 15.03 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + }, + "bipedBody": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + 0, + 359, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + 0, + 10, + 15.03 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + }, + "bipedRightArm": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + 0, + 359, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + -15, + 10, + -1.97 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + }, + "bipedLeftArm": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + 0, + 359, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + 15, + 10, + -1.97 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + }, + "bipedRightLeg": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + 0, + 359, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + 11, + -31, + 15.03 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + }, + "bipedLeftLeg": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + 0, + 359, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + -11, + -31, + 15.03 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + } + } + }, + "idle": { + "loop": true, + "animation_length": 4.6, + "bones": { + "group": { + "rotation": { + "0.0": { + "vector": [ + 0, + -20, + 0 + ] + }, + "0.8": { + "vector": [ + 0, + -15, + 15 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + }, + "2.32": { + "vector": [ + 0, + -15, + 15 + ], + "easing": "easeInOutSine" + }, + "3.08": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + }, + "3.84": { + "vector": [ + 0, + -15, + 15 + ], + "easing": "easeInOutSine" + }, + "4.6": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + } + } + }, + "group2": { + "rotation": { + "0.0": { + "vector": [ + 0, + -20, + 0 + ] + }, + "0.8": { + "vector": [ + 0, + -15, + -15 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + }, + "2.32": { + "vector": [ + 0, + -15, + -15 + ], + "easing": "easeInOutSine" + }, + "3.08": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + }, + "3.84": { + "vector": [ + 0, + -15, + -15 + ], + "easing": "easeInOutSine" + }, + "4.6": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + } + } + }, + "launcher": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.52": { + "vector": [ + 25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "4.04": { + "vector": [ + 25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "4.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + } + }, + "bone4": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.52": { + "vector": [ + -25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "1.0": { + "vector": [ + -25, + -17.5, + 0 + ], + "easing": "easeInOutSine" + }, + "1.52": { + "vector": [ + -25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "2.0": { + "vector": [ + -25, + 13, + 0 + ], + "easing": "easeInOutSine" + }, + "2.52": { + "vector": [ + -25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "3.04": { + "vector": [ + -25, + -17.5, + 0 + ], + "easing": "easeInOutSine" + }, + "3.52": { + "vector": [ + -25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "4.08": { + "vector": [ + -25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "4.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + } + } + } + }, + "attacking": { + "animation_length": 2.08, + "bones": { + "blade": { + "position": { + "0.0": { + "vector": [ + 5, + 0, + 0 + ] + }, + "0.52": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutCirc" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutCirc" + }, + "2.08": { + "vector": [ + 5, + 0, + 0 + ], + "easing": "easeInOutCirc" + } + }, + "scale": { + "0.0": { + "vector": [ + 0.7, + 0.7, + 0.7 + ] + }, + "0.52": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutCirc" + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutCirc" + }, + "2.08": { + "vector": [ + 0.7, + 0.7, + 0.7 + ], + "easing": "easeInOutCirc" + } + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/animations/item/pistol.animation.json b/common/src/main/resources/assets/azurelib/animations/item/pistol.animation.json new file mode 100644 index 000000000..dba595e89 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/item/pistol.animation.json @@ -0,0 +1,80 @@ +{ + "format_version": "1.8.0", + "animations": { + "firing": { + "loop": true, + "animation_length": 0.16, + "bones": { + "group": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.08": { + "vector": [ + -7.5, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "0.16": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.08": { + "vector": [ + 0, + 0, + 2 + ], + "easing": "easeInOutSine" + }, + "0.16": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + } + }, + "bone": { + "position": { + "vector": [ + 0, + 0, + -0.3 + ] + }, + "scale": { + "vector": [ + 7, + 7, + 7 + ] + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/blockstates/stargate.json b/common/src/main/resources/assets/azurelib/blockstates/stargate.json new file mode 100644 index 000000000..1d8c9ec54 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/blockstates/stargate.json @@ -0,0 +1,5 @@ +{ + "variants": { + "model": "azurelib:block/stargate" + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/block/stargate.geo.json b/common/src/main/resources/assets/azurelib/geo/block/stargate.geo.json new file mode 100644 index 000000000..8da51fbc9 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/block/stargate.geo.json @@ -0,0 +1,877 @@ +{ + "format_version": "1.21.20", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 256, + "texture_height": 256, + "visible_bounds_width": 7, + "visible_bounds_height": 6.5, + "visible_bounds_offset": [0, 2.75, 0] + }, + "bones": [ + { + "name": "bone9", + "pivot": [0, 12, -0.6] + }, + { + "name": "outter_ring", + "parent": "bone9", + "pivot": [0, 40, 0], + "cubes": [ + { + "origin": [-7.95649, 0, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [160, 24], "uv_size": [16, 4]}, + "east": {"uv": [42, 140], "uv_size": [6, 4]}, + "south": {"uv": [160, 28], "uv_size": [16, 4]}, + "west": {"uv": [122, 161], "uv_size": [6, 4]}, + "up": {"uv": [26, 132], "uv_size": [16, 6]}, + "down": {"uv": [26, 144], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 0, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [160, 32], "uv_size": [16, 4]}, + "east": {"uv": [198, 151], "uv_size": [6, 4]}, + "south": {"uv": [160, 36], "uv_size": [16, 4]}, + "west": {"uv": [199, 50], "uv_size": [6, 4]}, + "up": {"uv": [143, 143], "uv_size": [16, 6]}, + "down": {"uv": [144, 6], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 0, -3], + "size": [15.91299, 4, 6], + "uv": { + "north": {"uv": [160, 40], "uv_size": [16, 4]}, + "east": {"uv": [199, 54], "uv_size": [6, 4]}, + "south": {"uv": [160, 44], "uv_size": [16, 4]}, + "west": {"uv": [155, 200], "uv_size": [6, 4]}, + "up": {"uv": [144, 6], "uv_size": [16, 6]}, + "down": {"uv": [144, 18], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 0, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [160, 48], "uv_size": [16, 4]}, + "east": {"uv": [161, 200], "uv_size": [6, 4]}, + "south": {"uv": [160, 52], "uv_size": [16, 4]}, + "west": {"uv": [167, 200], "uv_size": [6, 4]}, + "up": {"uv": [144, 18], "uv_size": [16, 6]}, + "down": {"uv": [144, 30], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 0, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [160, 56], "uv_size": [16, 4]}, + "east": {"uv": [173, 200], "uv_size": [6, 4]}, + "south": {"uv": [143, 160], "uv_size": [16, 4]}, + "west": {"uv": [179, 200], "uv_size": [6, 4]}, + "up": {"uv": [26, 144], "uv_size": [16, 6]}, + "down": {"uv": [144, 36], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 76, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [159, 160], "uv_size": [16, 4]}, + "east": {"uv": [82, 201], "uv_size": [6, 4]}, + "south": {"uv": [143, 164], "uv_size": [16, 4]}, + "west": {"uv": [201, 166], "uv_size": [6, 4]}, + "up": {"uv": [144, 36], "uv_size": [16, 6]}, + "down": {"uv": [144, 48], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 76, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [159, 164], "uv_size": [16, 4]}, + "east": {"uv": [201, 170], "uv_size": [6, 4]}, + "south": {"uv": [26, 167], "uv_size": [16, 4]}, + "west": {"uv": [201, 174], "uv_size": [6, 4]}, + "up": {"uv": [144, 48], "uv_size": [16, 6]}, + "down": {"uv": [144, 60], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 76, -3], + "size": [15.91299, 4, 6], + "uv": { + "north": {"uv": [42, 167], "uv_size": [16, 4]}, + "east": {"uv": [201, 178], "uv_size": [6, 4]}, + "south": {"uv": [58, 167], "uv_size": [16, 4]}, + "west": {"uv": [202, 0], "uv_size": [6, 4]}, + "up": {"uv": [42, 145], "uv_size": [16, 6]}, + "down": {"uv": [58, 151], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 76, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [74, 167], "uv_size": [16, 4]}, + "east": {"uv": [202, 4], "uv_size": [6, 4]}, + "south": {"uv": [110, 167], "uv_size": [16, 4]}, + "west": {"uv": [24, 202], "uv_size": [6, 4]}, + "up": {"uv": [74, 145], "uv_size": [16, 6]}, + "down": {"uv": [90, 151], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 76, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [167, 145], "uv_size": [16, 4]}, + "east": {"uv": [30, 202], "uv_size": [6, 4]}, + "south": {"uv": [167, 149], "uv_size": [16, 4]}, + "west": {"uv": [36, 202], "uv_size": [6, 4]}, + "up": {"uv": [106, 145], "uv_size": [16, 6]}, + "down": {"uv": [143, 155], "uv_size": [16, -6]} + } + }, + { + "origin": [36, 32.04351, -3], + "size": [4, 15.91299, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [118, 151], "uv_size": [4, 16]}, + "east": {"uv": [122, 145], "uv_size": [6, 16]}, + "south": {"uv": [168, 0], "uv_size": [4, 16]}, + "west": {"uv": [26, 150], "uv_size": [6, 16]}, + "up": {"uv": [126, 65], "uv_size": [4, 6]}, + "down": {"uv": [126, 77], "uv_size": [4, -6]} + } + }, + { + "origin": [36, 32.04351, -3], + "size": [4, 15.91299, 6], + "uv": { + "north": {"uv": [143, 168], "uv_size": [4, 16]}, + "east": {"uv": [32, 150], "uv_size": [6, 16]}, + "south": {"uv": [147, 168], "uv_size": [4, 16]}, + "west": {"uv": [38, 151], "uv_size": [6, 16]}, + "up": {"uv": [138, 197], "uv_size": [4, 6]}, + "down": {"uv": [88, 207], "uv_size": [4, -6]} + } + }, + { + "origin": [36, 32.04351, -3], + "size": [4, 15.91299, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [151, 168], "uv_size": [4, 16]}, + "east": {"uv": [44, 151], "uv_size": [6, 16]}, + "south": {"uv": [155, 168], "uv_size": [4, 16]}, + "west": {"uv": [50, 151], "uv_size": [6, 16]}, + "up": {"uv": [42, 202], "uv_size": [4, 6]}, + "down": {"uv": [46, 208], "uv_size": [4, -6]} + } + }, + { + "origin": [-40, 32.04351, -3], + "size": [4, 15.91299, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [159, 168], "uv_size": [4, 16]}, + "east": {"uv": [56, 151], "uv_size": [6, 16]}, + "south": {"uv": [163, 168], "uv_size": [4, 16]}, + "west": {"uv": [62, 151], "uv_size": [6, 16]}, + "up": {"uv": [50, 202], "uv_size": [4, 6]}, + "down": {"uv": [54, 208], "uv_size": [4, -6]} + } + }, + { + "origin": [-40, 32.04351, -3], + "size": [4, 15.91299, 6], + "uv": { + "north": {"uv": [167, 168], "uv_size": [4, 16]}, + "east": {"uv": [68, 151], "uv_size": [6, 16]}, + "south": {"uv": [26, 171], "uv_size": [4, 16]}, + "west": {"uv": [74, 151], "uv_size": [6, 16]}, + "up": {"uv": [58, 202], "uv_size": [4, 6]}, + "down": {"uv": [62, 208], "uv_size": [4, -6]} + } + }, + { + "origin": [-40, 32.04351, -3], + "size": [4, 15.91299, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [30, 171], "uv_size": [4, 16]}, + "east": {"uv": [80, 151], "uv_size": [6, 16]}, + "south": {"uv": [34, 171], "uv_size": [4, 16]}, + "west": {"uv": [86, 151], "uv_size": [6, 16]}, + "up": {"uv": [66, 202], "uv_size": [4, 6]}, + "down": {"uv": [70, 208], "uv_size": [4, -6]} + } + } + ] + }, + { + "name": "bone", + "parent": "outter_ring", + "pivot": [0, 27, 0], + "cubes": [ + { + "origin": [10.4, 3.2, -3.8], + "size": [8, 6, 7.5], + "pivot": [18.4, 5.7, -3.8], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [191, 51], "uv_size": [8, 6]}, + "east": {"uv": [155, 194], "uv_size": [8, 6]}, + "south": {"uv": [163, 194], "uv_size": [8, 6]}, + "west": {"uv": [171, 194], "uv_size": [8, 6]}, + "up": {"uv": [160, 8], "uv_size": [8, 8]}, + "down": {"uv": [160, 24], "uv_size": [8, -8]} + } + }, + { + "origin": [-18.4, 3.2, -3.8], + "size": [8, 6, 7.5], + "pivot": [-18.4, 5.7, -3.8], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [199, 14], "uv_size": [8, 6]}, + "east": {"uv": [199, 20], "uv_size": [8, 6]}, + "south": {"uv": [199, 26], "uv_size": [8, 6]}, + "west": {"uv": [199, 32], "uv_size": [8, 6]}, + "up": {"uv": [78, 171], "uv_size": [8, 8]}, + "down": {"uv": [110, 179], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone2", + "parent": "bone", + "pivot": [-0.5, 76.8, -3.8], + "cubes": [ + { + "origin": [-4.5, 74.6, -3.8], + "size": [8, 6, 7.5], + "uv": { + "north": {"uv": [118, 73], "uv_size": [8, 6]}, + "east": {"uv": [199, 38], "uv_size": [7, 6]}, + "south": {"uv": [155, 188], "uv_size": [8, 6]}, + "west": {"uv": [199, 44], "uv_size": [7, 6]}, + "up": {"uv": [118, 171], "uv_size": [8, 7]}, + "down": {"uv": [187, 15], "uv_size": [8, -7]} + } + } + ] + }, + { + "name": "bone3", + "parent": "bone", + "pivot": [7.5, 47, -2.1], + "cubes": [ + { + "origin": [19.44583, 63.56781, -3.8], + "size": [8, 6, 7.5], + "pivot": [26.5, 64.6, -3.9], + "rotation": [0, 0, 42.5], + "uv": { + "north": {"uv": [163, 188], "uv_size": [8, 6]}, + "east": {"uv": [171, 188], "uv_size": [8, 6]}, + "south": {"uv": [179, 188], "uv_size": [8, 6]}, + "west": {"uv": [188, 184], "uv_size": [8, 6]}, + "up": {"uv": [118, 65], "uv_size": [8, 8]}, + "down": {"uv": [42, 140], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone4", + "parent": "bone", + "pivot": [10.8, 42.2, -2.1], + "cubes": [ + { + "origin": [27, 46.7, -3.8], + "size": [8, 6, 7.5], + "pivot": [35, 46.7, -3.8], + "rotation": [0, 0, 70], + "uv": { + "north": {"uv": [190, 160], "uv_size": [8, 6]}, + "east": {"uv": [187, 190], "uv_size": [8, 6]}, + "south": {"uv": [191, 15], "uv_size": [8, 6]}, + "west": {"uv": [191, 21], "uv_size": [8, 6]}, + "up": {"uv": [110, 151], "uv_size": [8, 8]}, + "down": {"uv": [110, 167], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone5", + "parent": "bone", + "pivot": [35.2, 22.1, -2.1], + "cubes": [ + { + "origin": [26.4, 20.7, -3.8], + "size": [8, 6, 7.5], + "pivot": [34.4, 23.2, -3.8], + "rotation": [0, 0, -60], + "uv": { + "north": {"uv": [191, 27], "uv_size": [8, 6]}, + "east": {"uv": [191, 33], "uv_size": [8, 6]}, + "south": {"uv": [191, 39], "uv_size": [8, 6]}, + "west": {"uv": [191, 45], "uv_size": [8, 6]}, + "up": {"uv": [159, 145], "uv_size": [8, 8]}, + "down": {"uv": [160, 8], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone6", + "parent": "bone", + "pivot": [-29.9, 22.8, -2.1], + "cubes": [ + { + "origin": [-34.4, 20.7, -3.8], + "size": [8, 6, 7.5], + "pivot": [-34.4, 23.2, -3.8], + "rotation": [0, 0, 60], + "uv": { + "north": {"uv": [8, 198], "uv_size": [8, 6]}, + "east": {"uv": [16, 198], "uv_size": [8, 6]}, + "south": {"uv": [198, 145], "uv_size": [8, 6]}, + "west": {"uv": [198, 160], "uv_size": [8, 6]}, + "up": {"uv": [62, 171], "uv_size": [8, 8]}, + "down": {"uv": [70, 179], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone7", + "parent": "bone", + "pivot": [-34.6, 48.8, -2.1], + "cubes": [ + { + "origin": [-35, 46.7, -3.8], + "size": [8, 6, 7.5], + "pivot": [-35, 46.7, -3.8], + "rotation": [0, 0, -70], + "uv": { + "north": {"uv": [187, 196], "uv_size": [8, 6]}, + "east": {"uv": [195, 196], "uv_size": [8, 6]}, + "south": {"uv": [130, 197], "uv_size": [8, 6]}, + "west": {"uv": [0, 198], "uv_size": [8, 6]}, + "up": {"uv": [46, 171], "uv_size": [8, 8]}, + "down": {"uv": [54, 179], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone8", + "parent": "bone", + "pivot": [-23.5, 67.1, -2.1], + "cubes": [ + { + "origin": [-28.44583, 66.56781, -3.8], + "size": [8, 6, 7.5], + "pivot": [-23.5, 67.6, -3.9], + "rotation": [0, 0, -42.5], + "uv": { + "north": {"uv": [179, 194], "uv_size": [8, 6]}, + "east": {"uv": [195, 8], "uv_size": [8, 6]}, + "south": {"uv": [195, 190], "uv_size": [8, 6]}, + "west": {"uv": [196, 184], "uv_size": [8, 6]}, + "up": {"uv": [168, 16], "uv_size": [8, 8]}, + "down": {"uv": [38, 179], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "inner_ring", + "parent": "bone9", + "pivot": [0, 40, 0], + "cubes": [ + { + "origin": [-7.35976, 3, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [171, 168], "uv_size": [15, 4]}, + "east": {"uv": [48, 140], "uv_size": [4, 4]}, + "south": {"uv": [172, 0], "uv_size": [15, 4]}, + "west": {"uv": [74, 202], "uv_size": [4, 4]}, + "up": {"uv": [172, 4], "uv_size": [15, 4]}, + "down": {"uv": [172, 12], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 3, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [172, 12], "uv_size": [15, 4]}, + "east": {"uv": [78, 202], "uv_size": [4, 4]}, + "south": {"uv": [171, 172], "uv_size": [15, 4]}, + "west": {"uv": [110, 202], "uv_size": [4, 4]}, + "up": {"uv": [175, 160], "uv_size": [15, 4]}, + "down": {"uv": [175, 168], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 3, -2], + "size": [14.71952, 4, 4], + "uv": { + "north": {"uv": [176, 16], "uv_size": [15, 4]}, + "east": {"uv": [114, 202], "uv_size": [4, 4]}, + "south": {"uv": [176, 20], "uv_size": [15, 4]}, + "west": {"uv": [118, 202], "uv_size": [4, 4]}, + "up": {"uv": [176, 24], "uv_size": [15, 4]}, + "down": {"uv": [176, 32], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 3, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [176, 32], "uv_size": [15, 4]}, + "east": {"uv": [122, 202], "uv_size": [4, 4]}, + "south": {"uv": [176, 36], "uv_size": [15, 4]}, + "west": {"uv": [185, 202], "uv_size": [4, 4]}, + "up": {"uv": [176, 40], "uv_size": [15, 4]}, + "down": {"uv": [176, 48], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 3, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [176, 48], "uv_size": [15, 4]}, + "east": {"uv": [189, 202], "uv_size": [4, 4]}, + "south": {"uv": [176, 52], "uv_size": [15, 4]}, + "west": {"uv": [193, 202], "uv_size": [4, 4]}, + "up": {"uv": [176, 56], "uv_size": [15, 4]}, + "down": {"uv": [171, 180], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 73, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [38, 179], "uv_size": [15, 4]}, + "east": {"uv": [197, 202], "uv_size": [4, 4]}, + "south": {"uv": [53, 179], "uv_size": [15, 4]}, + "west": {"uv": [201, 202], "uv_size": [4, 4]}, + "up": {"uv": [68, 179], "uv_size": [15, 4]}, + "down": {"uv": [110, 183], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 73, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [171, 180], "uv_size": [15, 4]}, + "east": {"uv": [203, 8], "uv_size": [4, 4]}, + "south": {"uv": [38, 183], "uv_size": [15, 4]}, + "west": {"uv": [130, 203], "uv_size": [4, 4]}, + "up": {"uv": [53, 183], "uv_size": [15, 4]}, + "down": {"uv": [68, 187], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 73, -2], + "size": [14.71952, 4, 4], + "uv": { + "north": {"uv": [110, 183], "uv_size": [15, 4]}, + "east": {"uv": [134, 203], "uv_size": [4, 4]}, + "south": {"uv": [183, 145], "uv_size": [15, 4]}, + "west": {"uv": [138, 203], "uv_size": [4, 4]}, + "up": {"uv": [183, 149], "uv_size": [15, 4]}, + "down": {"uv": [143, 188], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 73, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [158, 184], "uv_size": [15, 4]}, + "east": {"uv": [142, 203], "uv_size": [4, 4]}, + "south": {"uv": [173, 184], "uv_size": [15, 4]}, + "west": {"uv": [146, 203], "uv_size": [4, 4]}, + "up": {"uv": [186, 168], "uv_size": [15, 4]}, + "down": {"uv": [186, 176], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 73, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [186, 176], "uv_size": [15, 4]}, + "east": {"uv": [150, 203], "uv_size": [4, 4]}, + "south": {"uv": [186, 180], "uv_size": [15, 4]}, + "west": {"uv": [203, 190], "uv_size": [4, 4]}, + "up": {"uv": [187, 0], "uv_size": [15, 4]}, + "down": {"uv": [187, 8], "uv_size": [15, -4]} + } + }, + { + "origin": [33, 32.64024, -2], + "size": [4, 14.71952, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [86, 171], "uv_size": [4, 15]}, + "east": {"uv": [83, 186], "uv_size": [4, 15]}, + "south": {"uv": [87, 186], "uv_size": [4, 15]}, + "west": {"uv": [26, 187], "uv_size": [4, 15]}, + "up": {"uv": [203, 194], "uv_size": [4, 4]}, + "down": {"uv": [203, 202], "uv_size": [4, -4]} + } + }, + { + "origin": [33, 32.64024, -2], + "size": [4, 14.71952, 4], + "uv": { + "north": {"uv": [30, 187], "uv_size": [4, 15]}, + "east": {"uv": [34, 187], "uv_size": [4, 15]}, + "south": {"uv": [38, 187], "uv_size": [4, 15]}, + "west": {"uv": [42, 187], "uv_size": [4, 15]}, + "up": {"uv": [0, 204], "uv_size": [4, 4]}, + "down": {"uv": [4, 208], "uv_size": [4, -4]} + } + }, + { + "origin": [33, 32.64024, -2], + "size": [4, 14.71952, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [46, 187], "uv_size": [4, 15]}, + "east": {"uv": [50, 187], "uv_size": [4, 15]}, + "south": {"uv": [54, 187], "uv_size": [4, 15]}, + "west": {"uv": [58, 187], "uv_size": [4, 15]}, + "up": {"uv": [8, 204], "uv_size": [4, 4]}, + "down": {"uv": [12, 208], "uv_size": [4, -4]} + } + }, + { + "origin": [-37, 32.64024, -2], + "size": [4, 14.71952, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [62, 187], "uv_size": [4, 15]}, + "east": {"uv": [66, 187], "uv_size": [4, 15]}, + "south": {"uv": [70, 187], "uv_size": [4, 15]}, + "west": {"uv": [74, 187], "uv_size": [4, 15]}, + "up": {"uv": [16, 204], "uv_size": [4, 4]}, + "down": {"uv": [20, 208], "uv_size": [4, -4]} + } + }, + { + "origin": [-37, 32.64024, -2], + "size": [4, 14.71952, 4], + "uv": { + "north": {"uv": [78, 187], "uv_size": [4, 15]}, + "east": {"uv": [110, 187], "uv_size": [4, 15]}, + "south": {"uv": [114, 187], "uv_size": [4, 15]}, + "west": {"uv": [118, 187], "uv_size": [4, 15]}, + "up": {"uv": [204, 151], "uv_size": [4, 4]}, + "down": {"uv": [154, 208], "uv_size": [4, -4]} + } + }, + { + "origin": [-37, 32.64024, -2], + "size": [4, 14.71952, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [122, 187], "uv_size": [4, 15]}, + "east": {"uv": [143, 188], "uv_size": [4, 15]}, + "south": {"uv": [147, 188], "uv_size": [4, 15]}, + "west": {"uv": [151, 188], "uv_size": [4, 15]}, + "up": {"uv": [158, 204], "uv_size": [4, 4]}, + "down": {"uv": [162, 208], "uv_size": [4, -4]} + } + } + ] + }, + { + "name": "portal", + "parent": "bone9", + "pivot": [0, 40, -0.7], + "cubes": [ + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [52, 79], "uv_size": [13, 66]}, + "east": {"uv": [100, 151], "uv_size": [1, 66]}, + "south": {"uv": [65, 79], "uv_size": [13, 66]}, + "west": {"uv": [101, 151], "uv_size": [1, 66]}, + "up": {"uv": [191, 59], "uv_size": [13, 1]}, + "down": {"uv": [201, 183], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [78, 79], "uv_size": [13, 66]}, + "east": {"uv": [102, 151], "uv_size": [1, 66]}, + "south": {"uv": [91, 79], "uv_size": [13, 66]}, + "west": {"uv": [103, 151], "uv_size": [1, 66]}, + "up": {"uv": [201, 183], "uv_size": [13, 1]}, + "down": {"uv": [203, 13], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "uv": { + "north": {"uv": [104, 79], "uv_size": [13, 66]}, + "east": {"uv": [104, 151], "uv_size": [1, 66]}, + "south": {"uv": [117, 79], "uv_size": [13, 66]}, + "west": {"uv": [105, 151], "uv_size": [1, 66]}, + "up": {"uv": [203, 13], "uv_size": [13, 1]}, + "down": {"uv": [204, 59], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [130, 65], "uv_size": [13, 66]}, + "east": {"uv": [106, 151], "uv_size": [1, 66]}, + "south": {"uv": [130, 131], "uv_size": [13, 66]}, + "west": {"uv": [107, 151], "uv_size": [1, 66]}, + "up": {"uv": [204, 59], "uv_size": [13, 1]}, + "down": {"uv": [166, 205], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [0, 132], "uv_size": [13, 66]}, + "east": {"uv": [108, 151], "uv_size": [1, 66]}, + "south": {"uv": [13, 132], "uv_size": [13, 66]}, + "west": {"uv": [109, 151], "uv_size": [1, 66]}, + "up": {"uv": [204, 184], "uv_size": [13, 1]}, + "down": {"uv": [204, 186], "uv_size": [13, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [143, 65], "uv_size": [66, 13]}, + "east": {"uv": [91, 180], "uv_size": [1, 13]}, + "south": {"uv": [143, 78], "uv_size": [66, 13]}, + "west": {"uv": [82, 187], "uv_size": [1, 13]}, + "up": {"uv": [143, 156], "uv_size": [66, 1]}, + "down": {"uv": [143, 158], "uv_size": [66, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "uv": { + "north": {"uv": [143, 91], "uv_size": [66, 13]}, + "east": {"uv": [126, 191], "uv_size": [1, 13]}, + "south": {"uv": [143, 104], "uv_size": [66, 13]}, + "west": {"uv": [127, 191], "uv_size": [1, 13]}, + "up": {"uv": [143, 158], "uv_size": [66, 1]}, + "down": {"uv": [143, 160], "uv_size": [66, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [143, 117], "uv_size": [66, 13]}, + "east": {"uv": [126, 204], "uv_size": [1, 13]}, + "south": {"uv": [143, 130], "uv_size": [66, 13]}, + "west": {"uv": [127, 204], "uv_size": [1, 13]}, + "up": {"uv": [159, 143], "uv_size": [66, 1]}, + "down": {"uv": [159, 145], "uv_size": [66, -1]} + } + } + ] + }, + { + "name": "portal2", + "parent": "bone9", + "pivot": [0, 40, -0.7], + "cubes": [ + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [0, 0], "uv_size": [13, 66]}, + "east": {"uv": [128, 145], "uv_size": [1, 66]}, + "south": {"uv": [13, 0], "uv_size": [13, 66]}, + "west": {"uv": [129, 145], "uv_size": [1, 66]}, + "up": {"uv": [78, 65], "uv_size": [13, 1]}, + "down": {"uv": [91, 66], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [26, 0], "uv_size": [13, 66]}, + "east": {"uv": [92, 151], "uv_size": [1, 66]}, + "south": {"uv": [39, 0], "uv_size": [13, 66]}, + "west": {"uv": [93, 151], "uv_size": [1, 66]}, + "up": {"uv": [104, 65], "uv_size": [13, 1]}, + "down": {"uv": [159, 154], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "uv": { + "north": {"uv": [52, 0], "uv_size": [13, 66]}, + "east": {"uv": [94, 151], "uv_size": [1, 66]}, + "south": {"uv": [65, 0], "uv_size": [13, 66]}, + "west": {"uv": [95, 151], "uv_size": [1, 66]}, + "up": {"uv": [159, 154], "uv_size": [13, 1]}, + "down": {"uv": [172, 154], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [0, 66], "uv_size": [13, 66]}, + "east": {"uv": [96, 151], "uv_size": [1, 66]}, + "south": {"uv": [13, 66], "uv_size": [13, 66]}, + "west": {"uv": [97, 151], "uv_size": [1, 66]}, + "up": {"uv": [172, 154], "uv_size": [13, 1]}, + "down": {"uv": [185, 154], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [26, 66], "uv_size": [13, 66]}, + "east": {"uv": [98, 151], "uv_size": [1, 66]}, + "south": {"uv": [39, 66], "uv_size": [13, 66]}, + "west": {"uv": [99, 151], "uv_size": [1, 66]}, + "up": {"uv": [185, 154], "uv_size": [13, 1]}, + "down": {"uv": [191, 59], "uv_size": [13, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [52, 66], "uv_size": [66, 13]}, + "east": {"uv": [126, 165], "uv_size": [1, 13]}, + "south": {"uv": [78, 0], "uv_size": [66, 13]}, + "west": {"uv": [127, 165], "uv_size": [1, 13]}, + "up": {"uv": [144, 60], "uv_size": [66, 1]}, + "down": {"uv": [144, 62], "uv_size": [66, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "uv": { + "north": {"uv": [78, 13], "uv_size": [66, 13]}, + "east": {"uv": [90, 167], "uv_size": [1, 13]}, + "south": {"uv": [78, 26], "uv_size": [66, 13]}, + "west": {"uv": [91, 167], "uv_size": [1, 13]}, + "up": {"uv": [144, 62], "uv_size": [66, 1]}, + "down": {"uv": [144, 64], "uv_size": [66, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [78, 39], "uv_size": [66, 13]}, + "east": {"uv": [126, 178], "uv_size": [1, 13]}, + "south": {"uv": [78, 52], "uv_size": [66, 13]}, + "west": {"uv": [127, 178], "uv_size": [1, 13]}, + "up": {"uv": [144, 64], "uv_size": [66, 1]}, + "down": {"uv": [143, 156], "uv_size": [66, -1]} + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/item/doomicorn.geo.json b/common/src/main/resources/assets/azurelib/geo/item/doomicorn.geo.json new file mode 100644 index 000000000..2f4ec1a72 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/item/doomicorn.geo.json @@ -0,0 +1,17113 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 64, + "texture_height": 64, + "visible_bounds_width": 4, + "visible_bounds_height": 4.5, + "visible_bounds_offset": [ + 0, + 1.75, + 0 + ] + }, + "bones": [ + { + "name": "bipedHead", + "pivot": [ + 0, + 24, + 0 + ] + }, + { + "name": "armorHead", + "parent": "bipedHead", + "pivot": [ + 0, + 24, + 0 + ] + }, + { + "name": "horn", + "parent": "armorHead", + "pivot": [ + 0, + 33, + -3 + ] + }, + { + "name": "group3", + "parent": "horn", + "pivot": [ + 8, + 34.7, + -12 + ], + "cubes": [ + { + "origin": [ + -0.75, + 38, + -5.75 + ], + "size": [ + 1.5, + 2, + 1.5 + ], + "pivot": [ + 0, + 38.7, + -5 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 25, + 23 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 25, + 23 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 24, + 24 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 24, + 25 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 24, + 25 + ], + "uv_size": [ + 1, + 1 + ] + } + } + }, + { + "origin": [ + -1, + 35, + -6 + ], + "size": [ + 2, + 3, + 2 + ], + "pivot": [ + 0, + 38.7, + -5 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 23, + 23 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 23, + 24 + ], + "uv_size": [ + 2, + 3 + ] + }, + "south": { + "uv": [ + 23, + 24 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 23, + 22 + ], + "uv_size": [ + 2, + 3 + ] + }, + "up": { + "uv": [ + 23, + 23 + ], + "uv_size": [ + 2, + 2 + ] + } + } + }, + { + "origin": [ + -0.4, + 40, + -5.4 + ], + "size": [ + 0.8, + 1.2, + 0.8 + ], + "pivot": [ + 0, + 38.7, + -5 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 24, + 23 + ], + "uv_size": [ + 0, + 1 + ] + }, + "east": { + "uv": [ + 25, + 25 + ], + "uv_size": [ + 0, + 1 + ] + }, + "south": { + "uv": [ + 25, + 25 + ], + "uv_size": [ + 0, + 1 + ] + }, + "west": { + "uv": [ + 25, + 23 + ], + "uv_size": [ + 0, + 1 + ] + }, + "up": { + "uv": [ + 26, + 26 + ], + "uv_size": [ + 0, + 0 + ] + } + } + } + ] + }, + { + "name": "bone2", + "parent": "horn", + "pivot": [ + 8, + 31.7, + -16.5 + ], + "cubes": [ + { + "origin": [ + -2.5, + 32.7, + -6 + ], + "size": [ + 5, + 3, + 7 + ], + "uv": { + "north": { + "uv": [ + 10, + 3 + ], + "uv_size": [ + 5, + 3 + ] + }, + "east": { + "uv": [ + 7, + 0 + ], + "uv_size": [ + -7, + 3 + ] + }, + "south": { + "uv": [ + 10, + 4 + ], + "uv_size": [ + 5, + 3 + ] + }, + "west": { + "uv": [ + 0, + 0 + ], + "uv_size": [ + 7, + 3 + ] + }, + "up": { + "uv": [ + 9, + 1 + ], + "uv_size": [ + 5, + 7 + ] + }, + "down": { + "uv": [ + 9, + 8 + ], + "uv_size": [ + 5, + -7 + ] + } + } + }, + { + "origin": [ + -0.5, + 35.7, + -2.3 + ], + "size": [ + 1, + 1.2, + 3.3 + ], + "uv": { + "north": { + "uv": [ + 21, + 23 + ], + "uv_size": [ + 5, + 3 + ] + }, + "east": { + "uv": [ + 23, + 24 + ], + "uv_size": [ + 3, + 3 + ] + }, + "south": { + "uv": [ + 22, + 23 + ], + "uv_size": [ + 5, + 3 + ] + }, + "west": { + "uv": [ + 22, + 23 + ], + "uv_size": [ + 5, + 3 + ] + }, + "up": { + "uv": [ + 22, + 22 + ], + "uv_size": [ + 4, + 5 + ] + } + } + }, + { + "origin": [ + -0.5, + 33, + -2.1 + ], + "size": [ + 1, + 2.2, + 5.5 + ], + "pivot": [ + -2.5, + 32.5, + 1.4 + ], + "rotation": [ + -47.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 21, + 23 + ], + "uv_size": [ + 5, + 3 + ] + }, + "east": { + "uv": [ + 23, + 24 + ], + "uv_size": [ + 3, + 3 + ] + }, + "west": { + "uv": [ + 22, + 23 + ], + "uv_size": [ + 5, + 3 + ] + } + } + }, + { + "origin": [ + 0.6, + 34.8, + -0.9 + ], + "size": [ + 1.8, + 2.8, + 0.8 + ], + "uv": { + "north": { + "uv": [ + 10, + 3 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 3 + ] + }, + "south": { + "uv": [ + 11, + 2 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 14, + 3 + ], + "uv_size": [ + 1, + 3 + ] + }, + "up": { + "uv": [ + 10, + 3 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + -2.4, + 34.8, + -0.9 + ], + "size": [ + 1.8, + 2.8, + 0.8 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 3 + ] + }, + "south": { + "uv": [ + 11, + 2 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 12, + 2 + ], + "uv_size": [ + 1, + 3 + ] + }, + "up": { + "uv": [ + 10, + 3 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + -2, + 32.7, + -8 + ], + "size": [ + 4, + 3, + 2 + ], + "uv": { + "north": { + "uv": [ + 10, + 3 + ], + "uv_size": [ + 4, + 3 + ] + }, + "east": { + "uv": [ + 12, + 3 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 12, + 2 + ], + "uv_size": [ + 2, + 3 + ] + }, + "up": { + "uv": [ + 11, + 4 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 10, + 5 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + -1, + 32.7, + 0.5 + ], + "size": [ + 2, + 1.9, + 2 + ], + "uv": { + "east": { + "uv": [ + 11, + 0 + ], + "uv_size": [ + 2, + 8 + ] + }, + "south": { + "uv": [ + 11, + 0 + ], + "uv_size": [ + 2, + 8 + ] + }, + "west": { + "uv": [ + 11, + 0 + ], + "uv_size": [ + 2, + 8 + ] + }, + "up": { + "uv": [ + 13, + 3 + ], + "uv_size": [ + 2, + 2 + ] + } + } + } + ] + }, + { + "name": "bone5", + "parent": "armorHead", + "pivot": [ + 0, + 0, + 0 + ], + "cubes": [ + { + "origin": [ + 2, + 24, + -5 + ], + "size": [ + 3, + 2, + 1 + ], + "uv": { + "north": { + "uv": [ + 46, + 14 + ], + "uv_size": [ + 3, + 2 + ] + }, + "west": { + "uv": [ + 48, + 14 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 41, + 14 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 46, + 16 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 24, + -5 + ], + "size": [ + 3, + 2, + 1 + ], + "uv": { + "north": { + "uv": [ + 39, + 14 + ], + "uv_size": [ + 3, + 2 + ] + }, + "east": { + "uv": [ + 39, + 14 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 41, + 14 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 39, + 16 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 26, + -5 + ], + "size": [ + 2, + 1, + 1 + ], + "uv": { + "north": { + "uv": [ + 39, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 39, + 13 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 39, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 41, + 14 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 27, + -5 + ], + "size": [ + 1, + 3, + 1 + ], + "uv": { + "north": { + "uv": [ + 39, + 10 + ], + "uv_size": [ + 1, + 3 + ] + }, + "east": { + "uv": [ + 39, + 10 + ], + "uv_size": [ + 1, + 3 + ] + }, + "west": { + "uv": [ + 39, + 10 + ], + "uv_size": [ + 1, + 3 + ] + } + } + }, + { + "origin": [ + 4, + 27, + -5 + ], + "size": [ + 1, + 3, + 1 + ], + "uv": { + "north": { + "uv": [ + 39, + 10 + ], + "uv_size": [ + 1, + 3 + ] + }, + "east": { + "uv": [ + 39, + 10 + ], + "uv_size": [ + 1, + 3 + ] + }, + "west": { + "uv": [ + 48, + 10 + ], + "uv_size": [ + 1, + 3 + ] + } + } + }, + { + "origin": [ + -5, + 30, + -5 + ], + "size": [ + 10, + 1, + 1 + ], + "uv": { + "north": { + "uv": [ + 39, + 9 + ], + "uv_size": [ + 10, + 1 + ] + }, + "east": { + "uv": [ + 39, + 9 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 48, + 9 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 49, + 10 + ], + "uv_size": [ + -10, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 31, + -5 + ], + "size": [ + 10, + 2, + 1 + ], + "uv": { + "north": { + "uv": [ + 59, + 8 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 59, + 8 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 59, + 8 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 61, + 9 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -2, + 29, + -5 + ], + "size": [ + 4, + 1, + 1 + ], + "uv": { + "north": { + "uv": [ + 42, + 10 + ], + "uv_size": [ + 4, + 1 + ] + }, + "east": { + "uv": [ + 42, + 10 + ], + "uv_size": [ + 4, + 1 + ] + }, + "west": { + "uv": [ + 42, + 10 + ], + "uv_size": [ + 4, + 1 + ] + }, + "down": { + "uv": [ + 46, + 11 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 3, + 26, + -5 + ], + "size": [ + 2, + 1, + 1 + ], + "uv": { + "north": { + "uv": [ + 47, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 39, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 48, + 13 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 49, + 14 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -2, + 24, + -5 + ], + "size": [ + 4, + 2, + 9 + ], + "uv": { + "north": { + "uv": [ + 42, + 14 + ], + "uv_size": [ + 4, + 2 + ] + }, + "up": { + "uv": [ + 41, + 14 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 46, + 16 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + -1, + 26, + -5 + ], + "size": [ + 2, + 1, + 1 + ], + "uv": { + "north": { + "uv": [ + 43, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 8, + 6 + ], + "uv_size": [ + 8, + 1 + ] + }, + "west": { + "uv": [ + 8, + 6 + ], + "uv_size": [ + 8, + 1 + ] + }, + "up": { + "uv": [ + 16, + 7 + ], + "uv_size": [ + -8, + -1 + ] + } + } + }, + { + "origin": [ + -4, + 27, + -4.5 + ], + "size": [ + 8, + 2, + 0.1 + ], + "uv": { + "north": { + "uv": [ + 40, + 11 + ], + "uv_size": [ + 8, + 2 + ] + }, + "south": { + "uv": [ + 42, + 11 + ], + "uv_size": [ + 4, + 2 + ] + } + } + }, + { + "origin": [ + 1, + 26, + -4.5 + ], + "size": [ + 2, + 1, + 0.1 + ], + "uv": { + "north": { + "uv": [ + 45, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 11 + ], + "uv_size": [ + 4, + 2 + ] + } + } + }, + { + "origin": [ + -3, + 26, + -4.5 + ], + "size": [ + 2, + 1, + 0.1 + ], + "uv": { + "north": { + "uv": [ + 41, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 11 + ], + "uv_size": [ + 4, + 2 + ] + } + } + }, + { + "origin": [ + -4, + 29, + -4.5 + ], + "size": [ + 2, + 1, + 0.1 + ], + "uv": { + "north": { + "uv": [ + 40, + 10 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 11 + ], + "uv_size": [ + 4, + 2 + ] + } + } + }, + { + "origin": [ + 2, + 29, + -4.5 + ], + "size": [ + 2, + 1, + 0.1 + ], + "uv": { + "north": { + "uv": [ + 46, + 10 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 11 + ], + "uv_size": [ + 4, + 2 + ] + } + } + }, + { + "origin": [ + -5, + 32, + -2 + ], + "size": [ + 10, + 1, + 6 + ], + "uv": { + "east": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "up": { + "uv": [ + 48, + 7 + ], + "uv_size": [ + -8, + -6 + ] + } + } + }, + { + "origin": [ + -5, + 32, + -4 + ], + "size": [ + 10, + 1, + 2 + ], + "uv": { + "east": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "up": { + "uv": [ + 11, + 6 + ], + "uv_size": [ + -3, + -5 + ] + } + } + }, + { + "origin": [ + -5, + 25, + 4 + ], + "size": [ + 10, + 1, + 1 + ], + "pivot": [ + 5, + 25, + 4 + ], + "rotation": [ + -90, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "east": { + "uv": [ + 54, + 15 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 54, + 15 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 59, + 16 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 33, + 4 + ], + "size": [ + 10, + 1, + 1 + ], + "pivot": [ + 5, + 33, + 4 + ], + "rotation": [ + -90, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "east": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "up": { + "uv": [ + 61, + 9 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 4, + 32, + 4 + ], + "size": [ + 1, + 1, + 7 + ], + "pivot": [ + 5, + 32, + 4 + ], + "rotation": [ + -90, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 57, + 15 + ], + "uv_size": [ + 7, + 1 + ] + }, + "up": { + "uv": [ + 58, + 16 + ], + "uv_size": [ + -1, + -7 + ] + } + } + }, + { + "origin": [ + -5, + 32, + 4 + ], + "size": [ + 1, + 1, + 7 + ], + "pivot": [ + -4, + 32, + 4 + ], + "rotation": [ + -90, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "east": { + "uv": [ + 57, + 15 + ], + "uv_size": [ + 7, + 1 + ] + }, + "up": { + "uv": [ + 63, + 16 + ], + "uv_size": [ + -1, + -7 + ] + } + } + }, + { + "origin": [ + -4, + 32, + 4 + ], + "size": [ + 8, + 1, + 7 + ], + "pivot": [ + 3.5, + 32, + 4 + ], + "rotation": [ + -90, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 40, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "up": { + "uv": [ + 63, + 16 + ], + "uv_size": [ + -6, + -7 + ] + } + } + }, + { + "origin": [ + 2, + 24, + -4 + ], + "size": [ + 3, + 6, + 7 + ], + "uv": { + "west": { + "uv": [ + 49, + 10 + ], + "uv_size": [ + 6, + 6 + ] + }, + "down": { + "uv": [ + 54, + 14 + ], + "uv_size": [ + -5, + -4 + ] + } + } + }, + { + "origin": [ + -5, + 24, + -4 + ], + "size": [ + 3, + 6, + 7 + ], + "uv": { + "east": { + "uv": [ + 32, + 10 + ], + "uv_size": [ + 7, + 6 + ] + }, + "down": { + "uv": [ + 49, + 14 + ], + "uv_size": [ + 5, + -4 + ] + } + } + }, + { + "origin": [ + 4, + 30, + -4 + ], + "size": [ + 1, + 2, + 7 + ], + "uv": { + "west": { + "uv": [ + 49, + 8 + ], + "uv_size": [ + 6, + 2 + ] + } + } + }, + { + "origin": [ + -5, + 30, + -4 + ], + "size": [ + 1, + 2, + 7 + ], + "uv": { + "east": { + "uv": [ + 55, + 8 + ], + "uv_size": [ + -6, + 2 + ] + } + } + }, + { + "origin": [ + 2, + 24, + 3 + ], + "size": [ + 3, + 6, + 1 + ], + "uv": { + "south": { + "uv": [ + 0, + 0 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 54, + 10 + ], + "uv_size": [ + 1, + 6 + ] + }, + "down": { + "uv": [ + 46, + 16 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 24, + 3 + ], + "size": [ + 3, + 6, + 1 + ], + "uv": { + "east": { + "uv": [ + 54, + 10 + ], + "uv_size": [ + 1, + 6 + ] + }, + "south": { + "uv": [ + 0, + 0 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 46, + 16 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + 4, + 30, + 3 + ], + "size": [ + 1, + 2, + 1 + ], + "uv": { + "west": { + "uv": [ + 54, + 10 + ], + "uv_size": [ + 1, + 2 + ] + } + } + }, + { + "origin": [ + -5, + 30, + 3 + ], + "size": [ + 1, + 2, + 1 + ], + "uv": { + "east": { + "uv": [ + 54, + 10 + ], + "uv_size": [ + 1, + 2 + ] + } + } + } + ] + }, + { + "name": "bipedBody", + "pivot": [ + 0, + 24, + 0 + ] + }, + { + "name": "armorBody", + "parent": "bipedBody", + "pivot": [ + 0, + 24, + 0 + ] + }, + { + "name": "bone", + "parent": "armorBody", + "pivot": [ + 0, + 21.3, + 3.1 + ] + }, + { + "name": "group", + "parent": "bone", + "pivot": [ + 0.10714, + 20.31429, + 3.4 + ], + "cubes": [ + { + "origin": [ + -0.35, + 20.5, + 2.3 + ], + "size": [ + 12.1, + 1.6, + 1.6 + ], + "inflate": 0.1, + "pivot": [ + 1.2, + 21.3, + 3.1 + ], + "rotation": [ + 0, + 0, + -22.5 + ], + "uv": { + "north": { + "uv": [ + 22, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 23, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 22, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 23, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 22, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 22, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 5.67, + 21.27, + 2.32 + ], + "size": [ + 7.56, + 1.56, + 1.56 + ], + "inflate": 0.06, + "pivot": [ + 7.2, + 21.3, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 21, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 10.155, + 23.505, + 2.305 + ], + "size": [ + 9.09, + 1.59, + 1.59 + ], + "inflate": 0.09, + "pivot": [ + 11.7, + 24.3, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 21, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 8.66, + 22.76, + 2.31 + ], + "size": [ + 9.08, + 1.58, + 1.58 + ], + "inflate": 0.08, + "pivot": [ + 10.2, + 22.8, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 21, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 2.68, + 19.78, + 2.33 + ], + "size": [ + 6.04, + 1.54, + 1.54 + ], + "inflate": 0.04, + "pivot": [ + 4.2, + 19.8, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 21, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 7.165, + 22.015, + 2.315 + ], + "size": [ + 7.57, + 1.57, + 1.57 + ], + "inflate": 0.07, + "pivot": [ + 8.7, + 21.3, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 20, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 4.175, + 20.525, + 2.325 + ], + "size": [ + 6.05, + 1.55, + 1.55 + ], + "inflate": 0.05, + "pivot": [ + 5.7, + 19.8, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + } + ] + }, + { + "name": "group2", + "parent": "bone", + "pivot": [ + -0.19286, + 20.31429, + 3.6 + ], + "rotation": [ + -180, + 0, + 180 + ], + "cubes": [ + { + "origin": [ + -0.65, + 20.5, + 3.3 + ], + "size": [ + 12.1, + 1.6, + 1.6 + ], + "inflate": 0.1, + "pivot": [ + 0.9, + 21.3, + 4.1 + ], + "rotation": [ + 0, + 0, + -22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 25, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 25, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 23, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 5.37, + 21.27, + 3.32 + ], + "size": [ + 7.56, + 1.56, + 1.56 + ], + "inflate": 0.06, + "pivot": [ + 6.9, + 21.3, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 23, + 23 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 21, + 24 + ], + "uv_size": [ + 5, + 1 + ] + }, + "down": { + "uv": [ + 22, + 25 + ], + "uv_size": [ + 5, + -1 + ] + } + } + }, + { + "origin": [ + 9.855, + 23.505, + 3.305 + ], + "size": [ + 9.09, + 1.59, + 1.59 + ], + "inflate": 0.09, + "pivot": [ + 11.4, + 24.3, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 26, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 23, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 8.36, + 22.76, + 3.31 + ], + "size": [ + 9.08, + 1.58, + 1.58 + ], + "inflate": 0.08, + "pivot": [ + 9.9, + 22.8, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 23, + 23 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 24, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 21, + 25 + ], + "uv_size": [ + 6, + -1 + ] + } + } + }, + { + "origin": [ + 2.38, + 19.78, + 3.33 + ], + "size": [ + 6.04, + 1.54, + 1.54 + ], + "inflate": 0.04, + "pivot": [ + 3.9, + 19.8, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 26, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 23, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 6.865, + 22.015, + 3.315 + ], + "size": [ + 7.57, + 1.57, + 1.57 + ], + "inflate": 0.07, + "pivot": [ + 8.4, + 21.3, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 23, + 23 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 24, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 21, + 25 + ], + "uv_size": [ + 5, + -1 + ] + } + } + }, + { + "origin": [ + 3.875, + 20.525, + 3.325 + ], + "size": [ + 6.05, + 1.55, + 1.55 + ], + "inflate": 0.05, + "pivot": [ + 5.4, + 19.8, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 23, + 25 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 25, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 22, + 24 + ], + "uv_size": [ + 4, + 1 + ] + }, + "down": { + "uv": [ + 22, + 25 + ], + "uv_size": [ + 4, + -1 + ] + } + } + } + ] + }, + { + "name": "bone3", + "parent": "armorBody", + "pivot": [ + 0, + 24, + 0 + ], + "cubes": [ + { + "origin": [ + -4, + 12, + -2 + ], + "size": [ + 8, + 12, + 4 + ], + "uv": { + "north": { + "uv": [ + 20, + 20 + ], + "uv_size": [ + 8, + 12 + ] + }, + "south": { + "uv": [ + 32, + 20 + ], + "uv_size": [ + 8, + 12 + ] + } + } + } + ] + }, + { + "name": "bone15", + "parent": "bone3", + "pivot": [ + 0, + 18, + -2.3 + ], + "cubes": [ + { + "origin": [ + -4.1, + 12, + -2.4 + ], + "size": [ + 8.2, + 3, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 20, + 45 + ], + "uv_size": [ + 8, + 3 + ] + }, + "east": { + "uv": [ + 20, + 45 + ], + "uv_size": [ + 1, + 3 + ] + }, + "west": { + "uv": [ + 27, + 45 + ], + "uv_size": [ + 1, + 3 + ] + }, + "up": { + "uv": [ + 20, + 38 + ], + "uv_size": [ + 8, + 1 + ] + }, + "down": { + "uv": [ + 20, + 47 + ], + "uv_size": [ + 8, + 1 + ] + } + } + }, + { + "origin": [ + -4.1, + 12, + 2.1 + ], + "size": [ + 8.2, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 8, + 1 + ] + }, + "east": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 8, + 1 + ] + }, + "west": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 40, + 48 + ], + "uv_size": [ + -8, + -1 + ] + }, + "down": { + "uv": [ + 40, + 48 + ], + "uv_size": [ + -8, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 13, + 2.1 + ], + "size": [ + 3.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 46 + ], + "uv_size": [ + -3, + 1 + ] + }, + "east": { + "uv": [ + 34, + 46 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 32, + 46 + ], + "uv_size": [ + 3, + 1 + ] + }, + "west": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 35, + 47 + ], + "uv_size": [ + -3, + -1 + ] + } + } + }, + { + "origin": [ + -4.1, + 13, + 2.1 + ], + "size": [ + 3.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 32, + 46 + ], + "uv_size": [ + 3, + 1 + ] + }, + "east": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + 3, + 1 + ] + }, + "west": { + "uv": [ + 34, + 46 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 40, + 47 + ], + "uv_size": [ + -3, + -1 + ] + } + } + }, + { + "origin": [ + -1, + 14, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -1, + 16, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 17, + 2.1 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -2, + 17, + 2.1 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 19, + 2.1 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 32, + 41 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 32, + 41 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 32, + 41 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 32, + 41 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 33, + 42 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1, + 18, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -4, + 20, + 2.1 + ], + "size": [ + 8.1, + 2, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 32, + 38 + ], + "uv_size": [ + 8, + 2 + ] + }, + "east": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 32, + 38 + ], + "uv_size": [ + 8, + 2 + ] + }, + "west": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 40, + 39 + ], + "uv_size": [ + -8, + -1 + ] + }, + "down": { + "uv": [ + 40, + 40 + ], + "uv_size": [ + -8, + -1 + ] + } + } + }, + { + "origin": [ + -2.1, + 23, + 2.1 + ], + "size": [ + 4.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 34, + 36 + ], + "uv_size": [ + 4, + 1 + ] + }, + "east": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 34, + 36 + ], + "uv_size": [ + 4, + 1 + ] + }, + "west": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + } + } + }, + { + "origin": [ + -3.1, + 22, + 2.1 + ], + "size": [ + 6.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 33, + 37 + ], + "uv_size": [ + 6, + 1 + ] + }, + "east": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 33, + 37 + ], + "uv_size": [ + 6, + 1 + ] + }, + "west": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + -6, + -1 + ] + } + } + }, + { + "origin": [ + -2, + 19, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 36, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 37, + 40 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 36, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 36, + 40 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 38, + 41 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 3, + 18, + 2.1 + ], + "size": [ + 1.1, + 2, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 32, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 32, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 32, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 33, + 42 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -4, + 18, + 2.1 + ], + "size": [ + 1.1, + 2, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 39, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 39, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 39, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 40, + 42 + ], + "uv_size": [ + -1, + -2 + ] + } + } + }, + { + "origin": [ + -3, + 15, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 38, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 37, + 44 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 39, + 45 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 15, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 33, + 44 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 33, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -3.1, + 15, + -2.1 + ], + "size": [ + 6.2, + 2, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 6, + 2 + ] + }, + "east": { + "uv": [ + 26, + 43 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 26, + 43 + ], + "uv_size": [ + 1, + 2 + ] + } + } + }, + { + "origin": [ + -3.1, + 22, + -2.4 + ], + "size": [ + 6.2, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 21, + 37 + ], + "uv_size": [ + 6, + 1 + ] + }, + "east": { + "uv": [ + 21, + 37 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 21, + 37 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 27, + 38 + ], + "uv_size": [ + -6, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 23, + -2.4 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + } + } + }, + { + "origin": [ + 2, + 20, + -2.7 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 26, + 39 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 26, + 39 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 26, + 39 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 27, + 40 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 27, + 40 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -2.1, + 23, + -2.4 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + } + } + }, + { + "origin": [ + -4.1, + 17, + -2.4 + ], + "size": [ + 8.2, + 5, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 20, + 38 + ], + "uv_size": [ + 8, + 5 + ] + }, + "east": { + "uv": [ + 20, + 38 + ], + "uv_size": [ + 1, + 5 + ] + }, + "west": { + "uv": [ + 27, + 38 + ], + "uv_size": [ + 1, + 5 + ] + }, + "up": { + "uv": [ + 20, + 38 + ], + "uv_size": [ + 8, + 1 + ] + }, + "down": { + "uv": [ + 20, + 47 + ], + "uv_size": [ + 8, + 1 + ] + } + } + } + ] + }, + { + "name": "bipedRightArm", + "pivot": [ + -4, + 22, + 0 + ] + }, + { + "name": "armorRightArm", + "parent": "bipedRightArm", + "pivot": [ + -4, + 22, + 0 + ] + }, + { + "name": "bone11", + "parent": "armorRightArm", + "pivot": [ + -4, + 22, + 0 + ], + "cubes": [ + { + "origin": [ + -8.1, + 11.9, + -2.1 + ], + "size": [ + 4.2, + 12.1, + 4.2 + ], + "uv": { + "north": { + "uv": [ + 44, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "east": { + "uv": [ + 40, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "south": { + "uv": [ + 52, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "west": { + "uv": [ + 48, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "up": { + "uv": [ + 44, + 20 + ], + "uv_size": [ + 4, + -4 + ] + } + } + } + ] + }, + { + "name": "armorRightOut", + "parent": "bone11", + "pivot": [ + -7.1, + 24.1, + 2 + ], + "cubes": [ + { + "origin": [ + -8.45, + 20, + -2.25 + ], + "size": [ + 0.35, + 3.1, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 43, + 37 + ], + "uv_size": [ + 1, + 3 + ] + }, + "east": { + "uv": [ + 40, + 37 + ], + "uv_size": [ + 4, + 3 + ] + }, + "south": { + "uv": [ + 43, + 37 + ], + "uv_size": [ + 1, + 3 + ] + }, + "west": { + "uv": [ + 40, + 37 + ], + "uv_size": [ + 4, + 3 + ] + }, + "up": { + "uv": [ + 44, + 40 + ], + "uv_size": [ + -1, + -3 + ] + }, + "down": { + "uv": [ + 44, + 40 + ], + "uv_size": [ + -1, + -3 + ] + } + } + }, + { + "origin": [ + -8.45, + 17, + 1.15 + ], + "size": [ + 0.35, + 1, + 1.1 + ], + "uv": { + "north": { + "uv": [ + 40, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 40, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 40, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 41, + 43 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -3.95, + 16, + 1.15 + ], + "size": [ + 0.35, + 1, + 1.1 + ], + "uv": { + "east": { + "uv": [ + 51, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 51, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 51, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 52, + 44 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 23.1, + -1.15 + ], + "size": [ + 0.35, + 0.9, + 2.3 + ], + "uv": { + "north": { + "uv": [ + 41, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 41, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 41, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 43, + 37 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -7.25, + 23, + 2.55 + ], + "size": [ + 0.35, + 1.1, + 2.3 + ], + "pivot": [ + -7.25, + 23, + 2.45 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 53, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 53, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 53, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 55, + 37 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 55, + 37 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -8.35, + 20.05, + 2.55 + ], + "size": [ + 0.25, + 2.95, + 1.2 + ], + "pivot": [ + -8.35, + 22, + 2.45 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 53, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 53, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 55, + 37 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 55, + 37 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -8.35, + 16, + 2.55 + ], + "size": [ + 0.35, + 2, + 2.3 + ], + "pivot": [ + -8.35, + 17, + 2.45 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 42 + ], + "uv_size": [ + 2, + 2 + ] + }, + "east": { + "uv": [ + 54, + 42 + ], + "uv_size": [ + 2, + 2 + ] + }, + "up": { + "uv": [ + 56, + 44 + ], + "uv_size": [ + -2, + -2 + ] + }, + "down": { + "uv": [ + 56, + 44 + ], + "uv_size": [ + -2, + -2 + ] + } + } + }, + { + "origin": [ + -6.25, + 16, + 2.75 + ], + "size": [ + 0.35, + 1, + 2.1 + ], + "pivot": [ + -6.25, + 17, + 2.45 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 52, + 43 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 52, + 43 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 54, + 44 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 54, + 44 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -8.25, + 11.9, + 2.55 + ], + "size": [ + 0.35, + 4.1, + 4.3 + ], + "pivot": [ + -8.25, + 11.9, + 2.45 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 61, + 60 + ], + "uv_size": [ + -1, + 4 + ] + }, + "east": { + "uv": [ + 64, + 60 + ], + "uv_size": [ + -4, + 4 + ] + }, + "up": { + "uv": [ + 61, + 60 + ], + "uv_size": [ + -1, + 4 + ] + }, + "down": { + "uv": [ + 61, + 53 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -7.35, + 23.1, + -2.05 + ], + "size": [ + 0.35, + 0.9, + 2.3 + ], + "pivot": [ + -7.25, + 23, + -2.15 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 55, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "east": { + "uv": [ + 45, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "west": { + "uv": [ + 45, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + }, + "down": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 16, + -2.05 + ], + "size": [ + 0.35, + 1, + 3.4 + ], + "pivot": [ + -8.35, + 16, + -2.15 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + -2, + 1 + ] + }, + "east": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + -2, + 1 + ] + }, + "south": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + -2, + 1 + ] + }, + "west": { + "uv": [ + 44, + 43 + ], + "uv_size": [ + 3, + 1 + ] + }, + "up": { + "uv": [ + 54, + 60 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 21, + -2.05 + ], + "size": [ + 0.35, + 2.1, + 4.5 + ], + "pivot": [ + -8.35, + 22, + -2.15 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 55, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "east": { + "uv": [ + 48, + 37 + ], + "uv_size": [ + -4, + 2 + ] + }, + "south": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "west": { + "uv": [ + 44, + 37 + ], + "uv_size": [ + 4, + 2 + ] + }, + "up": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + }, + "down": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 20, + -2.05 + ], + "size": [ + 0.35, + 1, + 3.4 + ], + "pivot": [ + -8.35, + 21, + -2.15 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 55, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "east": { + "uv": [ + 52, + 53 + ], + "uv_size": [ + 4, + 2 + ] + }, + "south": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "west": { + "uv": [ + 44, + 39 + ], + "uv_size": [ + 3, + 1 + ] + }, + "down": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 11.9, + -2.05 + ], + "size": [ + 0.35, + 4.1, + 4.5 + ], + "pivot": [ + -8.35, + 15, + -2.15 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + -1, + 4 + ] + }, + "east": { + "uv": [ + 52, + 60 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 53, + 60 + ], + "uv_size": [ + -1, + 4 + ] + }, + "west": { + "uv": [ + 44, + 44 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + }, + "down": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 11.9, + -2.25 + ], + "size": [ + 0.35, + 5.1, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 43, + 43 + ], + "uv_size": [ + 1, + 5 + ] + }, + "east": { + "uv": [ + 40, + 43 + ], + "uv_size": [ + 4, + 5 + ] + }, + "south": { + "uv": [ + 40, + 43 + ], + "uv_size": [ + 1, + 5 + ] + }, + "west": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + 4, + 5 + ] + }, + "up": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + 3, + -1 + ] + }, + "down": { + "uv": [ + 55, + 64 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -3.95, + 11.9, + -2.25 + ], + "size": [ + 0.35, + 4.1, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 49, + 59 + ], + "uv_size": [ + 4, + 5 + ] + }, + "east": { + "uv": [ + 52, + 44 + ], + "uv_size": [ + -4, + 4 + ] + }, + "south": { + "uv": [ + 49, + 59 + ], + "uv_size": [ + 4, + 5 + ] + }, + "west": { + "uv": [ + 48, + 44 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -7.1, + 24, + -2.3 + ], + "size": [ + 2.2, + 0.2, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 45, + 35 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 54, + 49 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 45, + 32 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 47, + 32 + ], + "uv_size": [ + -2, + 4 + ] + }, + "down": { + "uv": [ + 47, + 36 + ], + "uv_size": [ + -2, + -4 + ] + } + } + }, + { + "origin": [ + -8.2, + 11.9, + -2.2 + ], + "size": [ + 4.4, + 0.2, + 4.4 + ], + "uv": { + "north": { + "uv": [ + 55, + 48 + ], + "uv_size": [ + -2, + 1 + ] + }, + "south": { + "uv": [ + 53, + 48 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 52, + 36 + ], + "uv_size": [ + -4, + -4 + ] + }, + "down": { + "uv": [ + 52, + 36 + ], + "uv_size": [ + -4, + -4 + ] + } + } + }, + { + "origin": [ + -8.2, + 24, + -1.3 + ], + "size": [ + 1.1, + 0.2, + 2.5 + ], + "uv": { + "north": { + "uv": [ + 55, + 49 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 55, + 49 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 55, + 49 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 45, + 35 + ], + "uv_size": [ + -1, + -2 + ] + }, + "down": { + "uv": [ + 45, + 35 + ], + "uv_size": [ + -1, + -2 + ] + } + } + } + ] + }, + { + "name": "bipedLeftArm", + "pivot": [ + 4, + 22, + 0 + ] + }, + { + "name": "armorLeftArm", + "parent": "bipedLeftArm", + "pivot": [ + 4, + 22, + 0 + ] + }, + { + "name": "bone8", + "parent": "armorLeftArm", + "pivot": [ + -4, + 22, + 0 + ], + "cubes": [ + { + "origin": [ + 3.9, + 11.9, + -2.1 + ], + "size": [ + 4.2, + 12.2, + 4.2 + ], + "uv": { + "north": { + "uv": [ + 36, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "east": { + "uv": [ + 32, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "south": { + "uv": [ + 44, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "west": { + "uv": [ + 40, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "up": { + "uv": [ + 36, + 48 + ], + "uv_size": [ + 4, + 4 + ] + } + } + } + ] + }, + { + "name": "armorLeftArmOut", + "parent": "bone8", + "pivot": [ + 7.1, + 24.1, + 2 + ], + "cubes": [ + { + "origin": [ + 8.1, + 18, + -2.25 + ], + "size": [ + 0.35, + 5, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 56, + 53 + ], + "uv_size": [ + 1, + 5 + ] + }, + "east": { + "uv": [ + 60, + 53 + ], + "uv_size": [ + -4, + 5 + ] + }, + "south": { + "uv": [ + 59, + 53 + ], + "uv_size": [ + 1, + 5 + ] + }, + "west": { + "uv": [ + 56, + 53 + ], + "uv_size": [ + 4, + 5 + ] + }, + "up": { + "uv": [ + 57, + 57 + ], + "uv_size": [ + -1, + -4 + ] + }, + "down": { + "uv": [ + 60, + 57 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 17, + -1.25 + ], + "size": [ + 0.35, + 1, + 3.5 + ], + "uv": { + "north": { + "uv": [ + 58, + 58 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 59, + 58 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 57, + 58 + ], + "uv_size": [ + 3, + 1 + ] + } + } + }, + { + "origin": [ + 8.1, + 23, + -1.15 + ], + "size": [ + 0.35, + 1, + 2.3 + ], + "uv": { + "north": { + "uv": [ + 57, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 57, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 57, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 59, + 53 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 6.9, + 23, + 2.55 + ], + "size": [ + 0.35, + 1, + 2.3 + ], + "pivot": [ + 7.25, + 23, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 20.95, + 2.55 + ], + "size": [ + 0.25, + 2.05, + 1.2 + ], + "pivot": [ + 8.35, + 22, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 8, + 17.9, + 2.55 + ], + "size": [ + 0.35, + 1.1, + 1.2 + ], + "pivot": [ + 8.35, + 18, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + 4.7, + 17.9, + 2.55 + ], + "size": [ + 0.35, + 1.1, + 1.2 + ], + "pivot": [ + 5.05, + 18, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 63, + 59 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 63, + 59 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 64, + 60 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 64, + 60 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.7, + 19, + 2.65 + ], + "size": [ + 0.35, + 1, + 1.1 + ], + "pivot": [ + 5.05, + 19, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 63, + 59 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 63, + 59 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 64, + 60 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8, + 19, + 2.55 + ], + "size": [ + 0.35, + 2, + 3.4 + ], + "pivot": [ + 8.35, + 19, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 60, + 55 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 60, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "up": { + "uv": [ + 64, + 60 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 63, + 56 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 8, + 16, + 2.55 + ], + "size": [ + 0.35, + 2, + 2.3 + ], + "pivot": [ + 8.35, + 17, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 7.9, + 11.9, + 2.55 + ], + "size": [ + 0.35, + 4.1, + 4.3 + ], + "pivot": [ + 8.25, + 11.9, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 60, + 60 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 60, + 60 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 60, + 60 + ], + "uv_size": [ + 1, + 4 + ] + }, + "down": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 7, + 23, + -2.05 + ], + "size": [ + 0.35, + 1, + 2.3 + ], + "pivot": [ + 7.25, + 23, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 16, + -2.05 + ], + "size": [ + 0.35, + 1, + 2.3 + ], + "pivot": [ + 8.35, + 16, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 4.9, + 16, + -1.95 + ], + "size": [ + 0.35, + 1, + 1.2 + ], + "pivot": [ + 5.15, + 16, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 21, + -2.05 + ], + "size": [ + 0.35, + 2, + 4.5 + ], + "pivot": [ + 8.35, + 22, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 52, + 53 + ], + "uv_size": [ + 4, + 2 + ] + }, + "south": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 56, + 53 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 20, + -2.05 + ], + "size": [ + 0.35, + 1, + 3.4 + ], + "pivot": [ + 8.35, + 21, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 53, + 55 + ], + "uv_size": [ + 3, + 1 + ] + }, + "south": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 56, + 53 + ], + "uv_size": [ + -4, + 2 + ] + } + } + }, + { + "origin": [ + 8.1, + 17.9, + -2.05 + ], + "size": [ + 0.35, + 2.1, + 4.5 + ], + "pivot": [ + 8.35, + 19, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 52, + 56 + ], + "uv_size": [ + 4, + 2 + ] + }, + "south": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 56, + 56 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 11.9, + -2.05 + ], + "size": [ + 0.35, + 4.1, + 4.5 + ], + "pivot": [ + 8.35, + 15, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 55, + 60 + ], + "uv_size": [ + 1, + 4 + ] + }, + "east": { + "uv": [ + 52, + 60 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 52, + 60 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + -4, + 4 + ] + }, + "up": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 11.9, + -2.25 + ], + "size": [ + 0.35, + 5.1, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + 1, + 5 + ] + }, + "east": { + "uv": [ + 60, + 59 + ], + "uv_size": [ + -4, + 5 + ] + }, + "south": { + "uv": [ + 59, + 59 + ], + "uv_size": [ + 1, + 5 + ] + }, + "west": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + 4, + 5 + ] + }, + "up": { + "uv": [ + 59, + 60 + ], + "uv_size": [ + -3, + -1 + ] + }, + "down": { + "uv": [ + 56, + 64 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.6, + 11.9, + -2.25 + ], + "size": [ + 0.35, + 5.1, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 53, + 59 + ], + "uv_size": [ + -4, + 5 + ] + }, + "east": { + "uv": [ + 53, + 59 + ], + "uv_size": [ + -4, + 5 + ] + }, + "south": { + "uv": [ + 53, + 59 + ], + "uv_size": [ + -4, + 5 + ] + }, + "west": { + "uv": [ + 53, + 59 + ], + "uv_size": [ + -4, + 5 + ] + }, + "up": { + "uv": [ + 59, + 60 + ], + "uv_size": [ + -3, + -1 + ] + }, + "down": { + "uv": [ + 56, + 64 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.6, + 17.9, + -2.25 + ], + "size": [ + 0.35, + 2.1, + 4.5 + ], + "uv": { + "east": { + "uv": [ + 53, + 56 + ], + "uv_size": [ + -4, + 2 + ] + }, + "south": { + "uv": [ + 53, + 56 + ], + "uv_size": [ + -4, + 2 + ] + }, + "west": { + "uv": [ + 53, + 56 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 49, + 58 + ], + "uv_size": [ + 4, + -2 + ] + }, + "down": { + "uv": [ + 49, + 58 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 4.9, + 24, + -2.3 + ], + "size": [ + 2.2, + 0.2, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 53, + 48 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 55, + 48 + ], + "uv_size": [ + -2, + 1 + ] + }, + "west": { + "uv": [ + 55, + 49 + ], + "uv_size": [ + -1, + 2 + ] + }, + "up": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 2, + -4 + ] + }, + "down": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 2, + -4 + ] + } + } + }, + { + "origin": [ + 3.8, + 11.9, + -2.2 + ], + "size": [ + 4.4, + 0.2, + 4.4 + ], + "uv": { + "north": { + "uv": [ + 53, + 48 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 55, + 48 + ], + "uv_size": [ + -2, + 1 + ] + }, + "up": { + "uv": [ + 53, + 64 + ], + "uv_size": [ + 2, + -4 + ] + }, + "down": { + "uv": [ + 56, + 52 + ], + "uv_size": [ + 4, + -4 + ] + } + } + }, + { + "origin": [ + 7.1, + 24, + -1.3 + ], + "size": [ + 1.1, + 0.2, + 2.5 + ], + "uv": { + "north": { + "uv": [ + 56, + 49 + ], + "uv_size": [ + -1, + 2 + ] + }, + "south": { + "uv": [ + 56, + 49 + ], + "uv_size": [ + -1, + 2 + ] + }, + "west": { + "uv": [ + 56, + 49 + ], + "uv_size": [ + -1, + 2 + ] + }, + "up": { + "uv": [ + 55, + 51 + ], + "uv_size": [ + 1, + -2 + ] + }, + "down": { + "uv": [ + 55, + 51 + ], + "uv_size": [ + 1, + -2 + ] + } + } + } + ] + }, + { + "name": "launcher", + "parent": "bone8", + "pivot": [ + 6, + 23.75, + -0.75 + ], + "cubes": [ + { + "origin": [ + 6.5, + 22.95, + 0.5 + ], + "size": [ + 1, + 3.5, + 1 + ], + "pivot": [ + 7.5, + 22.95, + 0.25 + ], + "rotation": [ + -47.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6, + 24.2, + 0.25 + ], + "size": [ + 2, + 1, + 1.5 + ], + "pivot": [ + 7.5, + 22.95, + 0.25 + ], + "rotation": [ + -47.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 24.8, + 3.35 + ], + "size": [ + 1, + 1.25, + 1.5 + ], + "inflate": 0.01, + "pivot": [ + 7.5, + 25.05, + 3.35 + ], + "rotation": [ + 55, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 24.35, + 2.7 + ], + "size": [ + 1, + 1.25, + 1 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.25, + 25.6, + 2.2 + ], + "size": [ + 1.5, + 1.25, + 1.75 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + } + ] + }, + { + "name": "bone4", + "parent": "launcher", + "pivot": [ + 7, + 27.25, + 2.7 + ], + "cubes": [ + { + "origin": [ + 7.5, + 26.45, + -1.3 + ], + "size": [ + 0.5, + 1.6, + 5 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 7.5, + 27.9, + -1.05 + ], + "size": [ + 0.5, + 0.6, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6, + 27.9, + -1.05 + ], + "size": [ + 0.5, + 0.6, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 7.75, + 27.2, + -0.3 + ], + "size": [ + 0.5, + 0.85, + 3 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.75, + 27.2, + -0.3 + ], + "size": [ + 0.5, + 0.85, + 3 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 7.75, + 26.35, + -0.8 + ], + "size": [ + 0.5, + 0.85, + 3.5 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.75, + 26.35, + -0.8 + ], + "size": [ + 0.5, + 0.85, + 3.5 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 7.5, + 26.1, + -1.05 + ], + "size": [ + 0.5, + 0.35, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 25.85, + -1.05 + ], + "size": [ + 1, + 0.35, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 28.35, + -1.05 + ], + "size": [ + 1, + 0.35, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 28.1, + 1.45 + ], + "size": [ + 1, + 0.6, + 1.75 + ], + "inflate": 0.1, + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6, + 26.1, + -1.05 + ], + "size": [ + 0.5, + 0.35, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6, + 26.45, + -1.3 + ], + "size": [ + 0.5, + 1.6, + 5 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 26.1, + -1.3 + ], + "size": [ + 1, + 0.65, + 5 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 27.85, + -1.3 + ], + "size": [ + 1, + 0.65, + 5 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 26.6, + 3.7 + ], + "size": [ + 1, + 1.4, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + } + ] + }, + { + "name": "doomblade", + "parent": "bone8", + "pivot": [ + 8.2, + 14.8, + 0 + ], + "rotation": [ + 90, + 180, + 90 + ] + }, + { + "name": "group4", + "parent": "doomblade", + "pivot": [ + -16.2, + 16.65, + 16.5 + ], + "cubes": [ + { + "origin": [ + 8.95, + 14.05, + 0.375 + ], + "size": [ + 0.75, + 1.5, + 1.125 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 9.7, + 14.05, + 0.375 + ], + "size": [ + 0.75, + 1.5, + 0.75 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.3, + 14.05, + 0.375 + ], + "size": [ + 0.45, + 1.5, + 0.875 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.33, + 14.3, + 0.375 + ], + "size": [ + 0.95, + 1, + 0.375 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 2.83, + 14.3, + -0.02 + ], + "size": [ + 2.45, + 1, + 0.375 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.08, + 14.55, + 0.375 + ], + "size": [ + 2.2, + 0.5, + 0.375 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.55, + 14.05, + 0.875 + ], + "size": [ + 0.7, + 1.5, + 0.625 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.55, + 14.05, + 0.5 + ], + "size": [ + 0.45, + 1.5, + 0.375 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.7, + 14.05, + 1 + ], + "size": [ + 0.45, + 1.5, + 0.375 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.55, + 14.05, + 0.375 + ], + "size": [ + 0.7, + 1.5, + 0.625 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.05, + 14.05, + 0 + ], + "size": [ + 5.25, + 1.5, + 0.375 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.7, + 14.2, + 0.375 + ], + "size": [ + 3.25, + 1.2, + 0.9 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 3, + 1 + ] + }, + "east": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 3, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 3, + 1 + ] + }, + "west": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 3, + 1 + ] + }, + "up": { + "uv": [ + 61, + 13 + ], + "uv_size": [ + -3, + -1 + ] + }, + "down": { + "uv": [ + 61, + 13 + ], + "uv_size": [ + -3, + -1 + ] + } + } + } + ] + }, + { + "name": "group5", + "parent": "doomblade", + "pivot": [ + -16.2, + 16.65, + 16.5 + ], + "cubes": [ + { + "origin": [ + 4, + 15.565, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -10.1, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.225, + 15.565, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.875, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.45, + 15.565, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.65, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.675, + 15.565, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.425, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + } + ] + }, + { + "name": "group6", + "parent": "doomblade", + "pivot": [ + -16.2, + 16.65, + 16.5 + ], + "cubes": [ + { + "origin": [ + 4, + 14.035, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -10.1, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.225, + 14.035, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.875, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.45, + 14.035, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.65, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.675, + 14.035, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.425, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + } + ] + }, + { + "name": "blade", + "parent": "doomblade", + "pivot": [ + 4.8, + 14.85, + 0.7 + ], + "cubes": [ + { + "origin": [ + 0.36392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 0.4223, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 0.26662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 0.26662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 0.75396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + -0.18766, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 1.11392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 1.1723, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.01662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.05, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 1.25, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.01662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.50396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 0.56234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 2.25396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 1.31234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 1.76662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.8, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 2, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "up": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + }, + "down": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + } + } + }, + { + "origin": [ + 1.76662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.86392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 1.9223, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.00396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 2.06234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 2.51662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 2.55, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 2.75, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "up": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + }, + "down": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + } + } + }, + { + "origin": [ + 2.51662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 2.61392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 2.6723, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.75396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 2.81234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 3.26662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.3, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 3.5, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "up": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + }, + "down": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + } + } + }, + { + "origin": [ + 3.26662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.36392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 3.4223, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.50396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 3.56234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 4.01662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.05, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 4.25, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "up": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + }, + "down": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + } + } + }, + { + "origin": [ + 4.01662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.11392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 4.1723, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.25396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 4.31234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 4.76662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.8, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 5, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "up": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + }, + "down": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + } + } + }, + { + "origin": [ + 4.76662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.86392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 4.9223, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 0.55, + 14.75, + 0.15 + ], + "size": [ + 4.75, + 0.1, + 0.975 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.2, + 14.75, + 0.15 + ], + "size": [ + 1.75, + 0.1, + 0.725 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -2.00595, + 14.7, + 0.0951 + ], + "size": [ + 2.5, + 0.2, + 0.225 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.50595, + 14.7, + 0.3201 + ], + "size": [ + 2, + 0.2, + 0.225 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -0.23338, + 14.7, + 0.675 + ], + "size": [ + 0.75, + 0.2, + 0.475 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.00595, + 14.7, + 0.5451 + ], + "size": [ + 1.75, + 0.2, + 0.225 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.55597, + 14.7, + 1.07007 + ], + "size": [ + 1, + 0.2, + 0.475 + ], + "pivot": [ + 0.39403, + 0, + 0.42007 + ], + "rotation": [ + 0, + -25, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.73967, + 14.7, + 1.57457 + ], + "size": [ + 0.25, + 0.2, + 0.475 + ], + "pivot": [ + -0.03967, + 0, + 0.92457 + ], + "rotation": [ + 0, + -47.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.92377, + 14.7, + 1.71887 + ], + "size": [ + 0.25, + 0.2, + 0.225 + ], + "pivot": [ + -0.22377, + 0, + 0.81887 + ], + "rotation": [ + 0, + -50, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -0.88962, + 14.7, + 0.5842 + ], + "size": [ + 0.75, + 0.2, + 0.475 + ], + "pivot": [ + -0.79584, + 15, + 0.74701 + ], + "rotation": [ + 0, + -10, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -0.35269, + 14.7, + 0.66088 + ], + "size": [ + 0.5, + 0.2, + 0.475 + ], + "pivot": [ + -0.25891, + 15, + 0.82369 + ], + "rotation": [ + 0, + -17.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + } + ] + }, + { + "name": "bipedRightLeg", + "pivot": [ + -2, + 12, + 0 + ] + }, + { + "name": "armorRightLeg", + "parent": "bipedRightLeg", + "pivot": [ + -2, + 12, + 0 + ] + }, + { + "name": "bone6", + "parent": "armorRightLeg", + "pivot": [ + -4, + 22, + 0 + ], + "cubes": [ + { + "origin": [ + -0.1, + 0.2, + -2.2 + ], + "size": [ + 4.4, + 11.8, + 4.4 + ], + "uv": { + "north": { + "uv": [ + 8, + 20 + ], + "uv_size": [ + -4, + 12 + ] + }, + "south": { + "uv": [ + 16, + 20 + ], + "uv_size": [ + -4, + 12 + ] + }, + "west": { + "uv": [ + 4, + 20 + ], + "uv_size": [ + -4, + 12 + ] + }, + "up": { + "uv": [ + 8, + 20 + ], + "uv_size": [ + -4, + -4 + ] + } + } + } + ] + }, + { + "name": "armorRightBoot", + "parent": "bipedRightLeg", + "pivot": [ + -2, + 12, + 0 + ] + }, + { + "name": "bone9", + "parent": "armorRightBoot", + "pivot": [ + -4, + 22, + 0 + ] + }, + { + "name": "bone14", + "parent": "bone9", + "pivot": [ + -4, + 22, + 0 + ], + "cubes": [ + { + "origin": [ + 0, + -0.3, + -2.3 + ], + "size": [ + 4.6, + 2.2, + 4.6 + ], + "uv": { + "north": { + "uv": [ + 4, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "south": { + "uv": [ + 12, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "west": { + "uv": [ + 8, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "up": { + "uv": [ + 12, + 20 + ], + "uv_size": [ + -4, + -4 + ] + }, + "down": { + "uv": [ + 12, + 20 + ], + "uv_size": [ + -4, + -4 + ] + } + } + }, + { + "origin": [ + 0, + 2.8, + -2.5 + ], + "size": [ + 4.6, + 4.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 4, + 57 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 4, + 57 + ], + "uv_size": [ + 4, + 4 + ] + }, + "west": { + "uv": [ + 5, + 57 + ], + "uv_size": [ + -1, + 4 + ] + }, + "up": { + "uv": [ + 8, + 58 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 4, + 61 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + 0, + 5.8, + 2.2 + ], + "size": [ + 4.6, + 1.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 12, + 57 + ], + "uv_size": [ + 4, + 1 + ] + }, + "south": { + "uv": [ + 12, + 57 + ], + "uv_size": [ + 4, + 1 + ] + }, + "west": { + "uv": [ + 12, + 57 + ], + "uv_size": [ + 4, + 1 + ] + }, + "up": { + "uv": [ + 16, + 58 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 16, + 58 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 0, + 2.8, + 2 + ], + "size": [ + 4.6, + 1.1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 12, + 60 + ], + "uv_size": [ + 4, + 1 + ] + }, + "south": { + "uv": [ + 12, + 60 + ], + "uv_size": [ + 4, + 1 + ] + }, + "west": { + "uv": [ + 12, + 60 + ], + "uv_size": [ + 4, + 1 + ] + }, + "up": { + "uv": [ + 16, + 61 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 16, + 61 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 0, + -0.2, + -2.5 + ], + "size": [ + 4.6, + 2.1, + 0.7 + ], + "uv": { + "north": { + "uv": [ + 4, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 1, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "up": { + "uv": [ + 8, + 63 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 8, + 64 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 2.3, + 6.9, + -2.5 + ], + "size": [ + 2.3, + 2.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 6, + 55 + ], + "uv_size": [ + 2, + 2 + ] + }, + "east": { + "uv": [ + 6, + 55 + ], + "uv_size": [ + 2, + 2 + ] + }, + "south": { + "uv": [ + 6, + 55 + ], + "uv_size": [ + 2, + 2 + ] + }, + "west": { + "uv": [ + 6, + 55 + ], + "uv_size": [ + 2, + 2 + ] + }, + "up": { + "uv": [ + 8, + 57 + ], + "uv_size": [ + -2, + -2 + ] + } + } + }, + { + "origin": [ + 0, + 6.9, + 2.2 + ], + "size": [ + 3.5, + 2.1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "south": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "west": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "up": { + "uv": [ + 15, + 57 + ], + "uv_size": [ + -3, + -2 + ] + } + } + }, + { + "origin": [ + 0, + 9, + 2.2 + ], + "size": [ + 1.2, + 1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "south": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "west": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "up": { + "uv": [ + 15, + 57 + ], + "uv_size": [ + -3, + -2 + ] + } + } + }, + { + "origin": [ + 0, + 10.9, + -2.5 + ], + "size": [ + 1.2, + 1.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 4, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 4, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 5, + 53 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 5, + 53 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.3, + 9, + -2.5 + ], + "size": [ + 1.3, + 2, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 7, + 53 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 7, + 53 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 7, + 53 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 7, + 53 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 8, + 55 + ], + "uv_size": [ + -1, + -2 + ] + } + } + }, + { + "origin": [ + 4.6, + -0.2, + 2 + ], + "size": [ + 4.6, + 2.1, + 0.5 + ], + "pivot": [ + 4.6, + -0.2, + 2.3 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "east": { + "uv": [ + 12, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "south": { + "uv": [ + 8, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "up": { + "uv": [ + 8, + 63 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 8, + 64 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 4.6, + 2.8, + 2.2 + ], + "size": [ + 4.6, + 8.2, + 0.3 + ], + "pivot": [ + 4.6, + 2.8, + 2.3 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 12, + 53 + ], + "uv_size": [ + -4, + 8 + ] + }, + "east": { + "uv": [ + 11, + 53 + ], + "uv_size": [ + 1, + 8 + ] + }, + "south": { + "uv": [ + 8, + 53 + ], + "uv_size": [ + 4, + 8 + ] + }, + "up": { + "uv": [ + 12, + 54 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 11, + 61 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + -0.2, + 2.8, + 2.3 + ], + "size": [ + 4.6, + 4.1, + 0.3 + ], + "pivot": [ + -0.2, + 2.8, + 2.3 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "up": { + "uv": [ + 4, + 58 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 11, + 61 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + -0.2, + -0.2, + 2.3 + ], + "size": [ + 4.6, + 2.1, + 0.4 + ], + "pivot": [ + -0.2, + -0.2, + 2.3 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "up": { + "uv": [ + 8, + 63 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 8, + 64 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 0, + -0.2, + 2.1 + ], + "size": [ + 4.6, + 2.1, + 0.4 + ], + "uv": { + "south": { + "uv": [ + 12, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 12, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "up": { + "uv": [ + 8, + 63 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 16, + 64 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 1.1, + 1.9, + 2.2 + ], + "size": [ + 2.4, + 1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + 0, + 3.9, + 2.1 + ], + "size": [ + 1.2, + 1, + 0.4 + ], + "uv": { + "south": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 15, + 62 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 3.4, + 3.9, + 1.9 + ], + "size": [ + 1.2, + 1, + 0.6 + ], + "uv": { + "east": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 15, + 62 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 15, + 62 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 1.1, + 1.9, + -2.5 + ], + "size": [ + 2.4, + 1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + } + } + } + ] + }, + { + "name": "bipedLeftLeg", + "pivot": [ + 2, + 12, + 0 + ] + }, + { + "name": "armorLeftLeg", + "parent": "bipedLeftLeg", + "pivot": [ + 2, + 12, + 0 + ] + }, + { + "name": "bone7", + "parent": "armorLeftLeg", + "pivot": [ + -4, + 22, + 0 + ] + }, + { + "name": "armorLeftBoot", + "parent": "bipedLeftLeg", + "pivot": [ + 2, + 12, + 0 + ] + }, + { + "name": "bone10", + "parent": "armorLeftBoot", + "pivot": [ + -4, + 22, + 0 + ], + "cubes": [ + { + "origin": [ + -4.2, + -0.2, + -2.3 + ], + "size": [ + 4.6, + 12.2, + 4.6 + ], + "uv": { + "north": { + "uv": [ + 4, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "east": { + "uv": [ + 0, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "south": { + "uv": [ + 12, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "west": { + "uv": [ + 4, + 52 + ], + "uv_size": [ + -4, + 12 + ] + }, + "up": { + "uv": [ + 4, + 0 + ], + "uv_size": [ + 4, + 4 + ] + } + } + }, + { + "origin": [ + -4.2, + -0.3, + -2.3 + ], + "size": [ + 4.6, + 2.2, + 4.6 + ], + "uv": { + "north": { + "uv": [ + 8, + 52 + ], + "uv_size": [ + -4, + 12 + ] + }, + "east": { + "uv": [ + 12, + 52 + ], + "uv_size": [ + -4, + 12 + ] + }, + "south": { + "uv": [ + 16, + 52 + ], + "uv_size": [ + -4, + 12 + ] + }, + "down": { + "uv": [ + 8, + 20 + ], + "uv_size": [ + 4, + -4 + ] + } + } + }, + { + "origin": [ + -4.2, + 2.8, + -2.5 + ], + "size": [ + 4.6, + 4.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 8, + 57 + ], + "uv_size": [ + -4, + 4 + ] + }, + "east": { + "uv": [ + 4, + 57 + ], + "uv_size": [ + 1, + 4 + ] + }, + "up": { + "uv": [ + 4, + 58 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 8, + 61 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + 5.8, + 2.2 + ], + "size": [ + 4.6, + 1.1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 16, + 57 + ], + "uv_size": [ + -4, + 1 + ] + }, + "south": { + "uv": [ + 16, + 57 + ], + "uv_size": [ + -4, + 1 + ] + }, + "up": { + "uv": [ + 12, + 58 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 12, + 58 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + 2.8, + 2 + ], + "size": [ + 4.6, + 1.1, + 0.5 + ], + "uv": { + "east": { + "uv": [ + 16, + 60 + ], + "uv_size": [ + -4, + 1 + ] + }, + "south": { + "uv": [ + 16, + 60 + ], + "uv_size": [ + -4, + 1 + ] + }, + "up": { + "uv": [ + 12, + 61 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 12, + 61 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + -0.2, + -2.5 + ], + "size": [ + 4.6, + 2.1, + 0.7 + ], + "uv": { + "north": { + "uv": [ + 8, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 5, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 4, + 63 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 4, + 64 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + 6.9, + -2.5 + ], + "size": [ + 2.3, + 2.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 8, + 55 + ], + "uv_size": [ + -2, + 2 + ] + }, + "east": { + "uv": [ + 8, + 55 + ], + "uv_size": [ + -2, + 2 + ] + }, + "west": { + "uv": [ + 8, + 55 + ], + "uv_size": [ + -2, + 2 + ] + }, + "up": { + "uv": [ + 6, + 57 + ], + "uv_size": [ + 2, + -2 + ] + } + } + }, + { + "origin": [ + -4.2, + 6.9, + 2.2 + ], + "size": [ + 3.5, + 2.1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "south": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "west": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "up": { + "uv": [ + 12, + 57 + ], + "uv_size": [ + 3, + -2 + ] + } + } + }, + { + "origin": [ + -4.2, + 9, + 2.2 + ], + "size": [ + 1.2, + 1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "south": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "west": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "up": { + "uv": [ + 12, + 57 + ], + "uv_size": [ + 3, + -2 + ] + } + } + }, + { + "origin": [ + -0.8, + 10.9, + -2.5 + ], + "size": [ + 1.2, + 1.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 5, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "up": { + "uv": [ + 4, + 53 + ], + "uv_size": [ + 1, + -1 + ] + }, + "down": { + "uv": [ + 4, + 53 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + 9, + -2.5 + ], + "size": [ + 1.3, + 2, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 8, + 53 + ], + "uv_size": [ + -1, + 2 + ] + }, + "east": { + "uv": [ + 8, + 53 + ], + "uv_size": [ + -1, + 2 + ] + }, + "west": { + "uv": [ + 8, + 53 + ], + "uv_size": [ + -1, + 2 + ] + }, + "up": { + "uv": [ + 7, + 55 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + -8.8, + -0.2, + 2 + ], + "size": [ + 4.6, + 2.1, + 0.5 + ], + "pivot": [ + -4.2, + -0.2, + 2.3 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "south": { + "uv": [ + 12, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "west": { + "uv": [ + 16, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 4, + 63 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 4, + 64 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -8.8, + 2.8, + 2.2 + ], + "size": [ + 4.6, + 8.2, + 0.3 + ], + "pivot": [ + -4.2, + 2.8, + 2.3 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 8, + 53 + ], + "uv_size": [ + 4, + 8 + ] + }, + "south": { + "uv": [ + 12, + 53 + ], + "uv_size": [ + -4, + 8 + ] + }, + "west": { + "uv": [ + 12, + 53 + ], + "uv_size": [ + -1, + 8 + ] + }, + "up": { + "uv": [ + 8, + 54 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 7, + 61 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4, + 2.8, + 2.3 + ], + "size": [ + 4.6, + 4.1, + 0.3 + ], + "pivot": [ + 0.6, + 2.8, + 2.3 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 4, + 57 + ], + "uv_size": [ + -4, + 4 + ] + }, + "west": { + "uv": [ + 4, + 57 + ], + "uv_size": [ + -4, + 4 + ] + }, + "up": { + "uv": [ + 0, + 58 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 7, + 61 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4, + -0.2, + 2.3 + ], + "size": [ + 4.6, + 2.1, + 0.4 + ], + "pivot": [ + 0.6, + -0.2, + 2.3 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "up": { + "uv": [ + 4, + 63 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 4, + 64 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + -0.2, + 2.1 + ], + "size": [ + 4.6, + 2.1, + 0.4 + ], + "uv": { + "east": { + "uv": [ + 16, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "south": { + "uv": [ + 16, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 4, + 63 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 12, + 64 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -3.1, + 1.9, + 2.2 + ], + "size": [ + 2.4, + 1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "south": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "west": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + } + } + }, + { + "origin": [ + -0.8, + 3.9, + 2.1 + ], + "size": [ + 1.2, + 1, + 0.4 + ], + "uv": { + "east": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "south": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "up": { + "uv": [ + 13, + 62 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + 3.9, + 1.9 + ], + "size": [ + 1.2, + 1, + 0.6 + ], + "uv": { + "east": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "south": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "west": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "up": { + "uv": [ + 13, + 62 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -3.1, + 1.9, + -2.5 + ], + "size": [ + 2.4, + 1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "east": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "west": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + } + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/item/pistol.geo.json b/common/src/main/resources/assets/azurelib/geo/item/pistol.geo.json new file mode 100644 index 000000000..dfef26e61 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/item/pistol.geo.json @@ -0,0 +1,3690 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 128, + "texture_height": 64, + "visible_bounds_width": 3, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [ + 0, + 0.75, + 0 + ] + }, + "bones": [ + { + "name": "group", + "pivot": [ + -0.49601, + 4.03502, + -0.09665 + ], + "cubes": [ + { + "origin": [ + -2, + -0.25, + -9.25 + ], + "size": [ + 3, + 4, + 7.75 + ], + "uv": { + "north": { + "uv": [ + 30, + 18 + ], + "uv_size": [ + 3, + 4 + ] + }, + "east": { + "uv": [ + 14, + 12 + ], + "uv_size": [ + 8, + 4 + ] + }, + "south": { + "uv": [ + 25, + 30 + ], + "uv_size": [ + 3, + 4 + ] + }, + "west": { + "uv": [ + 14, + 16 + ], + "uv_size": [ + 8, + 4 + ] + }, + "up": { + "uv": [ + 5, + 19 + ], + "uv_size": [ + 3, + 8 + ] + }, + "down": { + "uv": [ + 19, + 28 + ], + "uv_size": [ + 3, + -8 + ] + } + } + }, + { + "origin": [ + -1.375, + 1.25, + -11.75 + ], + "size": [ + 1.75, + 2.5, + 4.25 + ], + "uv": { + "north": { + "uv": [ + 37, + 6 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 30, + 26 + ], + "uv_size": [ + 4, + 3 + ] + }, + "south": { + "uv": [ + 16, + 37 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 28, + 30 + ], + "uv_size": [ + 4, + 3 + ] + }, + "up": { + "uv": [ + 17, + 29 + ], + "uv_size": [ + 2, + 4 + ] + }, + "down": { + "uv": [ + 3, + 40 + ], + "uv_size": [ + 2, + -4 + ] + } + } + }, + { + "origin": [ + -2.125, + 2, + -2.875 + ], + "size": [ + 3.25, + 1.5, + 2.75 + ], + "pivot": [ + -0.5, + 2.25, + -2.5 + ], + "rotation": [ + 45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 27, + 4 + ], + "uv_size": [ + 3, + 2 + ] + }, + "east": { + "uv": [ + 37, + 18 + ], + "uv_size": [ + 3, + 2 + ] + }, + "south": { + "uv": [ + 37, + 20 + ], + "uv_size": [ + 3, + 2 + ] + }, + "west": { + "uv": [ + 37, + 22 + ], + "uv_size": [ + 3, + 2 + ] + }, + "up": { + "uv": [ + 32, + 33 + ], + "uv_size": [ + 3, + 3 + ] + }, + "down": { + "uv": [ + 34, + 9 + ], + "uv_size": [ + 3, + -3 + ] + } + } + }, + { + "origin": [ + -2.25, + 3.75, + -12 + ], + "size": [ + 3.5, + 3, + 18.5 + ], + "uv": { + "north": { + "uv": [ + 31, + 0 + ], + "uv_size": [ + 4, + 3 + ] + }, + "east": { + "uv": [ + 8, + 0 + ], + "uv_size": [ + 19, + 3 + ] + }, + "south": { + "uv": [ + 31, + 3 + ], + "uv_size": [ + 4, + 3 + ] + }, + "west": { + "uv": [ + 8, + 3 + ], + "uv_size": [ + 19, + 3 + ] + }, + "up": { + "uv": [ + 0, + 0 + ], + "uv_size": [ + 4, + 19 + ] + }, + "down": { + "uv": [ + 4, + 19 + ], + "uv_size": [ + 4, + -19 + ] + } + } + }, + { + "origin": [ + -1.875, + 4.75, + -11.875 + ], + "size": [ + 2.75, + 3, + 18.25 + ], + "uv": { + "north": { + "uv": [ + 14, + 34 + ], + "uv_size": [ + 3, + 3 + ] + }, + "east": { + "uv": [ + 8, + 6 + ], + "uv_size": [ + 18, + 3 + ] + }, + "south": { + "uv": [ + 34, + 21 + ], + "uv_size": [ + 3, + 3 + ] + }, + "west": { + "uv": [ + 8, + 9 + ], + "uv_size": [ + 18, + 3 + ] + }, + "up": { + "uv": [ + 8, + 12 + ], + "uv_size": [ + 3, + 18 + ] + }, + "down": { + "uv": [ + 11, + 30 + ], + "uv_size": [ + 3, + -18 + ] + } + } + }, + { + "origin": [ + -2.125, + -2.89866, + 3.40497 + ], + "size": [ + 3.25, + 4.5, + 3.5 + ], + "pivot": [ + -0.5, + 0.57009, + 6.21747 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 27 + ], + "uv_size": [ + 3, + 5 + ] + }, + "east": { + "uv": [ + 22, + 12 + ], + "uv_size": [ + 4, + 5 + ] + }, + "south": { + "uv": [ + 19, + 28 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 22, + 17 + ], + "uv_size": [ + 4, + 5 + ] + }, + "up": { + "uv": [ + 31, + 6 + ], + "uv_size": [ + 3, + 4 + ] + }, + "down": { + "uv": [ + 31, + 26 + ], + "uv_size": [ + 3, + -4 + ] + } + } + }, + { + "origin": [ + -2, + -5.46979, + 4.98488 + ], + "size": [ + 3, + 3.125, + 3.125 + ], + "uv": { + "north": { + "uv": [ + 34, + 24 + ], + "uv_size": [ + 3, + 3 + ] + }, + "east": { + "uv": [ + 25, + 34 + ], + "uv_size": [ + 3, + 3 + ] + }, + "south": { + "uv": [ + 35, + 0 + ], + "uv_size": [ + 3, + 3 + ] + }, + "west": { + "uv": [ + 35, + 3 + ], + "uv_size": [ + 3, + 3 + ] + }, + "up": { + "uv": [ + 8, + 35 + ], + "uv_size": [ + 3, + 3 + ] + }, + "down": { + "uv": [ + 35, + 12 + ], + "uv_size": [ + 3, + -3 + ] + } + } + }, + { + "origin": [ + -2, + 0.47634, + 3.27997 + ], + "size": [ + 3, + 4.125, + 3.125 + ], + "uv": { + "north": { + "uv": [ + 0, + 32 + ], + "uv_size": [ + 3, + 4 + ] + }, + "east": { + "uv": [ + 3, + 32 + ], + "uv_size": [ + 3, + 4 + ] + }, + "south": { + "uv": [ + 32, + 29 + ], + "uv_size": [ + 3, + 4 + ] + }, + "west": { + "uv": [ + 17, + 33 + ], + "uv_size": [ + 3, + 4 + ] + }, + "up": { + "uv": [ + 11, + 35 + ], + "uv_size": [ + 3, + 3 + ] + }, + "down": { + "uv": [ + 35, + 15 + ], + "uv_size": [ + 3, + -3 + ] + } + } + }, + { + "origin": [ + -1.75, + -2.64866, + 2.65497 + ], + "size": [ + 2.5, + 4.75, + 4.75 + ], + "pivot": [ + -0.5, + 0.57009, + 6.21747 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 14, + 29 + ], + "uv_size": [ + 3, + 5 + ] + }, + "east": { + "uv": [ + 0, + 19 + ], + "uv_size": [ + 5, + 5 + ] + }, + "south": { + "uv": [ + 8, + 30 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 14, + 20 + ], + "uv_size": [ + 5, + 5 + ] + }, + "up": { + "uv": [ + 11, + 30 + ], + "uv_size": [ + 3, + 5 + ] + }, + "down": { + "uv": [ + 22, + 35 + ], + "uv_size": [ + 3, + -5 + ] + } + } + }, + { + "origin": [ + -1.625, + -4.96979, + 4.23488 + ], + "size": [ + 2.25, + 3.125, + 4.25 + ], + "uv": { + "north": { + "uv": [ + 18, + 37 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 33, + 18 + ], + "uv_size": [ + 4, + 3 + ] + }, + "south": { + "uv": [ + 37, + 24 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 28, + 33 + ], + "uv_size": [ + 4, + 3 + ] + }, + "up": { + "uv": [ + 36, + 27 + ], + "uv_size": [ + 2, + 4 + ] + }, + "down": { + "uv": [ + 28, + 40 + ], + "uv_size": [ + 2, + -4 + ] + } + } + }, + { + "origin": [ + -1.625, + 0.60134, + 2.40497 + ], + "size": [ + 2.25, + 4, + 4.375 + ], + "uv": { + "north": { + "uv": [ + 30, + 36 + ], + "uv_size": [ + 2, + 4 + ] + }, + "east": { + "uv": [ + 26, + 18 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 36, + 31 + ], + "uv_size": [ + 2, + 4 + ] + }, + "west": { + "uv": [ + 22, + 26 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 32, + 36 + ], + "uv_size": [ + 2, + 4 + ] + }, + "down": { + "uv": [ + 34, + 40 + ], + "uv_size": [ + 2, + -4 + ] + } + } + }, + { + "origin": [ + -1.5, + 0.875, + -1.5 + ], + "size": [ + 2, + 0.5, + 6 + ], + "uv": { + "north": { + "uv": [ + 30, + 29 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 38, + 0 + ], + "uv_size": [ + 6, + 1 + ] + }, + "south": { + "uv": [ + 40, + 21 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 38, + 1 + ], + "uv_size": [ + 6, + 1 + ] + }, + "up": { + "uv": [ + 6, + 32 + ], + "uv_size": [ + 2, + 6 + ] + }, + "down": { + "uv": [ + 20, + 39 + ], + "uv_size": [ + 2, + -6 + ] + } + } + }, + { + "origin": [ + -2, + 3.875, + 4.5 + ], + "size": [ + 3, + 1, + 3 + ], + "uv": { + "north": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 3, + 1 + ] + }, + "east": { + "uv": [ + 40, + 4 + ], + "uv_size": [ + 3, + 1 + ] + }, + "south": { + "uv": [ + 40, + 10 + ], + "uv_size": [ + 3, + 1 + ] + }, + "west": { + "uv": [ + 40, + 11 + ], + "uv_size": [ + 3, + 1 + ] + }, + "up": { + "uv": [ + 35, + 15 + ], + "uv_size": [ + 3, + 3 + ] + }, + "down": { + "uv": [ + 22, + 38 + ], + "uv_size": [ + 3, + -3 + ] + } + } + }, + { + "origin": [ + -1.625, + 4, + 7.5 + ], + "size": [ + 2.25, + 0.75, + 2 + ], + "uv": { + "north": { + "uv": [ + 40, + 22 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 40, + 23 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 25, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 28, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 8, + 38 + ], + "uv_size": [ + 2, + 2 + ] + }, + "down": { + "uv": [ + 38, + 11 + ], + "uv_size": [ + 2, + -2 + ] + } + } + }, + { + "origin": [ + 1, + 0.625, + -7.5 + ], + "size": [ + 0.5, + 4.125, + 5 + ], + "uv": { + "north": { + "uv": [ + 4, + 28 + ], + "uv_size": [ + 1, + 4 + ] + }, + "east": { + "uv": [ + 22, + 22 + ], + "uv_size": [ + 5, + 4 + ] + }, + "south": { + "uv": [ + 10, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 0, + 24 + ], + "uv_size": [ + 5, + 4 + ] + }, + "up": { + "uv": [ + 5, + 36 + ], + "uv_size": [ + 1, + 5 + ] + }, + "down": { + "uv": [ + 27, + 42 + ], + "uv_size": [ + 1, + -5 + ] + } + } + }, + { + "origin": [ + -2.5, + 0.625, + -7.5 + ], + "size": [ + 0.5, + 4.125, + 5 + ], + "uv": { + "north": { + "uv": [ + 11, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "east": { + "uv": [ + 14, + 25 + ], + "uv_size": [ + 5, + 4 + ] + }, + "south": { + "uv": [ + 38, + 11 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 26, + 6 + ], + "uv_size": [ + 5, + 4 + ] + }, + "up": { + "uv": [ + 6, + 38 + ], + "uv_size": [ + 1, + 5 + ] + }, + "down": { + "uv": [ + 7, + 43 + ], + "uv_size": [ + 1, + -5 + ] + } + } + }, + { + "origin": [ + 1.25, + 4.625, + -10 + ], + "size": [ + 0.75, + 1.75, + 9 + ], + "uv": { + "north": { + "uv": [ + 30, + 4 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 26, + 10 + ], + "uv_size": [ + 9, + 2 + ] + }, + "south": { + "uv": [ + 34, + 27 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 26, + 12 + ], + "uv_size": [ + 9, + 2 + ] + }, + "up": { + "uv": [ + 35, + 27 + ], + "uv_size": [ + 1, + 9 + ] + }, + "down": { + "uv": [ + 0, + 45 + ], + "uv_size": [ + 1, + -9 + ] + } + } + }, + { + "origin": [ + -2.875, + 4.625, + -10 + ], + "size": [ + 0.625, + 1.75, + 9 + ], + "uv": { + "north": { + "uv": [ + 19, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 26, + 14 + ], + "uv_size": [ + 9, + 2 + ] + }, + "south": { + "uv": [ + 30, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 26, + 16 + ], + "uv_size": [ + 9, + 2 + ] + }, + "up": { + "uv": [ + 1, + 36 + ], + "uv_size": [ + 1, + 9 + ] + }, + "down": { + "uv": [ + 2, + 45 + ], + "uv_size": [ + 1, + -9 + ] + } + } + }, + { + "origin": [ + 0.375, + 2.625, + -11.5 + ], + "size": [ + 1.375, + 3.625, + 4 + ], + "uv": { + "north": { + "uv": [ + 12, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "east": { + "uv": [ + 26, + 26 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 13, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 27, + 0 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 22, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "down": { + "uv": [ + 23, + 42 + ], + "uv_size": [ + 1, + -4 + ] + } + } + }, + { + "origin": [ + -2.75, + 2.625, + -11.5 + ], + "size": [ + 1.375, + 3.625, + 4 + ], + "uv": { + "north": { + "uv": [ + 24, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "east": { + "uv": [ + 27, + 22 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 38, + 27 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 0, + 28 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 38, + 31 + ], + "uv_size": [ + 1, + 4 + ] + }, + "down": { + "uv": [ + 38, + 39 + ], + "uv_size": [ + 1, + -4 + ] + } + } + }, + { + "origin": [ + -3.5, + -0.125, + -5.875 + ], + "size": [ + 1.5, + 0.75, + 4 + ], + "uv": { + "north": { + "uv": [ + 31, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 38, + 5 + ], + "uv_size": [ + 4, + 1 + ] + }, + "south": { + "uv": [ + 33, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 38, + 15 + ], + "uv_size": [ + 4, + 1 + ] + }, + "up": { + "uv": [ + 36, + 35 + ], + "uv_size": [ + 2, + 4 + ] + }, + "down": { + "uv": [ + 14, + 41 + ], + "uv_size": [ + 2, + -4 + ] + } + } + }, + { + "origin": [ + -0.75, + -0.875, + -7.5 + ], + "size": [ + 0.5, + 0.625, + 4 + ], + "uv": { + "north": { + "uv": [ + 33, + 21 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 38, + 16 + ], + "uv_size": [ + 4, + 1 + ] + }, + "south": { + "uv": [ + 34, + 9 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 38, + 17 + ], + "uv_size": [ + 4, + 1 + ] + }, + "up": { + "uv": [ + 39, + 11 + ], + "uv_size": [ + 1, + 4 + ] + }, + "down": { + "uv": [ + 20, + 43 + ], + "uv_size": [ + 1, + -4 + ] + } + } + }, + { + "origin": [ + -1.25, + 1.125, + 6.5 + ], + "size": [ + 1.5, + 2.875, + 0.75 + ], + "pivot": [ + -0.5, + 2.5625, + 6.875 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 25, + 37 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 21, + 39 + ], + "uv_size": [ + 1, + 3 + ] + }, + "south": { + "uv": [ + 38, + 2 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 40, + 12 + ], + "uv_size": [ + 1, + 3 + ] + }, + "up": { + "uv": [ + 40, + 39 + ], + "uv_size": [ + 2, + 1 + ] + }, + "down": { + "uv": [ + 40, + 41 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -0.625, + 1.40248, + 1.84024 + ], + "size": [ + 0.25, + 2.875, + 0.625 + ], + "pivot": [ + -0.5, + 3.08998, + 2.02774 + ], + "rotation": [ + -45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 16, + 40 + ], + "uv_size": [ + 1, + 3 + ] + }, + "east": { + "uv": [ + 17, + 40 + ], + "uv_size": [ + 1, + 3 + ] + }, + "south": { + "uv": [ + 18, + 40 + ], + "uv_size": [ + 1, + 3 + ] + }, + "west": { + "uv": [ + 40, + 18 + ], + "uv_size": [ + 1, + 3 + ] + }, + "up": { + "uv": [ + 39, + 8 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 42, + 24 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -0.75, + 2.52748, + 1.46524 + ], + "size": [ + 0.5, + 1.75, + 1 + ], + "pivot": [ + -0.5, + 3.08998, + 2.02774 + ], + "rotation": [ + -22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 35, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 5, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 41, + 6 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 41, + 12 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 24, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 42, + 26 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -1.375, + 7.75, + 4.5 + ], + "size": [ + 1.75, + 0.375, + 1.875 + ], + "uv": { + "north": { + "uv": [ + 14, + 41 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 41, + 14 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 41, + 18 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 41, + 19 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 39, + 6 + ], + "uv_size": [ + 2, + 2 + ] + }, + "down": { + "uv": [ + 39, + 26 + ], + "uv_size": [ + 2, + -2 + ] + } + } + }, + { + "origin": [ + 0.125, + 8.125, + 4.5 + ], + "size": [ + 0.25, + 0.375, + 1.875 + ], + "uv": { + "north": { + "uv": [ + 42, + 26 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 41, + 20 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 27, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 41, + 24 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 25, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 41, + 27 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + 1.25, + 4.825, + 4 + ], + "size": [ + 0.25, + 0.875, + 1.5 + ], + "uv": { + "north": { + "uv": [ + 28, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 41, + 27 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 28 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 28, + 41 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 26, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 41, + 30 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + -2.5, + 4.825, + 4 + ], + "size": [ + 0.25, + 0.875, + 1.5 + ], + "uv": { + "north": { + "uv": [ + 29, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 41, + 30 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 29 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 31, + 41 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 41, + 31 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 33, + 43 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + 1.25, + 4.825, + 5.5 + ], + "size": [ + 0.625, + 0.875, + 0.875 + ], + "uv": { + "north": { + "uv": [ + 30, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 31, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 42, + 31 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 32, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 42, + 32 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 35, + 43 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -2.875, + 4.825, + 5.5 + ], + "size": [ + 0.625, + 0.875, + 0.875 + ], + "uv": { + "north": { + "uv": [ + 42, + 35 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 42, + 36 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 42, + 38 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 42, + 39 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 42, + 40 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 42, + 42 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + 0.125, + 8.5, + 5 + ], + "size": [ + 0.25, + 0.375, + 1.125 + ], + "uv": { + "north": { + "uv": [ + 42, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 43, + 2 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 43, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 43, + 4 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 5, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 6 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -1.375, + 8.125, + 4.5 + ], + "size": [ + 0.25, + 0.375, + 1.875 + ], + "uv": { + "north": { + "uv": [ + 6, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 41, + 33 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 43, + 6 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 41, + 34 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 34, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 41, + 37 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + -1.375, + 8.5, + 5 + ], + "size": [ + 0.25, + 0.375, + 1.125 + ], + "uv": { + "north": { + "uv": [ + 7, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 43, + 8 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 43, + 9 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 43, + 10 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 11, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 12 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -0.75, + 7.75, + -11 + ], + "size": [ + 0.5, + 0.375, + 1.375 + ], + "uv": { + "north": { + "uv": [ + 12, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 13, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 14, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 43, + 14 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 16, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 17, + 44 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 3.375, + -14.625 + ], + "size": [ + 0.75, + 2, + 2 + ], + "pivot": [ + 13.5, + -5.25, + -14.5 + ], + "rotation": [ + -45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 36, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 39, + 26 + ], + "uv_size": [ + 2, + 2 + ] + }, + "south": { + "uv": [ + 37, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 39, + 28 + ], + "uv_size": [ + 2, + 2 + ] + }, + "up": { + "uv": [ + 38, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 39, + 43 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + -2.75, + 3.375, + -14.625 + ], + "size": [ + 0.75, + 2, + 2 + ], + "pivot": [ + -13.5, + -5.25, + -14.5 + ], + "rotation": [ + -45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 40, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 39, + 30 + ], + "uv_size": [ + 2, + 2 + ] + }, + "south": { + "uv": [ + 41, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 39, + 32 + ], + "uv_size": [ + 2, + 2 + ] + }, + "up": { + "uv": [ + 42, + 2 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 3, + 44 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + 1.75, + 3.875, + -14.125 + ], + "size": [ + 0.25, + 1, + 1 + ], + "pivot": [ + 13.5, + -5.25, + -14.5 + ], + "rotation": [ + -45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 18, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 43, + 18 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 43, + 19 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 20, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 43, + 20 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 21, + 44 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -3, + 3.875, + -14.125 + ], + "size": [ + 0.25, + 1, + 1 + ], + "pivot": [ + -13.5, + -5.25, + -14.5 + ], + "rotation": [ + -45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 43, + 21 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 22, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 43, + 22 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 43, + 23 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 24, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 25 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -1.5, + 4.25, + -13.5 + ], + "size": [ + 2, + 2, + 1.5 + ], + "pivot": [ + -0.5, + 5.25, + -12.75 + ], + "rotation": [ + 0, + 0, + -45 + ], + "uv": { + "north": { + "uv": [ + 39, + 34 + ], + "uv_size": [ + 2, + 2 + ] + }, + "east": { + "uv": [ + 36, + 39 + ], + "uv_size": [ + 2, + 2 + ] + }, + "south": { + "uv": [ + 39, + 36 + ], + "uv_size": [ + 2, + 2 + ] + }, + "west": { + "uv": [ + 38, + 39 + ], + "uv_size": [ + 2, + 2 + ] + }, + "up": { + "uv": [ + 40, + 2 + ], + "uv_size": [ + 2, + 2 + ] + }, + "down": { + "uv": [ + 3, + 42 + ], + "uv_size": [ + 2, + -2 + ] + } + } + }, + { + "origin": [ + -1.5, + 5.25, + 6.375 + ], + "size": [ + 2, + 2, + 0.25 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 8, + 40 + ], + "uv_size": [ + 2, + 2 + ] + }, + "east": { + "uv": [ + 4, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 40, + 8 + ], + "uv_size": [ + 2, + 2 + ] + }, + "west": { + "uv": [ + 42, + 5 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 41, + 37 + ], + "uv_size": [ + 2, + 1 + ] + }, + "down": { + "uv": [ + 42, + 8 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -0.75, + 6, + 6.625 + ], + "size": [ + 0.5, + 0.5, + 0.125 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 43, + 25 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 26, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 43, + 26 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 27, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 28 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + 0.25, + 5.375, + 6.625 + ], + "size": [ + 0.125, + 1.75, + 0.125 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 8, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 42, + 8 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 9, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 10, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 28, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 29 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -1.25, + 7, + 6.625 + ], + "size": [ + 1.5, + 0.125, + 0.125 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 11, + 42 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 29, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 42, + 12 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 43, + 29 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 13, + 42 + ], + "uv_size": [ + 2, + 1 + ] + }, + "down": { + "uv": [ + 42, + 14 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -1.25, + 5.375, + 6.625 + ], + "size": [ + 1.5, + 0.125, + 0.125 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 42, + 15 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 30, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 42, + 16 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 43, + 30 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 42, + 17 + ], + "uv_size": [ + 2, + 1 + ] + }, + "down": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -1.375, + 5.375, + 6.625 + ], + "size": [ + 0.125, + 1.75, + 0.125 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 15, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 19, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 42, + 21 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 23, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 31, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 32 + ], + "uv_size": [ + 1, + -1 + ] + } + } + } + ] + }, + { + "name": "bone", + "parent": "group", + "pivot": [ + -0.49601, + 5.23502, + -13.29665 + ], + "cubes": [ + { + "origin": [ + -0.99601, + 4.73502, + -13.29665 + ], + "size": [ + 1, + 1, + 0 + ], + "uv": { + "north": { + "uv": [ + 128, + 0 + ], + "uv_size": [ + -64, + 64 + ] + }, + "east": { + "uv": [ + 128, + 0 + ], + "uv_size": [ + 0, + 1 + ] + }, + "south": { + "uv": [ + 64, + 0 + ], + "uv_size": [ + 64, + 64 + ] + }, + "west": { + "uv": [ + 128, + 0 + ], + "uv_size": [ + 0, + 1 + ] + }, + "up": { + "uv": [ + 128, + 1 + ], + "uv_size": [ + 0, + -1 + ] + }, + "down": { + "uv": [ + 128, + 1 + ], + "uv_size": [ + 0, + -1 + ] + } + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/models/block/stargate.json b/common/src/main/resources/assets/azurelib/models/block/stargate.json new file mode 100644 index 000000000..bc6977543 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/block/stargate.json @@ -0,0 +1,96 @@ +{ + "credit": "Made with Blockbench", + "parent": "builtin/entity", + "texture_size": [ + 256, + 256 + ], + "display": { + "thirdperson_righthand": { + "scale": [ + 0.1, + 0.1, + 0.1 + ] + }, + "thirdperson_lefthand": { + "scale": [ + 0.1, + 0.1, + 0.1 + ] + }, + "firstperson_righthand": { + "rotation": [ + 0, + -64, + 0 + ], + "scale": [ + 0.1, + 0.1, + 0.1 + ] + }, + "firstperson_lefthand": { + "rotation": [ + 0, + -64, + 0 + ], + "scale": [ + 0.1, + 0.1, + 0.1 + ] + }, + "ground": { + "translation": [ + 0, + 1.75, + 0 + ], + "scale": [ + 0.1, + 0.1, + 0.1 + ] + }, + "gui": { + "rotation": [ + 0, + -36, + 0 + ], + "translation": [ + 0, + -6, + 0 + ], + "scale": [ + 0.18, + 0.18, + 0.18 + ] + }, + "head": { + "scale": [ + 0, + 0, + 0 + ] + }, + "fixed": { + "translation": [ + 0, + -6, + 0 + ], + "scale": [ + 0.2, + 0.2, + 0.2 + ] + } + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/models/item/doomicorn_boots.json b/common/src/main/resources/assets/azurelib/models/item/doomicorn_boots.json new file mode 100644 index 000000000..befab1952 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/doomicorn_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_boots" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/doomicorn_chestplate.json b/common/src/main/resources/assets/azurelib/models/item/doomicorn_chestplate.json new file mode 100644 index 000000000..96425b55a --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/doomicorn_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_chestplate" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/doomicorn_helmet.json b/common/src/main/resources/assets/azurelib/models/item/doomicorn_helmet.json new file mode 100644 index 000000000..0229c662d --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/doomicorn_helmet.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_helmet" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/doomicorn_leggings.json b/common/src/main/resources/assets/azurelib/models/item/doomicorn_leggings.json new file mode 100644 index 000000000..1afbd089c --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/doomicorn_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_leggings" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/pistol.json b/common/src/main/resources/assets/azurelib/models/item/pistol.json new file mode 100644 index 000000000..4164a6ee9 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/pistol.json @@ -0,0 +1,96 @@ +{ + "credit": "Made with Blockbench", + "parent": "builtin/entity", + "texture_size": [ + 128, + 64 + ], + "display": { + "thirdperson_righthand": { + "translation": [ + 0, + -1.25, + -0.25 + ], + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "thirdperson_lefthand": { + "translation": [ + 0, + -1.25, + -0.25 + ], + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "firstperson_righthand": { + "translation": [ + -9.5, + -5.5, + -5.75 + ] + }, + "firstperson_lefthand": { + "translation": [ + -8.75, + -5.5, + -5.75 + ] + }, + "ground": { + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "gui": { + "rotation": [ + 40, + -38, + 0 + ], + "translation": [ + -1, + -1.25, + 0 + ], + "scale": [ + 0.7, + 0.7, + 0.7 + ] + }, + "head": { + "scale": [ + 0, + 0, + 0 + ] + }, + "fixed": { + "rotation": [ + 0, + -90, + 0 + ], + "translation": [ + -1.75, + -2.5, + -0.25 + ], + "scale": [ + 0.8, + 0.8, + 0.8 + ] + } + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/models/item/stargate.json b/common/src/main/resources/assets/azurelib/models/item/stargate.json new file mode 100644 index 000000000..087c7af00 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/stargate.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/stargate" + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/textures/block/stargate.png b/common/src/main/resources/assets/azurelib/textures/block/stargate.png new file mode 100644 index 0000000000000000000000000000000000000000..7ef23d6292b596c40d528236854ba1b20c63a3da GIT binary patch literal 8667 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 DHE$o0 literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/azurelib/textures/item/doomicorn.png b/common/src/main/resources/assets/azurelib/textures/item/doomicorn.png new file mode 100644 index 0000000000000000000000000000000000000000..a504ce681eca5b98c56e5c6367a5933f956fe854 GIT binary patch literal 1189 zcmV;W1X}xvP)POYu2v#6S>sHCT-r>v%(rlXyrpq#p) zLF;6smXnW>jfIblhK`AXjE9AchK8PsKZb^ehJ=2DgM-yhj%<2zcyejLHg~c)a~(mFi%E1B~?ixNkCF4CL<#wB_bUg4+8)I0Q8KfrT_o{ z0d!JMQvg8b*k%9#1G-5>K~#9!wbqGt+Bg)(@jI#uw;eRhSF?4~AW!1N*^~EwxPH3E zAPeZ;-*MR#{VV%m9i-|>Q&&_s+Z{Plb!{b5jx+G`*WV0OJKOE$&E@5BfJ1F(<3ghV z<$;?=x;Yi-+B7caX#9Hu?>_uu;KRF9fq&#t~oyZE4)UPv{WOsa`Ue+~F-_TLMstHin4%u#x*lDe);EfY%P)xQ;wVLXM}ZXcY@W-_Dx zsme_fet3WX`qk@K_xIVjeJ?EFIB~#&I}y0QyEb?C!?>+r2)I1pjsni*0p~_5*lf02 zJ9#m7DYo0qURCYJudjjYYwgGTfUUs$tE;UeD{z?OS64oBd&_YGxx+XoGvMXp$14`d z3ArutgO8b87RYUZ?P$EJ_#g=YeM_=~C!r@d-;o_vg`5J!_-la}!mkBF`1ute(GU{_ z6y}Ls?v~FS{k{N|fwisy zK74lo#DdKSt@{<64}?M)sH*-^&S}D4lZ*m9Di+d%d`m;}Er0})pQWnj18?b%2jnY( zTBw!5G99K7y|~cyq!vg5AbU`fUbmmGOCEio(Ti63xYK_oI2V9$(^hAcFZsuz?ZOZM zED%B#fPHK_AO)c2KLrEQgsu&ZpeIQPwd}zh-gwyn&MlYD0UPn}rD?lH-b*IbSwIu# zH0iwe!hg%9A0E@pu9Z=MvVbSYgr`o(3O)pH^9gMS5hpq4#&=@~(TK$1BofH%RLH+%@OA)jbkf%={TIs`&ZL*V>=paAll%V}}WC~m4!jNb}C zj{^CG5aO=|VhBHW3U#^72c3hIhfA~vtlbch)C3OKjUXbe%})XQ-OvYgXHETlbu*nQ zq!|YwZD#@1`6>Z04gh_?3W^Y#d{>~hQ?nY30`vLY%TOR3ZWz$%K#t4upNuoUuES_Q z@V@PQ0hyJ^%I2s0fmXGwM*D$?wB_#wIfrwcJFy>>zZayiNCZg=pxh5irvp&c-E}|O z557A<7AW_Fk`&S(*TZeimFN3GV~XDk$AMrQo?+<=KC8OJ9@m3G00000NkvXXu0mjf DDoZ!s literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/azurelib/textures/item/doomicorn_boots.png b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_boots.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb401b3b7c07bad70354a4b77649c2b840ccdc8 GIT binary patch literal 136 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9JOMr-u0ZL4Lsu|2a5La|ZYV`Rbl7jv*Ddk{y_PBxmvQ^cb!(P;wEOnZPT^n;-xr8in|J c6f=G?s@`Q!ymNKoe4rKvPgg&ebxsLQ0Q|5bX8-^I literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/azurelib/textures/item/doomicorn_chestplate.png b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_chestplate.png new file mode 100644 index 0000000000000000000000000000000000000000..45562d9718955c8fbd368a18f64dbc719074afb6 GIT binary patch literal 338 zcmV-Y0j>UtP)F1LIeVqV_tpJ<<|Nrgn>!kpXp#Y5h{QRB(g7ozA%FMu$1bOlD@Rb01q5z56*wFd; z__M8g3g+uYRm_x6wmaOCCS_xSeo^z)PedYS=! z^YikGiG`sMeaXqhq@m?B kYkHijVXVdqcf)|ECc-EPMph;4;Q#;t07*qoM6N<$f;p_C3IG5A literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/azurelib/textures/item/doomicorn_helmet.png b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_helmet.png new file mode 100644 index 0000000000000000000000000000000000000000..c969da1462109167051b4cf6bbb7a95d7f03d85a GIT binary patch literal 503 zcmVAcnK_+8dYQH}NJC5uGH6INpbI~Pm!)DzFfne8#`uvm!Ika|>Pk26L|j;d zX@ay?TCvcfH=&)GV{D8G(7Lek?4RFx^Iil)J~3pT{{uXE`bd?Edwkt0@MFIP2&B}R zn?KF%TlWrqdaQzHD-YFfd5iq}RXigEQliNaBhdu56~{{1+_--CPwo(~^5U_ob()k5 z>+F1dOW2Gf!(mVYO*iPqVvL>0GHGYIa%riTJpwGNcRL$wyA>upL8nn8@IAbCi^jJK zZD*P(XO8*AUw~Ji*Vu5&Oe8Io@1cT#An@@I4(N`K;8+>Xr=|v1@TQdGLv@po9wHKn zAf@b0S_pv`_&CvVE?B1q1MBV=a@(6!>n>)(#4rq$QV0YF8q@JKv&qb0pt@V8P_Ix_ z`zWEI34ubP0VfHQjg4a^(_FoLvwsuwtFQU)mWj@sBk)a>FA=(jCiiINb0i`uGG{Nc zaP3Zip!8{tx?5w^c4#)B+X1ZyH0inpVrHDN$yt^b9~=jMHS77yWz}kWl#2D=o7nD6 tTh|3MXVTbqjKzif{TJz94r}OR`U#`sxe@0ys=)vN002ovPDHLkV1o16=w|=` literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/azurelib/textures/item/doomicorn_leggings.png b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_leggings.png new file mode 100644 index 0000000000000000000000000000000000000000..5d252cff21c34684e7b62c949585c39b804dd715 GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`L7py-Ar-f-2D&mHFc9#zRucXg z@INjs$>)o-F>BrN_UnoU4gxHqVh<|g^xgCP=k-mrXsj0zn0tJ}ay5m_d0G#4)m46D mdzrq!K(1-YS`i+bRw>C?{(lv_eYOHkXYh3Ob6Mw<&;$U>X)TQa literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/azurelib/textures/item/pistol.png b/common/src/main/resources/assets/azurelib/textures/item/pistol.png new file mode 100644 index 0000000000000000000000000000000000000000..290e21ba10d8170a3d0bb0d087335cfad19524f9 GIT binary patch literal 1486 zcmV;<1u^=GP)z>$|NsB0RVx4g|G$7>s#Q7Y=;+b8xzTi8xkfIwTQ|da zTC__%@$vD$SwQpi^WMC%yjeHQdQ$7_>%CPu-`Cg2cv#7DQN?so#&}b{Up&KWLBL)* zzhpeZWj)1gLBeZ2$$e78Z9&CvKfj!a%!XRTZ$Qa-Bj$Xy7lF*J>%!5eKk6O%yNzaH&)}3nAn`Y3FPR)l<)S6Y(mQd84 zSJt6f)t^-0xqaHKU)ZQu+_7WcvUJ|GX6D+!<;9HPx^Cynkl?&(*PvkO(3k7fp5ni6 zC=Ay|NsC0{{R2{|Nr{`|M>s@_5S_){{8v> z{rCR<@c#Ym{rvO&`|AArCH#tB@Q&?JFWoKz@adUr#hL4$^qo$~-ud=ndy2HlK(AC-6-s0u#?C$UI@$>Wa z_V)Jo`1twy{Qdp@{{H?9UglZ=00W{)L_t(|+U?bam)kfHfN^b^nVIRB%XrLKW@fG& zYi9oU`{c-Z-aPxTN@;&j8$&_gPRN<6B?^IpO9??t;eBZp*JhHNv=Uu^=900oF*gIV zFgKZjDu5rBN>NBair_)weUnnU116y>U=jua_^W`n38-)Y$9S`sCqO0rn!^Q97OI(; z|u?llB6@!452|x|R8A9HG zw*66-C674+go($1wr2po5fHKk#Gj4{c<-$eLSe4MJNOKTaR9Ti86RRd-ot#%!(P0F zWtf3~62N8tfc7^5>K7qizyttAzJS5IK#f(FJ}&sj3K$?(6t2U1?86VZfMfU`zu-rF zi4UwD)KOJn90jffQhtH9)IX0w4e&0LV0f!PjvLNUs4XVECJW zIdJ#{cX1CFa2^kE61#B*8?YpqgW&*QDIXJ&_8x732N2%}W+h-1$r8Xe6$!#B6JMqP z-w4nV1aQLiQ-C*P6oS8;0I(Xna0@qZ6Ay764{-^{unluD3oi1$EdW&j2diI*g^nh` z$AJ1?Nbke^0qI3JE`Vz>AmdXIf{3;SVCY6?z)bAIA)LSsT*Wn9!FAliY3#-%OhG?@ zjjaw~G4`|{)F7pB14Whq#@q-n9%6v1_lDS`LRPPrE5Q0w_8hClZjFH0V^PKcgh2q* zngR3}^e+Q8;~>7mNj$=RTuQFsJ}zQAT+$Mt%Apa^zu=HJKzzk)5YXQ_zC%V3fD{0= zL4YrVsB*zHBwqj<*IzpZqyW#hD$M}bWeWD=Yn;GC+{a~H!Y$mvQ+$E<(H-zOosh27 z3vkcNM(n{Y+(>TY3ZCF59^eSxhD#;_UXOr9_!K|mChp=WPT(ZI#W~!-co oYtg*tumWz#B-F==fEOO{CwClw<{7>lW&i*H07*qoM6N<$f-?r#K>z>% literal 0 HcmV?d00001 diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index 7948058c8..ea27c2315 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -2,19 +2,23 @@ import com.mojang.blaze3d.platform.InputConstants; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; import net.minecraft.client.KeyMapping; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; import org.lwjgl.glfw.GLFW; import mod.azure.azurelib.common.api.client.helper.ClientUtils; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.network.packet.*; -import mod.azure.azurelib.fabric.core2.example.DroneRenderer; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; -import mod.azure.azurelib.fabric.core2.example.FacehuggerRenderer; -import mod.azure.azurelib.fabric.core2.example.azure.DoomHunterRenderer; +import mod.azure.azurelib.fabric.core2.example.blocks.StargateRender; +import mod.azure.azurelib.fabric.core2.example.entities.doomhunter.DoomHunterRenderer; +import mod.azure.azurelib.fabric.core2.example.entities.drone.DroneRenderer; public final class ClientListener implements ClientModInitializer { @@ -65,7 +69,11 @@ public void onInitializeClient() { ClientPlayNetworking.registerGlobalReceiver(SendConfigDataPacket.TYPE, (packet, context) -> packet.handle()); EntityRendererRegistry.register(ExampleEntityTypes.DRONE, DroneRenderer::new); - EntityRendererRegistry.register(ExampleEntityTypes.FACEHUGGER, FacehuggerRenderer::new); EntityRendererRegistry.register(ExampleEntityTypes.DOOMHUNTER, DoomHunterRenderer::new); + BlockRenderLayerMap.INSTANCE.putBlock(FabricAzureLibMod.STARGATE, RenderType.translucent()); + BlockEntityRenderers.register( + ExampleEntityTypes.STARGATE, + (BlockEntityRendererProvider.Context rendererDispatcherIn) -> new StargateRender() + ); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 9f863138d..21f8e118a 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -3,6 +3,14 @@ import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockBehaviour; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.AzureLibMod; @@ -18,10 +26,17 @@ import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimTriggerPacket; import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; +import mod.azure.azurelib.fabric.core2.example.armors.DoomArmor; +import mod.azure.azurelib.fabric.core2.example.blocks.Stargate; +import mod.azure.azurelib.fabric.core2.example.items.Pistol; import mod.azure.azurelib.fabric.platform.FabricAzureLibNetwork; public final class FabricAzureLibMod implements ModInitializer { + public static final Block STARGATE = new Stargate( + BlockBehaviour.Properties.of().sound(SoundType.DRIPSTONE_BLOCK).strength(5.0f, 8.0f).noOcclusion() + ); + @Override public void onInitialize() { ConfigIO.FILE_WATCH_MANAGER.startService(); @@ -38,7 +53,37 @@ public void onInitialize() { PayloadTypeRegistry.playS2C().register(AnimTriggerPacket.TYPE, AnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(AnimDataSyncPacket.TYPE, AnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(SendConfigDataPacket.TYPE, SendConfigDataPacket.CODEC); - + Registry.register(BuiltInRegistries.BLOCK, AzureLib.modResource("stargate"), STARGATE); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("stargate"), + new BlockItem(STARGATE, new Item.Properties()) + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("pistol"), + new Pistol() + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("doomicorn_helmet"), + new DoomArmor(ArmorItem.Type.HELMET) + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("doomicorn_chestplate"), + new DoomArmor(ArmorItem.Type.CHESTPLATE) + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("doomicorn_leggings"), + new DoomArmor(ArmorItem.Type.LEGGINGS) + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("doomicorn_boots"), + new DoomArmor(ArmorItem.Type.BOOTS) + ); ExampleEntityTypes.initialize(); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java index 2ee0943d1..b36d16eda 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java @@ -1,14 +1,19 @@ package mod.azure.azurelib.fabric.core2.example; +import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.block.entity.BlockEntityType; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.fabric.core2.example.azure.DoomHunter; +import mod.azure.azurelib.fabric.FabricAzureLibMod; +import mod.azure.azurelib.fabric.core2.example.blocks.StargateBlockEntity; +import mod.azure.azurelib.fabric.core2.example.entities.doomhunter.DoomHunter; +import mod.azure.azurelib.fabric.core2.example.entities.drone.Drone; public class ExampleEntityTypes { @@ -29,9 +34,14 @@ private static EntityType register(String name, EntityType return entityType; } + public static BlockEntityType STARGATE = Registry.register( + BuiltInRegistries.BLOCK_ENTITY_TYPE, + AzureLib.modResource("stargate"), + FabricBlockEntityTypeBuilder.create(StargateBlockEntity::new, FabricAzureLibMod.STARGATE).build(null) + );; + public static void initialize() { FabricDefaultAttributeRegistry.register(DRONE, Drone.createMonsterAttributes()); - FabricDefaultAttributeRegistry.register(FACEHUGGER, Facehugger.createMonsterAttributes()); FabricDefaultAttributeRegistry.register(DOOMHUNTER, DoomHunter.createMonsterAttributes()); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/ArmorRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/ArmorRenderer.java new file mode 100644 index 000000000..e06c578a9 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/ArmorRenderer.java @@ -0,0 +1,37 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import net.minecraft.world.item.ArmorItem; + +import mod.azure.azurelib.common.api.client.model.DefaultedItemGeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; + +public class ArmorRenderer extends GeoArmorRenderer { + + public ArmorRenderer() { + super(new DefaultedItemGeoModel<>(AzureLib.modResource("doomicorn"))); + } + + // Only models I have on for armors with animations, the arm/legs are named wrong and i just didnt want to load it + // in bb again to rename, this should be a feature kept though + @Override + public GeoBone getLeftBootBone() { + return this.model.getBone("armorRightBoot").orElse(null); + } + + @Override + public GeoBone getLeftLegBone() { + return this.model.getBone("armorRightLeg").orElse(null); + } + + @Override + public GeoBone getRightBootBone() { + return this.model.getBone("armorLeftBoot").orElse(null); + } + + @Override + public GeoBone getRightLegBone() { + return this.model.getBone("armorLeftLeg").orElse(null); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/DoomArmor.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/DoomArmor.java new file mode 100644 index 000000000..bbb0704bd --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/DoomArmor.java @@ -0,0 +1,69 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArmorMaterials; +import net.minecraft.world.item.ItemStack; + +import java.util.function.Consumer; + +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; +import mod.azure.azurelib.core.animation.AnimatableManager; +import mod.azure.azurelib.core.animation.AnimationController; +import mod.azure.azurelib.core.animation.RawAnimation; +import mod.azure.azurelib.core.object.PlayState; + +public class DoomArmor extends ArmorItem implements GeoItem { + + private final AnimatableInstanceCache cache = AzureLibUtil.createInstanceCache(this); + + private static final String EQUIP_ANIMATION_NAME = "equipping"; + + private static final RawAnimation EQUIP_ANIMATION = RawAnimation.begin().thenLoop(EQUIP_ANIMATION_NAME); + + public DoomArmor(Type type) { + super(ArmorMaterials.NETHERITE, type, new Properties()); + } + + @Override + public void createRenderer(Consumer consumer) { + consumer.accept(new RenderProvider() { + + private ArmorRenderer renderer; + + @Override + public HumanoidModel getHumanoidArmorModel( + LivingEntity livingEntity, + ItemStack itemStack, + EquipmentSlot equipmentSlot, + HumanoidModel original + ) { + if (renderer == null) { + renderer = new ArmorRenderer(); + } + renderer.prepForRender(livingEntity, itemStack, equipmentSlot, original); + return this.renderer; + } + }); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { + controllers.add( + new AnimationController<>(this, "base_controller", 0, state -> PlayState.CONTINUE).triggerableAnim( + EQUIP_ANIMATION_NAME, + EQUIP_ANIMATION + ) + ); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return cache; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java new file mode 100644 index 000000000..cfecef419 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java @@ -0,0 +1,42 @@ +package mod.azure.azurelib.fabric.core2.example.blocks; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; +import mod.azure.azurelib.core.animation.AnimatableManager; +import mod.azure.azurelib.core.animation.AnimationController; +import mod.azure.azurelib.core.animation.RawAnimation; +import mod.azure.azurelib.core.object.PlayState; +import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; + +public class StargateBlockEntity extends BlockEntity implements GeoBlockEntity { + + private final AnimatableInstanceCache cache = AzureLibUtil.createInstanceCache(this); + + private static final String SPIN_ANIMATION_NAME = "equipping"; + + private static final RawAnimation SPIN_ANIMATION = RawAnimation.begin().thenLoop(SPIN_ANIMATION_NAME); + + public StargateBlockEntity(BlockPos pos, BlockState blockState) { + super(ExampleEntityTypes.STARGATE, pos, blockState); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { + controllers.add( + new AnimationController<>(this, "base_controller", 0, state -> PlayState.CONTINUE).triggerableAnim( + SPIN_ANIMATION_NAME, + SPIN_ANIMATION + ) + ); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return cache; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java new file mode 100644 index 000000000..6fd9dc875 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java @@ -0,0 +1,12 @@ +package mod.azure.azurelib.fabric.core2.example.blocks; + +import mod.azure.azurelib.common.api.client.model.DefaultedBlockGeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoBlockRenderer; +import mod.azure.azurelib.common.internal.common.AzureLib; + +public class StargateRender extends GeoBlockRenderer { + + public StargateRender() { + super(new DefaultedBlockGeoModel<>(AzureLib.modResource("stargate"))); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/Pistol.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/Pistol.java new file mode 100644 index 000000000..b3278c673 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/Pistol.java @@ -0,0 +1,93 @@ +package mod.azure.azurelib.fabric.core2.example.items; + +import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; + +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; +import mod.azure.azurelib.core.animation.AnimatableManager; +import mod.azure.azurelib.core.animation.Animation; +import mod.azure.azurelib.core.animation.AnimationController; +import mod.azure.azurelib.core.animation.RawAnimation; +import mod.azure.azurelib.core.object.PlayState; + +public class Pistol extends Item implements GeoItem { + + private final AnimatableInstanceCache cache = AzureLibUtil.createInstanceCache(this); + + private static final String FIRING_ANIMATION_NAME = "firing"; + + private static final RawAnimation FIRING_ANIMATION = RawAnimation.begin() + .then(FIRING_ANIMATION_NAME, Animation.LoopType.PLAY_ONCE); + + public Pistol() { + super(new Properties()); + SingletonGeoAnimatable.registerSyncedAnimatable(this); // Needed to make triggerable animations work + } + + @Override + public void onUseTick(Level level, LivingEntity livingEntity, ItemStack stack, int remainingUseDuration) { + super.onUseTick(level, livingEntity, stack, remainingUseDuration); + if (livingEntity instanceof Player player && !level.isClientSide()) { + triggerAnim( + player, + GeoItem.getOrAssignId(stack, (ServerLevel) level), + "base_controller", + FIRING_ANIMATION_NAME + ); + } + } + + @Override + public @NotNull InteractionResultHolder use( + @NotNull Level world, + Player user, + @NotNull InteractionHand hand + ) { + final var itemStack = user.getItemInHand(hand); + user.startUsingItem(hand); + return InteractionResultHolder.consume(itemStack); + } + + @Override + public void createRenderer(Consumer consumer) { + consumer.accept(new RenderProvider() { + + private PistolRender renderer = null; + + @Override + public BlockEntityWithoutLevelRenderer getCustomRenderer() { + this.renderer = new PistolRender(); + return this.renderer; + } + }); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { + controllers.add( + new AnimationController<>(this, "base_controller", event -> PlayState.CONTINUE).triggerableAnim( + FIRING_ANIMATION_NAME, + FIRING_ANIMATION + ) + ); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return cache; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/PistolRender.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/PistolRender.java new file mode 100644 index 000000000..157428209 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/PistolRender.java @@ -0,0 +1,12 @@ +package mod.azure.azurelib.fabric.core2.example.items; + +import mod.azure.azurelib.common.api.client.model.DefaultedItemGeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoItemRenderer; +import mod.azure.azurelib.common.internal.common.AzureLib; + +public class PistolRender extends GeoItemRenderer { + + public PistolRender() { + super(new DefaultedItemGeoModel<>(AzureLib.modResource("pistol"))); + } +} From e2cf434caba366934e03071a611977ffe094e2b1 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sun, 15 Dec 2024 02:16:34 -0500 Subject: [PATCH 089/224] Marauder added to test the glowmask/autoglowlayer when that's ported --- .../animations/entity/marauder.animation.json | 6262 +++++++++++++++++ .../azurelib/geo/entity/marauder.geo.json | 4168 +++++++++++ .../azurelib/textures/entity/marauder.png | Bin 0 -> 11573 bytes .../textures/entity/marauder_glowmask.png | Bin 0 -> 7478 bytes .../azure/azurelib/fabric/ClientListener.java | 2 + .../core2/example/ExampleEntityTypes.java | 7 + .../entities/marauder/MarauderAnimator.java | 64 + .../entities/marauder/MarauderEntity.java | 87 + .../entities/marauder/MarauderRenderer.java | 40 + 9 files changed, 10630 insertions(+) create mode 100644 common/src/main/resources/assets/azurelib/animations/entity/marauder.animation.json create mode 100644 common/src/main/resources/assets/azurelib/geo/entity/marauder.geo.json create mode 100644 common/src/main/resources/assets/azurelib/textures/entity/marauder.png create mode 100644 common/src/main/resources/assets/azurelib/textures/entity/marauder_glowmask.png create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java diff --git a/common/src/main/resources/assets/azurelib/animations/entity/marauder.animation.json b/common/src/main/resources/assets/azurelib/animations/entity/marauder.animation.json new file mode 100644 index 000000000..94ee538c4 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/entity/marauder.animation.json @@ -0,0 +1,6262 @@ +{ + "format_version": "1.8.0", + "animations": { + "idle": { + "loop": true, + "animation_length": 2, + "bones": { + "torso": { + "rotation": { + "vector": [0, 22.5, 0] + } + }, + "right_arm": { + "rotation": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0.5, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.2": { + "vector": [-2.83, 0, 0] + }, + "0.8": { + "vector": [-7.17, 0, 0] + }, + "1.0": { + "vector": [-7.5, 0, 0] + }, + "1.2": { + "vector": [-7.17, 0, 0] + }, + "1.8": { + "vector": [-2.83, 0, 0] + }, + "2.0": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, -1.5] + }, + "0.2": { + "vector": [0, -0.25, -1.5] + }, + "0.8": { + "vector": [0, -0.25, -1.5] + }, + "1.0": { + "vector": [0, -0.25, -1.5] + }, + "1.2": { + "vector": [0, -0.25, -1.5] + }, + "1.8": { + "vector": [0, -0.25, -1.5] + }, + "2.0": { + "vector": [0, -0.25, -1.5] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.2": { + "vector": [5.67, 0, 0] + }, + "0.8": { + "vector": [14.33, 0, 0] + }, + "1.0": { + "vector": [15, 0, 0] + }, + "1.2": { + "vector": [14.33, 0, 0] + }, + "1.8": { + "vector": [5.67, 0, 0] + }, + "2.0": { + "vector": [5, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.2": { + "vector": [-2.83, 0, 0] + }, + "0.8": { + "vector": [-7.17, 0, 0] + }, + "1.0": { + "vector": [-7.5, 0, 0] + }, + "1.2": { + "vector": [-7.17, 0, 0] + }, + "1.8": { + "vector": [-2.83, 0, 0] + }, + "2.0": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0.5] + }, + "0.2": { + "vector": [0, -0.25, 0.5] + }, + "0.8": { + "vector": [0, -0.25, 0.5] + }, + "1.0": { + "vector": [0, -0.25, 0.5] + }, + "1.2": { + "vector": [0, -0.25, 0.5] + }, + "1.8": { + "vector": [0, -0.25, 0.5] + }, + "2.0": { + "vector": [0, -0.25, 0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.2": { + "vector": [5.67, 0, 0] + }, + "0.8": { + "vector": [14.33, 0, 0] + }, + "1.0": { + "vector": [15, 0, 0] + }, + "1.2": { + "vector": [14.33, 0, 0] + }, + "1.8": { + "vector": [5.67, 0, 0] + }, + "2.0": { + "vector": [5, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "vector": [0, -22.5, 0] + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0.25, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, -0.5, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_attack": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [1, 1, 1] + } + } + } + }, + "walk": { + "loop": true, + "animation_length": 2, + "bones": { + "torso": { + "rotation": { + "vector": [0, 22.5, 0] + }, + "position": { + "0.0": { + "vector": [-0.25, 0, 0] + }, + "0.3": { + "vector": [-0.33, 0, 0] + }, + "1.0": { + "vector": [0.25, 0, 0] + }, + "1.3": { + "vector": [0.33, 0, 0] + }, + "2.0": { + "vector": [-0.25, 0, 0] + } + } + }, + "upper_torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 1] + }, + "0.3": { + "vector": [0, 0, 1.5] + }, + "1.0": { + "vector": [0, 0, -1] + }, + "1.3": { + "vector": [0, 0, -1.5] + }, + "2.0": { + "vector": [0, 0, 1] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, -0.17, 0] + }, + "0.2": { + "vector": [0, -0.83, 0] + }, + "0.3": { + "vector": [0, -1, 0] + }, + "0.45": { + "vector": [0, -0.93, 0] + }, + "0.85": { + "vector": [0, -0.07, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.1": { + "vector": [0, -0.17, 0] + }, + "1.2": { + "vector": [0, -0.83, 0] + }, + "1.3": { + "vector": [0, -1, 0] + }, + "1.45": { + "vector": [0, -0.93, 0] + }, + "1.85": { + "vector": [0, -0.07, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.3": { + "vector": [37.94, 29.52, 9.71] + }, + "1.0": { + "vector": [37.1047, 28.17926, 12.12078] + }, + "1.3": { + "vector": [36.1047, 28.17926, 12.12078] + }, + "2.0": { + "vector": [36.94319, 29.52361, 9.71415] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, 0.17, 0] + }, + "0.2": { + "vector": [0, 0.83, 0] + }, + "0.3": { + "vector": [0, 1, 0] + }, + "0.45": { + "vector": [0, 0.93, 0] + }, + "0.85": { + "vector": [0, 0.07, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.1": { + "vector": [0, 0.17, 0] + }, + "1.2": { + "vector": [0, 0.83, 0] + }, + "1.3": { + "vector": [0, 1, 0] + }, + "1.45": { + "vector": [0, 0.93, 0] + }, + "1.85": { + "vector": [0, 0.07, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [12.5, 0, 0] + }, + "0.55": { + "vector": [-10, 0, 0] + }, + "1.0": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "2.0": { + "vector": [12.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.5, -1] + }, + "0.15": { + "vector": [0, 1, -2] + }, + "0.55": { + "vector": [0, 1, -2] + }, + "1.0": { + "vector": [0, -1, -2.5] + }, + "2.0": { + "vector": [0, -0.5, -1] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [32.5, 0, 0] + }, + "1.0": { + "vector": [5, 0, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "1.0": { + "vector": [12.5, 0, 0] + }, + "1.55": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "2.0": { + "vector": [-9.96271, -0.86717, -4.92442] + } + }, + "position": { + "0.0": { + "vector": [0, -1, -0.5] + }, + "1.0": { + "vector": [0, -0.5, 1] + }, + "1.15": { + "vector": [0, 1, 0] + }, + "1.55": { + "vector": [0, 1, 0] + }, + "2.0": { + "vector": [0, -1, -0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.3": { + "vector": [32.5, 0, 0] + }, + "2.0": { + "vector": [5, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, -22.5, -1] + }, + "0.3": { + "vector": [0, -22.5, -1.5] + }, + "1.0": { + "vector": [0, -22.5, 1] + }, + "1.3": { + "vector": [0, -22.5, 1.5] + }, + "2.0": { + "vector": [0, -22.5, -1] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_attack": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.95": { + "effect": "walk" + }, + "1.95": { + "effect": "walk" + } + } + }, + "run": { + "loop": true, + "animation_length": 0.5, + "bones": { + "torso": { + "rotation": { + "vector": [25, 0, 0] + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [-47.41709, -12.48859, 0.54146] + }, + "0.1": { + "vector": [-16.79911, -16.90142, 4.98561] + }, + "0.25": { + "vector": [39.3969, -19.7052, 3.8848] + }, + "0.5": { + "vector": [-47.41709, -12.48859, 0.54146] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [-27.5, 0, 0] + }, + "0.5": { + "vector": [-27.5, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [39.3969, 19.7052, -3.8848] + }, + "0.25": { + "vector": [-47.41709, 12.4886, -0.5415] + }, + "0.35": { + "vector": [-16.79911, 16.9014, -4.9856] + }, + "0.5": { + "vector": [39.3969, 19.7052, -3.8848] + } + } + }, + "right_elbow": { + "rotation": { + "0.0": { + "vector": [-27.5, 0, 0] + }, + "0.5": { + "vector": [-27.5, 0, 0] + } + } + }, + "axe": { + "rotation": { + "vector": [-45, -45, 0] + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [48.84318, 11.0235, -2.4076] + }, + "0.25": { + "vector": [-47.31623, 14.328, 1.6962] + }, + "0.35": { + "vector": [-16.25675, 7.3218, 2.8407] + }, + "0.5": { + "vector": [48.84318, 11.0235, -2.4076] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, -1, -2] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [41.96457, 0, 0] + }, + "0.1": { + "vector": [22.01779, 0, 0] + }, + "0.25": { + "vector": [10.44841, 0, 0] + }, + "0.5": { + "vector": [41.96457, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-47.31623, -14.32798, -1.69619] + }, + "0.1": { + "vector": [-16.25675, -7.32179, -2.84073] + }, + "0.25": { + "vector": [48.84318, -11.02346, 2.40756] + }, + "0.5": { + "vector": [-47.31623, -14.32798, -1.69619] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, -1, -2] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [10.44841, 0, 0] + }, + "0.25": { + "vector": [41.96457, 0, 0] + }, + "0.35": { + "vector": [22.01779, 0, 0] + }, + "0.5": { + "vector": [10.44841, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "vector": [-15, 0, 0] + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, -2, 0] + }, + "0.2": { + "vector": [0, 1.5, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, -2, 0] + }, + "0.45": { + "vector": [0, 1.5, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_attack": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.05": { + "effect": "walk" + }, + "0.15": { + "effect": "walk" + }, + "0.3": { + "effect": "walk" + }, + "0.4": { + "effect": "walk" + } + } + }, + "energy_slash": { + "animation_length": 1, + "bones": { + "torso": { + "rotation": { + "0.0": { + "vector": [0, 22.5, 0] + }, + "0.25": { + "vector": [-22.45376, 4.88119, 1.08482], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [20.15711, -30.42471, 3.15289], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [0, 22.5, 0], + "easing": "easeInOutQuad" + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2": { + "vector": [0, 0.05, 0] + }, + "0.25": { + "vector": [0, 0.8, 0] + }, + "0.4": { + "vector": [0, 0.95, 0] + }, + "0.5": { + "vector": [0, 0.95, 0] + }, + "0.65": { + "vector": [0, 0.8, 0] + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-42.73421, -15.69986, -38.82495], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [-25.00772, 13.4395, -26.99582], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [-22.5, 0, 0], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.25": { + "vector": [-170.91589, -12.68945, -29.87236], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [-50.77424, 27.00637, -42.94328], + "easing": "easeInOutQuad" + }, + "0.5": { + "vector": [-21.42177, 17.7925, -31.36258], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [36.94319, 29.52361, 9.71415], + "easing": "easeInOutQuad" + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "axe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-45, -45, 15], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [22.5, -45, 15], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.25": { + "vector": [-56.86218, 2.34352, -12.28179] + }, + "0.4": { + "vector": [-32.5, 0, 0] + }, + "0.5": { + "vector": [-32.5, 0, 0] + }, + "1.0": { + "vector": [-2.5, 0, 0], + "easing": "easeInOutQuad" + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, -1.5] + }, + "1.0": { + "vector": [0, -0.25, -1.5], + "easing": "easeInOutQuad" + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.25": { + "vector": [45, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [45, 0, 0], + "easing": "easeInOutQuad" + }, + "0.5": { + "vector": [45, 0, 0], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [5, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.25": { + "vector": [10.4943, -0.822, -2.71827] + }, + "0.4": { + "vector": [37.5, 0, 0] + }, + "0.5": { + "vector": [37.5, 0, 0] + }, + "1.0": { + "vector": [-2.5, 0, 0], + "easing": "easeInOutQuad" + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0.5] + }, + "1.0": { + "vector": [0, -0.25, 0.5], + "easing": "easeInOutQuad" + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "1.0": { + "vector": [5, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "h_slash": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 4, -8] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + }, + "scale": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.35": { + "vector": [1, 1, 1], + "easing": "easeInOutQuad" + } + } + }, + "h_slash2": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash3": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash4": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash5": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash6": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash7": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash8": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash9": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash10": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.25": { + "vector": [33.77048, -5.99032, 2.66499] + }, + "0.4": { + "vector": [-5.12161, 25.82329, -2.83601] + }, + "0.5": { + "vector": [-5.12161, 25.82329, -2.83601] + }, + "0.75": { + "vector": [-0.75543, 4.97912, -2.45465] + }, + "1.0": { + "vector": [0, -22.5, 0], + "easing": "easeInOutQuad" + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.15": { + "vector": [0, -1, 2] + }, + "0.3": { + "vector": [0, -1, 2] + }, + "0.4": { + "vector": [0, -4, -8] + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.35": { + "effect": "slash" + } + } + }, + "hook": { + "animation_length": 1, + "bones": { + "torso": { + "rotation": { + "0.0": { + "vector": [0, 22.5, 0] + }, + "0.35": { + "vector": [0, -45, 0] + }, + "0.5": { + "vector": [30, 45, 0] + }, + "0.6": { + "vector": [63.10819, 71.24264, 36.51548] + }, + "1.0": { + "vector": [0, 22.5, 0] + } + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.4": { + "vector": [62.65725, 6.55676, -77.51703] + }, + "0.5": { + "vector": [-67.34275, 6.55676, -77.51703] + }, + "0.6": { + "vector": [-104.84275, 6.55676, -77.51703] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-60, 0, 0] + }, + "0.4": { + "vector": [-91.5, 0, 0] + }, + "0.5": { + "vector": [-37.5, 0, 0] + }, + "0.6": { + "vector": [-30.5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.35": { + "vector": [42.52426, 19.88275, 12.4118] + }, + "0.4": { + "vector": [42.52426, 19.88275, 12.4118] + }, + "0.45": { + "vector": [10.82416, 8.65125, 9.70546] + }, + "0.5": { + "vector": [-5.0275, -2.11363, 18.00718] + }, + "0.6": { + "vector": [-14.10919, -0.72303, 17.14132] + }, + "1.0": { + "vector": [36.94319, 29.52361, 9.71415] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [1, 0, 1] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "right_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [22.5, 0, 0] + }, + "0.35": { + "vector": [22.5, 0, 0] + }, + "0.4": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [7.5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.4": { + "vector": [-7.5, 0, 0] + }, + "0.5": { + "vector": [-2.5, 0, 0] + }, + "1.0": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, -1.5] + }, + "0.5": { + "vector": [0, -0.25, -1.5] + }, + "1.0": { + "vector": [0, -0.25, -1.5] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.4": { + "vector": [12.5, 0, 0] + }, + "0.5": { + "vector": [5, 0, 0] + }, + "1.0": { + "vector": [5, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.4": { + "vector": [-7.5, 0, 0] + }, + "0.5": { + "vector": [-2.5, 0, 0] + }, + "1.0": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0.5] + }, + "0.5": { + "vector": [0, -0.25, -1.5] + }, + "1.0": { + "vector": [0, -0.25, 0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.4": { + "vector": [12.5, 0, 0] + }, + "0.5": { + "vector": [5, 0, 0] + }, + "1.0": { + "vector": [5, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.25": { + "vector": [18.81517, 32.16683, 2.79164] + }, + "0.3": { + "vector": [17.23042, 35.45167, 3.72115] + }, + "0.35": { + "vector": [15.61275, 38.78143, 4.50441] + }, + "0.4": { + "vector": [1.82829, 15.09442, -2.58693] + }, + "0.5": { + "vector": [-3.83528, -41.13981, 7.84775] + }, + "0.6": { + "vector": [-20.07884, -63.15509, 26.26946] + }, + "0.8": { + "vector": [-0.62387, -43.76225, -0.56045] + }, + "1.0": { + "vector": [0, -22.5, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.45": { + "effect": "axe_hit" + } + } + }, + "shoot": { + "animation_length": 1.25, + "bones": { + "torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, 3.75, 0] + }, + "0.2": { + "vector": [0, 18.75, 0] + }, + "0.3": { + "vector": [0, 22.5, 0] + }, + "0.55": { + "vector": [0, 22.5, 0] + }, + "0.75": { + "vector": [0, 22.5, 0] + }, + "0.85": { + "vector": [0, 20.89, 0] + }, + "1.15": { + "vector": [0, 1.61, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "upper_torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, 3.75, 0] + }, + "0.2": { + "vector": [0, 18.75, 0] + }, + "0.3": { + "vector": [0, 22.5, 0] + }, + "0.55": { + "vector": [0, 22.5, 0] + }, + "0.65": { + "vector": [-3.53092, 22.36846, -2.70099] + }, + "0.75": { + "vector": [-3.53, 22.37, -2.7] + }, + "0.85": { + "vector": [-3.28, 20.77, -2.51] + }, + "1.15": { + "vector": [-0.25, 1.6, -0.19] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.65": { + "vector": [0, 0, 1] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.85": { + "vector": [0, 0, 0] + }, + "1.15": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [-10.25, -7.3, 2.45] + }, + "0.2": { + "vector": [-51.27, -36.49, 12.26] + }, + "0.3": { + "vector": [-61.52003, -43.79162, 14.71526] + }, + "0.55": { + "vector": [-61.52003, -43.79162, 14.71526] + }, + "0.65": { + "vector": [-106.52003, -43.79162, 14.71526] + }, + "0.75": { + "vector": [-106.52, -43.79, 14.72] + }, + "0.85": { + "vector": [-98.91, -40.66, 13.67] + }, + "1.15": { + "vector": [-7.61, -3.13, 1.05] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.55": { + "vector": [0, 0, 0] + }, + "0.65": { + "vector": [0, 0, 1] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.85": { + "vector": [0, 0, 0] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.65": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "0.85": { + "vector": [-20.89, 0, 0] + }, + "1.15": { + "vector": [-1.61, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.1": { + "vector": [32.45, 24.6, 8.1] + }, + "0.2": { + "vector": [14.49, 4.92, 1.62] + }, + "0.3": { + "vector": [10, 0, 0] + }, + "0.75": { + "vector": [10, 0, 0] + }, + "0.85": { + "vector": [11.68, 1.85, 0.61] + }, + "1.15": { + "vector": [35.26, 27.68, 9.11] + }, + "1.25": { + "vector": [36.94319, 29.52361, 9.71415] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0.83, -7.5, 0] + }, + "0.2": { + "vector": [4.17, -37.5, 0] + }, + "0.3": { + "vector": [5, -45, 0] + }, + "0.4": { + "vector": [5, -45, 0] + }, + "0.75": { + "vector": [5, -45, 0] + }, + "0.85": { + "vector": [4.64, -41.79, 0] + }, + "1.15": { + "vector": [0.2, -1.77, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.65": { + "vector": [-2.5, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.65": { + "vector": [0, 0, 0.7] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.45": { + "effect": "attack" + } + } + }, + "axe_attack": { + "animation_length": 1.25, + "override_previous_animation": true, + "bones": { + "torso": { + "rotation": { + "0.0": { + "vector": [0, 22.5, 0] + }, + "0.3": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [0, 19.42, 0] + }, + "0.8": { + "vector": [0, -15.24, 0] + }, + "1.25": { + "vector": [0, 22.5, 0] + } + } + }, + "upper_torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [0, 45, 0] + }, + "0.5": { + "vector": [0, 45, 0] + }, + "0.55": { + "vector": [0, -7.5, 0] + }, + "0.6": { + "vector": [0, 16.15, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [-15.50853, 9.3733, -19.69937] + }, + "0.5": { + "vector": [-15.50853, 9.3733, -19.69937] + }, + "0.6": { + "vector": [20.14197, 18.45386, -44.18719] + }, + "0.9": { + "vector": [21.31475, -5.36143, -32.73013] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [-67.5, 0, 0] + }, + "0.5": { + "vector": [-67.5, 0, 0] + }, + "0.6": { + "vector": [-17.31, 0, 0] + }, + "0.9": { + "vector": [-17.31, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.3": { + "vector": [-109.70372, -34.12145, 43.97409] + }, + "0.5": { + "vector": [-121.22829, -24.29511, 67.25777] + }, + "0.55": { + "vector": [-102.45958, -14.42399, 77.57976] + }, + "0.6": { + "vector": [-29.07197, -13.47349, 60.63172] + }, + "0.7": { + "vector": [37.73643, -0.99934, 60.90401] + }, + "0.8": { + "vector": [52.73643, -0.99934, 60.90401] + }, + "1.25": { + "vector": [36.94319, 29.52361, 9.71415] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [2, -1, -1] + }, + "0.5": { + "vector": [2, -1, -1] + }, + "0.6": { + "vector": [2, 0, 0] + }, + "0.7": { + "vector": [2, 0, 0] + }, + "0.8": { + "vector": [2, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "right_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "axe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [27.44634, -46.77638, 1.64566] + }, + "0.2": { + "vector": [12.8954, -72.37008, -0.60389] + }, + "0.3": { + "vector": [-1.09992, -78.07078, 2.27213] + }, + "0.5": { + "vector": [-19.66347, -69.27795, 32.98256] + }, + "0.55": { + "vector": [-26.9171, -41.80641, 26.33413] + }, + "0.6": { + "vector": [-26.9171, -41.80641, 26.33413] + }, + "0.7": { + "vector": [-4.4171, -41.80641, 26.33413] + }, + "0.75": { + "vector": [18.0829, -41.80641, 26.33413] + }, + "0.8": { + "vector": [40.32194, -42.2031, 21.34306] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.15": { + "vector": [0.8, -0.8, -2] + }, + "0.3": { + "vector": [0, 0, -1] + }, + "0.5": { + "vector": [0, 0, -1] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + }, + "0.7": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.3": { + "vector": [-2.5, 0, 0] + }, + "0.5": { + "vector": [-2.5, 0, 0] + }, + "0.55": { + "vector": [-2.5, 0, 0] + }, + "0.6": { + "vector": [-18.7289, 36.8678, 1.46479] + }, + "0.65": { + "vector": [-39.75355, 33.51618, 1.33163] + }, + "1.25": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, -1.5] + }, + "0.3": { + "vector": [0, -0.25, -1.5] + }, + "0.5": { + "vector": [0, -0.25, -1.5] + }, + "0.55": { + "vector": [0, -0.25, -1.5] + }, + "1.25": { + "vector": [0, -0.25, -1.5] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.3": { + "vector": [5, 0, 0] + }, + "0.45": { + "vector": [5, 0, 0] + }, + "0.55": { + "vector": [5, 0, 0] + }, + "0.6": { + "vector": [27.5, 0, 0] + }, + "0.65": { + "vector": [47.95, 0, 0] + }, + "1.25": { + "vector": [5, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.3": { + "vector": [-2.5, 0, 0] + }, + "0.45": { + "vector": [-21.38885, 10.86362, 32.59688] + }, + "0.55": { + "vector": [-20.35186, 1.51634, 36.30248] + }, + "0.6": { + "vector": [27.22998, 57.15097, 37.99251] + }, + "1.25": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0.5] + }, + "0.3": { + "vector": [0, -0.25, 0.5] + }, + "0.45": { + "vector": [0, -0.25, 0.5] + }, + "0.55": { + "vector": [0, -0.25, 0.5] + }, + "1.25": { + "vector": [0, -0.25, 0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.3": { + "vector": [5, 0, 0] + }, + "0.45": { + "vector": [72.5, 0, 0] + }, + "0.55": { + "vector": [72.5, 0, 0] + }, + "0.6": { + "vector": [27.5, 0, 0] + }, + "1.25": { + "vector": [5, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.3": { + "vector": [0, 72.5, 0] + }, + "0.5": { + "vector": [0, 72.5, 0] + }, + "0.55": { + "vector": [0, 45, 0] + }, + "0.6": { + "vector": [0, 22.5, 0] + }, + "0.65": { + "vector": [0, 22.92, 0] + }, + "1.25": { + "vector": [0, -22.5, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.15": { + "vector": [0, 75, 0] + }, + "0.3": { + "vector": [0, 100, 0] + }, + "0.5": { + "vector": [0, 220.04517, 0] + }, + "0.6": { + "vector": [0, 310.04517, 0] + }, + "0.65": { + "vector": [0, 310.04517, 0] + }, + "0.85": { + "vector": [0, 360, 0] + }, + "1.25": { + "vector": [0, 360, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [1, -1, 4] + }, + "0.4": { + "vector": [4.5, -1, 1] + }, + "0.45": { + "vector": [4.25, -1, -2.5] + }, + "0.5": { + "vector": [3, -1, -4] + }, + "0.55": { + "vector": [0, 0, -4] + }, + "0.65": { + "vector": [0, -4, -8] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.25": { + "effect": "axe_hit" + } + } + }, + "axe_cut": { + "animation_length": 1.35, + "bones": { + "torso": { + "rotation": { + "0.0": { + "vector": [0, 22.5, 0] + }, + "0.3": { + "vector": [-12.5, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [56.82632, 6.94314, -0.0723] + }, + "0.75": { + "vector": [56.82632, 6.94314, -0.0723] + }, + "1.25": { + "vector": [0, 22.5, 0] + } + } + }, + "upper_torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [0, 55, 0] + }, + "0.5": { + "vector": [0, 45, 0] + }, + "0.55": { + "vector": [0, 42, 0] + }, + "0.6": { + "vector": [0, -21, 0] + }, + "0.75": { + "vector": [0, -21, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "vector": [0, 0, 0] + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, 0, 0] + }, + "0.2": { + "vector": [-36.54219, -33.28982, -69.7671] + }, + "0.4": { + "vector": [-15.2553, -34.46461, -98.06686] + }, + "0.5": { + "vector": [-33.95742, -37.02514, -80.39611] + }, + "0.55": { + "vector": [-40.69539, -21.98867, -73.87325] + }, + "0.6": { + "vector": [-97.19705, 30.96904, -59.43905] + }, + "0.75": { + "vector": [-97.19705, 30.96904, -59.43905] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + }, + "0.6": { + "vector": [-34.81, 0, 0] + }, + "0.75": { + "vector": [-34.81, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.2": { + "vector": [-145.20556, -13.66588, 31.66413] + }, + "0.35": { + "vector": [-145.20556, -13.66588, 31.66413] + }, + "0.5": { + "vector": [-143.03203, -20.66768, 33.50612] + }, + "0.55": { + "vector": [-134.1591, -38.7886, 10.07665] + }, + "0.6": { + "vector": [-84.25071, -6.85667, -9.50735] + }, + "0.75": { + "vector": [-84.25071, -6.85667, -9.50735] + }, + "1.25": { + "vector": [36.94319, 29.52361, 9.71415] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2": { + "vector": [1, 3, -1] + }, + "0.5": { + "vector": [2, 3, -2] + }, + "0.6": { + "vector": [2, 0, 0] + }, + "0.7": { + "vector": [2, 0, 0] + }, + "0.8": { + "vector": [2, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "right_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [-12.5, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.2": { + "vector": [0, 0, 0] + } + } + }, + "axe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.05": { + "vector": [-17.55366, -46.77638, 1.64566] + }, + "0.15": { + "vector": [-31.37378, -33.42989, -4.98105] + }, + "0.2": { + "vector": [-44.19581, -3.0647, 48.97981] + }, + "0.35": { + "vector": [-44.12388, 1.93476, 49.08245] + }, + "0.5": { + "vector": [-46.88452, -10.32122, 51.03982] + }, + "0.55": { + "vector": [-57.65366, -23.33192, 27.23873] + }, + "0.6": { + "vector": [16.98134, -43.05147, 42.21258] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0.8, -0.8, -2] + }, + "0.2": { + "vector": [0, 0, -1] + }, + "0.5": { + "vector": [0, 0, -1] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.3": { + "vector": [-2.5, 0, 0] + }, + "0.55": { + "vector": [12.5, 0, 0] + }, + "0.6": { + "vector": [12.5, 0, 0] + }, + "0.65": { + "vector": [12.5, 0, 0] + }, + "0.7": { + "vector": [12.5, 0, 0] + }, + "0.75": { + "vector": [12.5, 0, 0] + }, + "1.25": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, -1.5] + }, + "0.3": { + "vector": [0, -0.25, -1.5] + }, + "0.6": { + "vector": [0, -0.25, -1.5] + }, + "0.65": { + "vector": [0, -0.25, -1.5] + }, + "1.25": { + "vector": [0, -0.25, -1.5] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.3": { + "vector": [5, 0, 0] + }, + "0.55": { + "vector": [15, 0, 0] + }, + "0.65": { + "vector": [15, 0, 0] + }, + "0.7": { + "vector": [15, 0, 0] + }, + "0.75": { + "vector": [15, 0, 0] + }, + "1.25": { + "vector": [5, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.15": { + "vector": [-47.5, 0, 0] + }, + "0.4": { + "vector": [-47.5, 0, 0] + }, + "0.5": { + "vector": [-27.06, 0, 0] + }, + "1.25": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0.5] + }, + "0.15": { + "vector": [0, -0.25, 0.5] + }, + "0.4": { + "vector": [0, -0.25, 0.5] + }, + "1.25": { + "vector": [0, -0.25, 0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.15": { + "vector": [27.5, 0, 0] + }, + "0.4": { + "vector": [27.5, 0, 0] + }, + "0.5": { + "vector": [17.5, 0, 0] + }, + "0.65": { + "vector": [31.03, 0, 0] + }, + "1.25": { + "vector": [5, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.3": { + "vector": [5.24771, -55.29505, 5.70142] + }, + "0.5": { + "vector": [4.24777, -45.32881, 6.99588] + }, + "0.55": { + "vector": [2.01385, -45.16677, 0.61212] + }, + "0.6": { + "vector": [-31.34904, 12.54752, 4.35778] + }, + "0.75": { + "vector": [-37.83777, 14.32159, 7.88953] + }, + "1.25": { + "vector": [0, -22.5, 0] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash10": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.4": { + "vector": [0, 0, -1] + }, + "0.5": { + "vector": [0, -2, -7] + }, + "0.55": { + "vector": [0, -2, -9.5] + }, + "0.6": { + "vector": [0, -2, -10] + }, + "0.65": { + "vector": [0, -2, -11] + }, + "0.75": { + "vector": [0, -2, -11] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.6": { + "effect": "axe_hit" + } + } + }, + "death": { + "animation_length": 10, + "bones": { + "right_heel": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-12.5, 0, 0] + }, + "0.35": { + "vector": [17.5, 0, 0] + } + } + }, + "right_foot": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-33.13773, 0.2136, -1.9553] + }, + "0.35": { + "vector": [27.10718, 0.299, -2.7374] + }, + "0.6": { + "vector": [72.10718, 0.299, -2.7374] + } + } + }, + "left_heel": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-12.5, 0, 0] + }, + "0.35": { + "vector": [17.5, 0, 0] + } + } + }, + "left_foot": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-33.13773, -0.21358, 1.95528] + }, + "0.35": { + "vector": [27.10718, -0.29901, 2.73739] + }, + "0.6": { + "vector": [72.10718, -0.29901, 2.73739] + } + } + }, + "torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-35, 0, 0] + }, + "0.35": { + "vector": [-45, 0, 0] + }, + "0.45": { + "vector": [-45, 0, 0] + }, + "0.6": { + "vector": [22.5, 0, 0] + } + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [-99.28275, -76.00637, 13.97749] + }, + "0.5": { + "vector": [-99.28275, -76.00637, 13.97749] + }, + "0.7": { + "vector": [-99.28275, -76.00637, 13.97749] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-2.5, 0, 0] + }, + "0.35": { + "vector": [12.5, 0, 0] + }, + "0.5": { + "vector": [17.5, 0, 0] + }, + "0.6": { + "vector": [17.5, 0, 0] + }, + "0.7": { + "vector": [17.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [-0.75, 0, 0] + }, + "0.5": { + "vector": [-0.75, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [-166.3778, 49.43206, -84.18841] + }, + "0.5": { + "vector": [-166.3778, 49.43206, -84.18841] + }, + "0.7": { + "vector": [-166.3778, 49.43206, -84.18841] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0] + } + } + }, + "right_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-2.5, 0, 0] + }, + "0.35": { + "vector": [12.5, 0, 0] + }, + "0.5": { + "vector": [17.5, 0, 0] + }, + "0.6": { + "vector": [17.5, 0, 0] + }, + "0.7": { + "vector": [17.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0.75, 0, 0] + }, + "0.5": { + "vector": [0.75, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + } + } + }, + "axe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [-112.2725, 1.95838, -155.96286] + }, + "0.7": { + "vector": [-111.16188, -2.34128, -158.55673] + } + }, + "position": { + "0.6": { + "vector": [0, 0, 0] + }, + "0.7": { + "vector": [2.75, -16, -4.25] + }, + "0.75": { + "vector": [4.75, -18, -6.25] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 7.5, 0] + }, + "0.6": { + "vector": [25, 7.5, 0] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [72.86, 0, 0] + }, + "0.35": { + "vector": [42.5, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, -7.5, 0] + }, + "0.6": { + "vector": [25, -7.5, 0] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [72.86, 0, 0] + }, + "0.35": { + "vector": [42.5, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.4": { + "vector": [-22.5, 0, 0] + }, + "0.6": { + "vector": [-37.5, 0, 0] + }, + "0.75": { + "vector": [-12.5, 0, 0] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-7.5, 0, 0] + }, + "0.35": { + "vector": [27.5, 0, 0] + }, + "0.45": { + "vector": [65, 0, 0] + }, + "0.7": { + "vector": [65, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -8.5, -6] + }, + "0.35": { + "vector": [0, -10, -10] + }, + "0.45": { + "vector": [0, -19, -14] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_attack": { + "scale": { + "vector": [0, 0, 0] + } + } + } + }, + "spawn": { + "animation_length": 14.35, + "override_previous_animation": true, + "bones": { + "dreadnought": { + "position": { + "0.0": { + "vector": [0, 0, 90] + }, + "0.3": { + "vector": [0, 0, 90] + }, + "0.35": { + "vector": [0, 0, 80] + }, + "2.35": { + "vector": [0, 0, 64] + }, + "10.35": { + "vector": [0, 0, 32] + }, + "14.35": { + "vector": [0, 0, 0] + } + }, + "scale": { + "0.3": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [1, 1, 1] + } + } + }, + "torso": { + "rotation": { + "0.35": { + "vector": [0, 0, 0] + }, + "9.35": { + "vector": [0, 0, 0] + }, + "10.35": { + "vector": [0, 22.5, 0] + }, + "12.35": { + "vector": [0, 22.5, 0] + }, + "14.35": { + "vector": [0, 22.5, 0] + } + }, + "position": { + "0.35": { + "vector": [-0.25, 0, 0] + }, + "0.8": { + "vector": [-0.33, 0, 0] + }, + "1.6": { + "vector": [0.25, 0, 0] + }, + "2.05": { + "vector": [0.33, 0, 0] + }, + "2.85": { + "vector": [-0.25, 0, 0] + }, + "3.3": { + "vector": [-0.33, 0, 0] + }, + "4.1": { + "vector": [0.25, 0, 0] + }, + "4.55": { + "vector": [0.33, 0, 0] + }, + "5.35": { + "vector": [-0.25, 0, 0] + }, + "5.8": { + "vector": [-0.33, 0, 0] + }, + "6.6": { + "vector": [0.25, 0, 0] + }, + "7.05": { + "vector": [0.33, 0, 0] + }, + "7.85": { + "vector": [-0.25, 0, 0] + }, + "8.3": { + "vector": [-0.33, 0, 0] + }, + "9.1": { + "vector": [0.25, 0, 0] + }, + "9.55": { + "vector": [0.33, 0, 0] + }, + "10.35": { + "vector": [-0.25, 0, 0] + }, + "10.65": { + "vector": [-0.33, 0, 0] + }, + "11.35": { + "vector": [0.25, 0, 0] + }, + "11.65": { + "vector": [0.33, 0, 0] + }, + "12.35": { + "vector": [-0.25, 0, 0] + }, + "12.65": { + "vector": [-0.33, 0, 0] + }, + "13.35": { + "vector": [0.25, 0, 0] + }, + "13.65": { + "vector": [0.33, 0, 0] + }, + "14.35": { + "vector": [0, 0, 0] + } + } + }, + "upper_torso": { + "rotation": { + "0.35": { + "vector": [0, 0, 1] + }, + "0.8": { + "vector": [0, 0, 2.5] + }, + "1.6": { + "vector": [0, 0, -1] + }, + "2.05": { + "vector": [0, 0, -2.5] + }, + "2.85": { + "vector": [0, 0, 1] + }, + "3.3": { + "vector": [0, 0, 2.5] + }, + "4.1": { + "vector": [0, 0, -1] + }, + "4.55": { + "vector": [0, 0, -2.5] + }, + "5.35": { + "vector": [0, 0, 1] + }, + "5.8": { + "vector": [0, 0, 2.5] + }, + "6.6": { + "vector": [0, 0, -1] + }, + "7.05": { + "vector": [0, 0, -2.5] + }, + "7.85": { + "vector": [0, 0, 1] + }, + "8.3": { + "vector": [0, 0, 2.5] + }, + "9.1": { + "vector": [0, 0, -1] + }, + "9.55": { + "vector": [0, 0, -2.5] + }, + "10.35": { + "vector": [0, 0, 1] + }, + "10.65": { + "vector": [0, 0, 2.5] + }, + "11.35": { + "vector": [0, 0, -1] + }, + "11.65": { + "vector": [0, 0, -2.5] + }, + "12.35": { + "vector": [0, 0, 1] + }, + "12.65": { + "vector": [0, 0, 2.5] + }, + "13.35": { + "vector": [0, 0, -1] + }, + "13.65": { + "vector": [0, 0, -2.5] + }, + "14.35": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.35": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, -0.17, 0] + }, + "0.65": { + "vector": [0, -0.83, 0] + }, + "0.8": { + "vector": [0, -1, 0] + }, + "0.95": { + "vector": [0, -0.93, 0] + }, + "1.4": { + "vector": [0, -0.07, 0] + }, + "1.6": { + "vector": [0, 0, 0] + }, + "1.75": { + "vector": [0, -0.17, 0] + }, + "1.9": { + "vector": [0, -0.83, 0] + }, + "2.05": { + "vector": [0, -1, 0] + }, + "2.2": { + "vector": [0, -0.93, 0] + }, + "2.7": { + "vector": [0, -0.07, 0] + }, + "2.85": { + "vector": [0, 0, 0] + }, + "3.0": { + "vector": [0, -0.17, 0] + }, + "3.15": { + "vector": [0, -0.83, 0] + }, + "3.3": { + "vector": [0, -1, 0] + }, + "3.45": { + "vector": [0, -0.93, 0] + }, + "3.9": { + "vector": [0, -0.07, 0] + }, + "4.1": { + "vector": [0, 0, 0] + }, + "4.25": { + "vector": [0, -0.17, 0] + }, + "4.4": { + "vector": [0, -0.83, 0] + }, + "4.55": { + "vector": [0, -1, 0] + }, + "4.7": { + "vector": [0, -0.93, 0] + }, + "5.2": { + "vector": [0, -0.07, 0] + }, + "5.35": { + "vector": [0, 0, 0] + }, + "5.5": { + "vector": [0, -0.17, 0] + }, + "5.65": { + "vector": [0, -0.83, 0] + }, + "5.8": { + "vector": [0, -1, 0] + }, + "5.95": { + "vector": [0, -0.93, 0] + }, + "6.4": { + "vector": [0, -0.07, 0] + }, + "6.6": { + "vector": [0, 0, 0] + }, + "6.75": { + "vector": [0, -0.17, 0] + }, + "6.9": { + "vector": [0, -0.83, 0] + }, + "7.05": { + "vector": [0, -1, 0] + }, + "7.2": { + "vector": [0, -0.93, 0] + }, + "7.7": { + "vector": [0, -0.07, 0] + }, + "7.85": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -0.17, 0] + }, + "8.15": { + "vector": [0, -0.83, 0] + }, + "8.3": { + "vector": [0, -1, 0] + }, + "8.45": { + "vector": [0, -0.93, 0] + }, + "8.9": { + "vector": [0, -0.07, 0] + }, + "9.1": { + "vector": [0, 0, 0] + }, + "9.25": { + "vector": [0, -0.17, 0] + }, + "9.4": { + "vector": [0, -0.83, 0] + }, + "9.55": { + "vector": [0, -1, 0] + }, + "9.7": { + "vector": [0, -0.93, 0] + }, + "10.2": { + "vector": [0, -0.07, 0] + }, + "10.35": { + "vector": [0, 0, 0] + }, + "10.45": { + "vector": [0, -0.17, 0] + }, + "10.55": { + "vector": [0, -0.83, 0] + }, + "10.65": { + "vector": [0, -1, 0] + }, + "10.8": { + "vector": [0, -0.93, 0] + }, + "11.2": { + "vector": [0, -0.07, 0] + }, + "11.35": { + "vector": [0, 0, 0] + }, + "11.45": { + "vector": [0, -0.17, 0] + }, + "11.55": { + "vector": [0, -0.83, 0] + }, + "11.65": { + "vector": [0, -1, 0] + }, + "11.8": { + "vector": [0, -0.93, 0] + }, + "12.2": { + "vector": [0, -0.07, 0] + }, + "12.35": { + "vector": [0, 0, 0] + }, + "12.45": { + "vector": [0, -0.17, 0] + }, + "12.55": { + "vector": [0, -0.83, 0] + }, + "12.65": { + "vector": [0, -1, 0] + }, + "12.8": { + "vector": [0, -0.93, 0] + }, + "13.2": { + "vector": [0, -0.07, 0] + }, + "13.35": { + "vector": [0, 0, 0] + }, + "13.45": { + "vector": [0, -0.17, 0] + }, + "13.55": { + "vector": [0, -0.83, 0] + }, + "13.65": { + "vector": [0, -1, 0] + }, + "13.8": { + "vector": [0, -0.93, 0] + }, + "14.2": { + "vector": [0, -0.07, 0] + }, + "14.35": { + "vector": [0, 0, 0] + } + } + }, + "left_arm": { + "rotation": { + "0.35": { + "vector": [-65.3438, 2.97085, -54.00316] + }, + "1.35": { + "vector": [-65.3438, 2.97085, -54.00316] + }, + "2.1": { + "vector": [-19.29063, 7.22373, -42.19927] + }, + "2.6": { + "vector": [13.14, 0.83582, -11.7567] + }, + "3.45": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "5.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "6.6": { + "vector": [12.5, 0, 0] + }, + "7.4": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "7.85": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "9.1": { + "vector": [12.5, 0, 0] + }, + "9.9": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "10.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "14.35": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.35": { + "vector": [12.68664, -9.76061, -2.18558] + }, + "2.85": { + "vector": [12.68664, -9.76061, -2.18558] + }, + "3.55": { + "vector": [-10.15108, -9.84655, 1.75378] + }, + "4.1": { + "vector": [-10.08648, -8.98092, 6.66735] + }, + "5.35": { + "vector": [12.68664, -9.76061, -2.18558] + }, + "6.05": { + "vector": [-10.15108, -9.84655, 1.75378] + }, + "6.6": { + "vector": [-10.08648, -8.98092, 6.66735] + }, + "7.85": { + "vector": [12.68664, -9.76061, -2.18558] + }, + "8.2": { + "vector": [37.68664, -9.76061, -2.18558] + }, + "8.35": { + "vector": [20.18664, -9.76061, -2.18558] + }, + "9.35": { + "vector": [25.0691, 18.40276, 1.7084] + }, + "10.35": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "10.65": { + "vector": [37.94, 29.52, 9.71] + }, + "11.35": { + "vector": [37.1047, 28.17926, 12.12078] + }, + "11.65": { + "vector": [36.1047, 28.17926, 12.12078] + }, + "12.35": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "12.65": { + "vector": [37.94, 29.52, 9.71] + }, + "13.35": { + "vector": [37.1047, 28.17926, 12.12078] + }, + "13.65": { + "vector": [36.1047, 28.17926, 12.12078] + }, + "14.35": { + "vector": [36.94319, 29.52361, 9.71415] + } + }, + "position": { + "7.85": { + "vector": [0, 0, 0] + }, + "8.2": { + "vector": [0, 1, 1] + }, + "8.35": { + "vector": [-1, -1, -1] + }, + "9.35": { + "vector": [0, 0, 0] + }, + "10.35": { + "vector": [0, 0, 0] + }, + "10.45": { + "vector": [0, 0.17, 0] + }, + "10.55": { + "vector": [0, 0.83, 0] + }, + "10.65": { + "vector": [0, 1, 0] + }, + "10.8": { + "vector": [0, 0.93, 0] + }, + "11.2": { + "vector": [0, 0.07, 0] + }, + "11.35": { + "vector": [0, 0, 0] + }, + "11.45": { + "vector": [0, 0.17, 0] + }, + "11.55": { + "vector": [0, 0.83, 0] + }, + "11.65": { + "vector": [0, 1, 0] + }, + "11.8": { + "vector": [0, 0.93, 0] + }, + "12.2": { + "vector": [0, 0.07, 0] + }, + "12.35": { + "vector": [0, 0, 0] + }, + "12.45": { + "vector": [0, 0.17, 0] + }, + "12.55": { + "vector": [0, 0.83, 0] + }, + "12.65": { + "vector": [0, 1, 0] + }, + "12.8": { + "vector": [0, 0.93, 0] + }, + "13.2": { + "vector": [0, 0.07, 0] + }, + "13.35": { + "vector": [0, 0, 0] + }, + "13.45": { + "vector": [0, 0.17, 0] + }, + "13.55": { + "vector": [0, 0.83, 0] + }, + "13.65": { + "vector": [0, 1, 0] + }, + "13.8": { + "vector": [0, 0.93, 0] + }, + "14.2": { + "vector": [0, 0.07, 0] + }, + "14.35": { + "vector": [0, 0, 0] + } + } + }, + "right_elbow": { + "rotation": { + "0.35": { + "vector": [22.5, 0, 0] + }, + "2.85": { + "vector": [22.5, 0, 0] + }, + "5.35": { + "vector": [22.5, 0, 0] + }, + "7.85": { + "vector": [22.5, 0, 0] + }, + "8.1": { + "vector": [-2.5, 0, 0] + }, + "8.25": { + "vector": [-2.5, 0, 0] + }, + "8.4": { + "vector": [2.5, 0, 0] + }, + "9.35": { + "vector": [22.5, 0, 0] + }, + "10.35": { + "vector": [0, 0, 0] + } + } + }, + "axe": { + "rotation": { + "8.4": { + "vector": [-17.76543, -17.59014, -11.04134] + }, + "8.45": { + "vector": [-17.76543, -17.59014, -11.04134] + }, + "8.85": { + "vector": [-17.76543, -17.59014, -11.04134] + }, + "9.35": { + "vector": [-26.84362, -11.72676, -7.36089] + }, + "10.35": { + "vector": [0, 0, 0] + } + }, + "position": { + "8.35": { + "vector": [0.75, 3, 3] + }, + "8.4": { + "vector": [0.75, 3, 3] + }, + "8.45": { + "vector": [0.75, 3, 3] + }, + "8.85": { + "vector": [0.75, 3, 3] + }, + "10.35": { + "vector": [0, 0, 0] + } + }, + "scale": { + "8.35": { + "vector": [0, 0, 0] + }, + "8.4": { + "vector": [1, 1, 1] + } + } + }, + "left_leg": { + "rotation": { + "0.35": { + "vector": [5, 0, 0] + }, + "1.05": { + "vector": [-10, 0, 0] + }, + "1.6": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "2.85": { + "vector": [5, 0, 0] + }, + "3.55": { + "vector": [-10, 0, 0] + }, + "4.1": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "5.35": { + "vector": [5, 0, 0] + }, + "6.05": { + "vector": [-10, 0, 0] + }, + "6.6": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "7.85": { + "vector": [5, 0, 0] + }, + "8.55": { + "vector": [-10, 0, 0] + }, + "9.1": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "10.35": { + "vector": [12.5, 0, 0] + }, + "10.9": { + "vector": [-10, 0, 0] + }, + "11.35": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "12.35": { + "vector": [12.5, 0, 0] + }, + "12.9": { + "vector": [-10, 0, 0] + }, + "13.35": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "14.35": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.35": { + "vector": [0, -0.5, -1] + }, + "1.05": { + "vector": [0, 0, -2] + }, + "1.6": { + "vector": [0, -1, -2.5] + }, + "2.85": { + "vector": [0, -0.5, -1] + }, + "3.55": { + "vector": [0, 0, -2] + }, + "4.1": { + "vector": [0, -1, -2.5] + }, + "5.35": { + "vector": [0, -0.5, -1] + }, + "6.05": { + "vector": [0, 0, -2] + }, + "6.6": { + "vector": [0, -1, -2.5] + }, + "7.85": { + "vector": [0, -0.5, -1] + }, + "8.55": { + "vector": [0, 0, -2] + }, + "9.1": { + "vector": [0, -1, -2.5] + }, + "10.35": { + "vector": [0, -0.5, -1] + }, + "10.5": { + "vector": [0, 1, -2] + }, + "10.9": { + "vector": [0, 1, -2] + }, + "11.35": { + "vector": [0, -1, -2.5] + }, + "12.35": { + "vector": [0, -0.5, -1] + }, + "12.5": { + "vector": [0, 1, -2] + }, + "12.9": { + "vector": [0, 1, -2] + }, + "13.35": { + "vector": [0, -1, -2.5] + }, + "14.35": { + "vector": [0, -0.25, -1.5] + } + } + }, + "left_knee": { + "rotation": { + "0.35": { + "vector": [0, 0, 0] + }, + "0.8": { + "vector": [32.5, 0, 0] + }, + "1.6": { + "vector": [5, 0, 0] + }, + "2.85": { + "vector": [0, 0, 0] + }, + "3.3": { + "vector": [32.5, 0, 0] + }, + "4.1": { + "vector": [5, 0, 0] + }, + "5.35": { + "vector": [0, 0, 0] + }, + "5.8": { + "vector": [32.5, 0, 0] + }, + "6.6": { + "vector": [5, 0, 0] + }, + "7.85": { + "vector": [0, 0, 0] + }, + "8.3": { + "vector": [32.5, 0, 0] + }, + "9.1": { + "vector": [5, 0, 0] + }, + "10.35": { + "vector": [0, 0, 0] + }, + "10.65": { + "vector": [32.5, 0, 0] + }, + "11.35": { + "vector": [5, 0, 0] + }, + "12.35": { + "vector": [0, 0, 0] + }, + "12.65": { + "vector": [32.5, 0, 0] + }, + "13.35": { + "vector": [5, 0, 0] + }, + "14.35": { + "vector": [5, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "1.6": { + "vector": [5, 0, 0] + }, + "2.4": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "2.85": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "4.1": { + "vector": [5, 0, 0] + }, + "4.9": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "5.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "6.6": { + "vector": [5, 0, 0] + }, + "7.4": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "7.85": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "9.1": { + "vector": [5, 0, 0] + }, + "9.9": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "10.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "11.35": { + "vector": [12.5, 0, 0] + }, + "11.9": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "12.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "13.35": { + "vector": [12.5, 0, 0] + }, + "13.9": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "14.35": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.35": { + "vector": [0, -1, -0.5] + }, + "1.6": { + "vector": [0, -0.5, 1] + }, + "2.4": { + "vector": [0, 0, 0] + }, + "2.85": { + "vector": [0, -1, -0.5] + }, + "4.1": { + "vector": [0, -0.5, 1] + }, + "4.9": { + "vector": [0, 0, 0] + }, + "5.35": { + "vector": [0, -1, -0.5] + }, + "6.6": { + "vector": [0, -0.5, 1] + }, + "7.4": { + "vector": [0, 0, 0] + }, + "7.85": { + "vector": [0, -1, -0.5] + }, + "9.1": { + "vector": [0, -0.5, 1] + }, + "9.9": { + "vector": [0, 0, 0] + }, + "10.35": { + "vector": [0, -1, -0.5] + }, + "11.35": { + "vector": [0, -0.5, 1] + }, + "11.5": { + "vector": [0, 1, 0] + }, + "11.9": { + "vector": [0, 1, 0] + }, + "12.35": { + "vector": [0, -1, -0.5] + }, + "13.35": { + "vector": [0, -0.5, 1] + }, + "13.5": { + "vector": [0, 1, 0] + }, + "13.9": { + "vector": [0, 1, 0] + }, + "14.35": { + "vector": [0, -0.25, 0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.35": { + "vector": [5, 0, 0] + }, + "1.6": { + "vector": [0, 0, 0] + }, + "2.05": { + "vector": [32.5, 0, 0] + }, + "2.85": { + "vector": [5, 0, 0] + }, + "4.1": { + "vector": [0, 0, 0] + }, + "4.55": { + "vector": [32.5, 0, 0] + }, + "5.35": { + "vector": [5, 0, 0] + }, + "6.6": { + "vector": [0, 0, 0] + }, + "7.05": { + "vector": [32.5, 0, 0] + }, + "7.85": { + "vector": [5, 0, 0] + }, + "9.1": { + "vector": [0, 0, 0] + }, + "9.55": { + "vector": [32.5, 0, 0] + }, + "10.35": { + "vector": [5, 0, 0] + }, + "11.35": { + "vector": [0, 0, 0] + }, + "11.65": { + "vector": [32.5, 0, 0] + }, + "12.35": { + "vector": [5, 0, 0] + }, + "13.35": { + "vector": [0, 0, 0] + }, + "13.65": { + "vector": [32.5, 0, 0] + }, + "14.35": { + "vector": [5, 0, 0] + } + } + }, + "inactive_axe": { + "rotation": { + "0.35": { + "vector": [2.51565, -47.38422, -0.7522] + }, + "2.85": { + "vector": [-32.48435, -47.38422, -0.7522] + }, + "3.55": { + "vector": [-17.48435, -47.38422, -0.7522] + }, + "4.1": { + "vector": [-19.98435, -47.38422, -0.7522] + }, + "5.35": { + "vector": [-32.48435, -47.38422, -0.7522] + }, + "6.05": { + "vector": [-17.48435, -47.38422, -0.7522] + }, + "6.6": { + "vector": [-19.98435, -47.38422, -0.7522] + }, + "7.85": { + "vector": [-17.76543, -17.59014, -11.04134] + }, + "8.15": { + "vector": [-17.76543, -17.59014, -11.04134] + }, + "8.35": { + "vector": [-17.76543, -17.59014, -11.04134] + } + }, + "position": { + "0.35": { + "vector": [0, 7, 7] + }, + "2.85": { + "vector": [0, 1, 4] + }, + "3.55": { + "vector": [0, 2, 4] + }, + "4.1": { + "vector": [0, 1, 4] + }, + "5.35": { + "vector": [0, 1, 4] + }, + "6.05": { + "vector": [-1, 2.75, 4] + }, + "6.6": { + "vector": [-1, 2, 4] + }, + "7.85": { + "vector": [0.75, 3, 3] + }, + "8.15": { + "vector": [0.75, 3, 3] + }, + "8.35": { + "vector": [0.75, 3, 3] + }, + "8.4": { + "vector": [0, -3200, 4] + } + }, + "scale": { + "0.0": { + "vector": [1, 1, 1] + }, + "8.35": { + "vector": [1, 1, 1] + }, + "8.45": { + "vector": [0, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.35": { + "vector": [0, 0, -1] + }, + "0.8": { + "vector": [15, 0, 1] + }, + "1.6": { + "vector": [15, 0, 1] + }, + "2.85": { + "vector": [0, 0, -1] + }, + "3.3": { + "vector": [0, 0, -2.5] + }, + "4.1": { + "vector": [0, 0, 1] + }, + "4.55": { + "vector": [0, 0, 2.5] + }, + "5.35": { + "vector": [0, 0, -1] + }, + "5.8": { + "vector": [0, 0, -2.5] + }, + "6.6": { + "vector": [0, 0, 1] + }, + "7.05": { + "vector": [0, 0, 2.5] + }, + "7.85": { + "vector": [0, 0, -1] + }, + "8.3": { + "vector": [0, 0, -2.5] + }, + "9.1": { + "vector": [0, 0, 1] + }, + "9.55": { + "vector": [0, 0, 2.5] + }, + "10.35": { + "vector": [0, -22.5, -1] + }, + "10.65": { + "vector": [0, -22.5, -2.5] + }, + "11.35": { + "vector": [0, -22.5, 1] + }, + "11.65": { + "vector": [0, -22.5, 2.5] + }, + "12.35": { + "vector": [0, -22.5, -1] + }, + "12.65": { + "vector": [0, -22.5, -2.5] + }, + "13.35": { + "vector": [0, -22.5, 1] + }, + "13.65": { + "vector": [0, -22.5, 2.5] + }, + "14.35": { + "vector": [0, -22.5, 0] + } + }, + "position": { + "0.35": { + "vector": [0, 0, 0] + }, + "1.35": { + "vector": [0, 0, -2] + }, + "1.75": { + "vector": [0, 0, -2] + }, + "2.05": { + "vector": [0, 0, 0] + }, + "14.35": { + "vector": [0, 0, 0] + } + } + }, + "hand_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "position": { + "vector": [0, 0, 0] + } + }, + "dreadnought_portal": { + "position": { + "0.0": { + "vector": [0, 0, 69] + }, + "7.85": { + "vector": [0, 0, 69] + }, + "8.0": { + "vector": [0, 25, 69] + } + }, + "scale": { + "7.85": { + "vector": [1, 1, 1] + }, + "8.1": { + "vector": [0, 0, 0] + } + } + }, + "black": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cluster1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud5": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud6": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud7": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud8": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud9": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud10": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud11": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud12": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud13": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud14": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud15": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud16": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud17": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud18": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster5": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud19": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud20": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud21": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud22": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster6": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud23": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud24": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud25": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud26": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud27": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster7": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud28": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud29": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud30": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud31": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster8": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud32": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud33": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud34": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud35": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud36": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster9": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud37": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud38": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud39": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud40": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster10": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud41": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud42": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud43": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud44": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud45": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster11": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud46": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud47": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud48": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud49": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster12": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud50": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud51": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud52": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud53": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud54": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster13": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud55": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud56": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud57": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud58": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster14": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud59": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud60": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud61": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud62": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud63": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster15": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud64": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud65": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud66": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud67": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster16": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud68": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud69": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud70": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud71": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud72": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster17": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud73": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud74": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud75": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud76": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster18": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud77": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud78": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud79": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud80": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud81": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster19": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud82": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud83": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud84": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud85": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster20": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud86": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud87": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud88": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud89": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud90": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster21": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud91": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud92": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud93": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud94": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster22": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud95": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud96": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud97": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud98": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud99": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster23": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud100": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud101": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud102": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud103": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster24": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud104": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud105": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud106": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud107": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud108": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster25": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud109": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud110": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud111": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud112": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster26": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud113": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud114": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud115": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud116": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud117": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster27": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud118": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud119": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud120": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud121": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster28": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud122": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud123": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud124": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud125": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud126": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster29": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud127": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud128": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud129": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud130": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster30": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud131": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud132": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud133": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud134": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud135": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster31": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud136": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud137": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud138": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud139": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster32": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud140": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud141": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud142": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud143": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud144": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "eyes_attack": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.0": { + "effect": "portal" + }, + "0.35": { + "effect": "walk" + }, + "1.7": { + "effect": "walk" + }, + "2.85": { + "effect": "walk" + }, + "4.05": { + "effect": "walk" + }, + "4.3": { + "effect": "portal" + }, + "5.25": { + "effect": "walk" + }, + "6.5": { + "effect": "walk" + }, + "7.85": { + "effect": "walk" + }, + "8.35": { + "effect": "axe" + }, + "9.05": { + "effect": "walk" + }, + "10.3": { + "effect": "walk" + }, + "11.2": { + "effect": "walk" + }, + "12.25": { + "effect": "walk" + }, + "13.25": { + "effect": "walk" + }, + "14.0": { + "effect": "walk" + } + } + } + }, + "azurelib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/entity/marauder.geo.json b/common/src/main/resources/assets/azurelib/geo/entity/marauder.geo.json new file mode 100644 index 000000000..2cd28b0b0 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/entity/marauder.geo.json @@ -0,0 +1,4168 @@ +{ + "format_version": "1.21.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 512, + "texture_height": 128, + "visible_bounds_width": 14, + "visible_bounds_height": 8, + "visible_bounds_offset": [0, 2, 0] + }, + "bones": [ + { + "name": "dreadnought", + "pivot": [0, 0, 0] + }, + { + "name": "body2", + "parent": "dreadnought", + "pivot": [0, 21, 0] + }, + { + "name": "torso", + "parent": "body2", + "pivot": [0, 21, 0], + "cubes": [ + { + "origin": [-4, 19, -2], + "size": [8, 7, 4], + "uv": { + "north": {"uv": [411, 18], "uv_size": [8, 7]}, + "east": {"uv": [384, 55], "uv_size": [4, 7]}, + "south": {"uv": [411, 25], "uv_size": [8, 7]}, + "west": {"uv": [423, 55], "uv_size": [4, 7]}, + "up": {"uv": [438, 27], "uv_size": [8, 4]}, + "down": {"uv": [439, 49], "uv_size": [8, -4]} + } + }, + { + "origin": [-4, 22.25, -2], + "size": [8, 2, 4], + "inflate": 0.25, + "uv": { + "north": {"uv": [451, 33], "uv_size": [8, 2]}, + "east": {"uv": [456, 45], "uv_size": [4, 2]}, + "south": {"uv": [451, 43], "uv_size": [8, 2]}, + "west": {"uv": [456, 47], "uv_size": [4, 2]} + } + } + ] + }, + { + "name": "upper_torso", + "parent": "torso", + "pivot": [0, 25, 0], + "cubes": [ + { + "origin": [-5.5, 25, -2.5], + "size": [11, 9, 5], + "uv": { + "north": {"uv": [403, 0], "uv_size": [11, 9]}, + "east": {"uv": [423, 35], "uv_size": [5, 9]}, + "south": {"uv": [403, 9], "uv_size": [11, 9]}, + "west": {"uv": [425, 0], "uv_size": [5, 9]}, + "up": {"uv": [414, 0], "uv_size": [11, 5]}, + "down": {"uv": [414, 10], "uv_size": [11, -5]} + } + }, + { + "origin": [-2, 34, -2], + "size": [4, 2, 4], + "uv": { + "north": {"uv": [430, 7], "uv_size": [4, 2]}, + "east": {"uv": [446, 29], "uv_size": [4, 2]}, + "south": {"uv": [457, 25], "uv_size": [4, 2]}, + "west": {"uv": [457, 27], "uv_size": [4, 2]}, + "up": {"uv": [449, 9], "uv_size": [4, 4]}, + "down": {"uv": [395, 69], "uv_size": [4, -4]} + } + }, + { + "origin": [0, 27, -2.75], + "size": [6, 7, 5.5], + "inflate": 0.01, + "pivot": [3, 30, 0], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [428, 9], "uv_size": [6, 7]}, + "east": {"uv": [430, 0], "uv_size": [6, 7]}, + "south": {"uv": [427, 46], "uv_size": [6, 7]}, + "west": {"uv": [431, 16], "uv_size": [6, 7]}, + "up": {"uv": [433, 41], "uv_size": [6, 6]}, + "down": {"uv": [433, 53], "uv_size": [6, -6]} + } + }, + { + "origin": [1.75, 29, -2.85], + "size": [3, 3, 0], + "inflate": 0.01, + "uv": { + "north": {"uv": [387, 79], "uv_size": [-3, 3]}, + "east": {"uv": [430, 0], "uv_size": [6, 7]}, + "south": {"uv": [384, 79], "uv_size": [3, 3]}, + "west": {"uv": [431, 16], "uv_size": [6, 7]}, + "up": {"uv": [433, 41], "uv_size": [6, 6]}, + "down": {"uv": [433, 53], "uv_size": [6, -6]} + } + }, + { + "origin": [-6.77164, 29.14805, -2.75], + "size": [7, 2, 0], + "pivot": [0.22836, 31.14805, -2.75], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [438, 29], "uv_size": [-7, 2]}, + "east": {"uv": [384, 0], "uv_size": [0, 2]}, + "south": {"uv": [431, 29], "uv_size": [7, 2]}, + "west": {"uv": [384, 0], "uv_size": [0, 2]}, + "up": {"uv": [384, 0], "uv_size": [7, 0]}, + "down": {"uv": [384, 0], "uv_size": [7, 0]} + } + }, + { + "origin": [-3.39104, 29.23463, -3], + "size": [2, 4, 6], + "pivot": [-4.39104, 29.23463, -2.75], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [393, 72], "uv_size": [2, 4]}, + "east": {"uv": [395, 61], "uv_size": [6, 4]}, + "south": {"uv": [410, 72], "uv_size": [2, 4]}, + "west": {"uv": [445, 31], "uv_size": [6, 4]}, + "up": {"uv": [436, 0], "uv_size": [2, 6]}, + "down": {"uv": [410, 68], "uv_size": [2, -6]} + } + }, + { + "origin": [-3.89104, 31.73463, -2.75], + "size": [3, 3, 5.5], + "pivot": [-4.39104, 29.23463, -2.75], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [455, 49], "uv_size": [3, 3]}, + "east": {"uv": [447, 54], "uv_size": [6, 3]}, + "south": {"uv": [456, 13], "uv_size": [3, 3]}, + "west": {"uv": [448, 0], "uv_size": [6, 3]}, + "up": {"uv": [396, 50], "uv_size": [3, 6]}, + "down": {"uv": [449, 9], "uv_size": [3, -6]} + } + } + ] + }, + { + "name": "h_head_furious", + "parent": "upper_torso", + "pivot": [0, 35, 0], + "cubes": [ + { + "origin": [-3.5, 34.5, -4], + "size": [7, 4, 4], + "inflate": 0.25, + "pivot": [0, 37.5, -2], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [442, 5], "uv_size": [7, 4]}, + "east": {"uv": [449, 13], "uv_size": [4, 4]}, + "south": {"uv": [442, 9], "uv_size": [7, 4]}, + "west": {"uv": [449, 17], "uv_size": [4, 4]}, + "up": {"uv": [442, 13], "uv_size": [7, 4]}, + "down": {"uv": [442, 21], "uv_size": [7, -4]} + } + }, + { + "origin": [-3.5, 35, -3.5], + "size": [7, 7, 7], + "uv": { + "north": {"uv": [414, 10], "uv_size": [7, 7]}, + "east": {"uv": [389, 34], "uv_size": [7, 7]}, + "south": {"uv": [396, 34], "uv_size": [7, 7]}, + "west": {"uv": [419, 17], "uv_size": [7, 7]}, + "up": {"uv": [419, 24], "uv_size": [7, 7]}, + "down": {"uv": [421, 17], "uv_size": [7, -7]} + } + }, + { + "origin": [-0.1, 39.75, -5.25], + "size": [0.1, 2, 2], + "pivot": [0, 40, -3.5], + "rotation": [-45, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 2]}, + "east": {"uv": [446, 72], "uv_size": [-2, 2]}, + "south": {"uv": [384, 0], "uv_size": [0, 2]}, + "west": {"uv": [444, 72], "uv_size": [2, 2]}, + "up": {"uv": [384, 0], "uv_size": [0, 2]}, + "down": {"uv": [384, 2], "uv_size": [0, -2]} + } + }, + { + "origin": [-0.1, 42, -2.5], + "size": [0.1, 2, 2], + "pivot": [0, 42, -2.5], + "rotation": [-45, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 2]}, + "east": {"uv": [448, 72], "uv_size": [-2, 2]}, + "south": {"uv": [384, 0], "uv_size": [0, 2]}, + "west": {"uv": [446, 72], "uv_size": [2, 2]}, + "up": {"uv": [384, 0], "uv_size": [0, 2]}, + "down": {"uv": [384, 2], "uv_size": [0, -2]} + } + }, + { + "origin": [3.5, 38.5, -7.5], + "size": [3, 0.1, 11], + "pivot": [3.5, 38.501, 0.5], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [3, 0]}, + "east": {"uv": [384, 0], "uv_size": [9, 0]}, + "south": {"uv": [384, 0], "uv_size": [3, 0]}, + "west": {"uv": [384, 0], "uv_size": [9, 0]}, + "up": {"uv": [509, 0], "uv_size": [3, 11]}, + "down": {"uv": [509, 11], "uv_size": [3, -11]} + } + }, + { + "origin": [-6.5, 38.5, -7.5], + "size": [3, 0.1, 11], + "pivot": [-3.5, 38.501, 0.5], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [387, 0], "uv_size": [-3, 0]}, + "east": {"uv": [393, 0], "uv_size": [-9, 0]}, + "south": {"uv": [387, 0], "uv_size": [-3, 0]}, + "west": {"uv": [393, 0], "uv_size": [-9, 0]}, + "up": {"uv": [512, 0], "uv_size": [-3, 11]}, + "down": {"uv": [512, 11], "uv_size": [-3, -11]} + } + }, + { + "origin": [0, 34.25, -5.32843], + "size": [4, 4, 3], + "pivot": [0, 38.25, -5.32843], + "rotation": [0, -22.5, 0], + "uv": { + "north": {"uv": [423, 65], "uv_size": [4, 4]}, + "east": {"uv": [453, 25], "uv_size": [3, 4]}, + "south": {"uv": [449, 57], "uv_size": [4, 4]}, + "west": {"uv": [451, 69], "uv_size": [3, 4]}, + "up": {"uv": [454, 0], "uv_size": [4, 3]}, + "down": {"uv": [454, 38], "uv_size": [4, -3]} + } + }, + { + "origin": [-4, 34.25, -5.32843], + "size": [4, 4, 3], + "pivot": [0, 38.25, -5.32843], + "rotation": [0, 22.5, 0], + "uv": { + "north": {"uv": [427, 65], "uv_size": [-4, 4]}, + "east": {"uv": [454, 69], "uv_size": [-3, 4]}, + "south": {"uv": [453, 57], "uv_size": [-4, 4]}, + "west": {"uv": [456, 25], "uv_size": [-3, 4]}, + "up": {"uv": [458, 0], "uv_size": [-4, 3]}, + "down": {"uv": [458, 38], "uv_size": [-4, -3]} + } + } + ] + }, + { + "name": "eyes_attack", + "parent": "h_head_furious", + "pivot": [-2.9, 38.25, -3.6], + "cubes": [ + { + "origin": [-3.4, 38.25, -3.6], + "size": [2.5, 2, 0.1], + "pivot": [-2.9, 38.25, -3.6], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [454, 12], "uv_size": [-1, 2]}, + "east": {"uv": [426, 17], "uv_size": [-7, 7]}, + "south": {"uv": [454, 12], "uv_size": [-1, 2]}, + "west": {"uv": [396, 34], "uv_size": [-7, 7]}, + "up": {"uv": [426, 24], "uv_size": [-7, 7]}, + "down": {"uv": [428, 17], "uv_size": [-7, -7]} + } + }, + { + "origin": [0.9, 38.25, -3.6], + "size": [2.5, 2, 0.1], + "pivot": [2.9, 38.25, -3.6], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [453, 12], "uv_size": [1, 2]}, + "east": {"uv": [389, 34], "uv_size": [7, 7]}, + "south": {"uv": [453, 12], "uv_size": [1, 2]}, + "west": {"uv": [419, 17], "uv_size": [7, 7]}, + "up": {"uv": [419, 24], "uv_size": [7, 7]}, + "down": {"uv": [421, 17], "uv_size": [7, -7]} + } + }, + { + "origin": [1.4, 38.25, -3.8], + "size": [1, 1, 0.1], + "uv": { + "north": {"uv": [451, 126], "uv_size": [1, 2]}, + "east": {"uv": [389, 34], "uv_size": [7, 7]}, + "south": {"uv": [393, 15], "uv_size": [1, 2]}, + "west": {"uv": [419, 17], "uv_size": [7, 7]}, + "up": {"uv": [419, 24], "uv_size": [7, 7]}, + "down": {"uv": [421, 17], "uv_size": [7, -7]} + } + }, + { + "origin": [-2.4, 38.25, -3.8], + "size": [1, 1, 0.1], + "uv": { + "north": {"uv": [452, 126], "uv_size": [-1, 2]}, + "east": {"uv": [426, 17], "uv_size": [-7, 7]}, + "south": {"uv": [394, 15], "uv_size": [-1, 2]}, + "west": {"uv": [396, 34], "uv_size": [-7, 7]}, + "up": {"uv": [426, 24], "uv_size": [-7, 7]}, + "down": {"uv": [428, 17], "uv_size": [-7, -7]} + } + } + ] + }, + { + "name": "eyes_normal", + "parent": "h_head_furious", + "pivot": [-2.9, 38.25, -3.6], + "cubes": [ + { + "origin": [-3.4, 38.25, -3.6], + "size": [2.5, 2, 0.1], + "pivot": [-2.9, 38.25, -3.6], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [456, 13], "uv_size": [-2, 2]}, + "east": {"uv": [426, 17], "uv_size": [-7, 7]}, + "south": {"uv": [456, 13], "uv_size": [-2, 2]}, + "west": {"uv": [396, 34], "uv_size": [-7, 7]}, + "up": {"uv": [426, 24], "uv_size": [-7, 7]}, + "down": {"uv": [428, 17], "uv_size": [-7, -7]} + } + }, + { + "origin": [0.9, 38.25, -3.6], + "size": [2.5, 2, 0.1], + "pivot": [2.9, 38.25, -3.6], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [456, 13], "uv_size": [-2, 2]}, + "east": {"uv": [389, 34], "uv_size": [7, 7]}, + "south": {"uv": [456, 13], "uv_size": [-2, 2]}, + "west": {"uv": [419, 17], "uv_size": [7, 7]}, + "up": {"uv": [419, 24], "uv_size": [7, 7]}, + "down": {"uv": [421, 17], "uv_size": [7, -7]} + } + }, + { + "origin": [-2.4, 38.25, -3.8], + "size": [1, 1, 0.1], + "uv": { + "north": {"uv": [454, 12], "uv_size": [-1, 2]}, + "east": {"uv": [454, 12], "uv_size": [-1, 2]}, + "south": {"uv": [454, 12], "uv_size": [-1, 2]}, + "west": {"uv": [454, 12], "uv_size": [-1, 2]}, + "up": {"uv": [453, 14], "uv_size": [1, -2]}, + "down": {"uv": [428, 17], "uv_size": [-7, -7]} + } + }, + { + "origin": [1.4, 38.25, -3.8], + "size": [1, 1, 0.1], + "uv": { + "north": {"uv": [454, 12], "uv_size": [-1, 2]}, + "east": {"uv": [454, 12], "uv_size": [-1, 2]}, + "south": {"uv": [454, 12], "uv_size": [-1, 2]}, + "west": {"uv": [454, 12], "uv_size": [-1, 2]}, + "up": {"uv": [453, 14], "uv_size": [1, -2]}, + "down": {"uv": [421, 17], "uv_size": [7, -7]} + } + } + ] + }, + { + "name": "h_left_horn_furious", + "parent": "h_head_furious", + "pivot": [0, 40.5, 0], + "rotation": [60, -15, -15], + "cubes": [ + { + "origin": [1.5, 41, -3], + "size": [3, 5, 3], + "pivot": [2.5, 42.5, -1.5], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [427, 65], "uv_size": [3, 5]}, + "east": {"uv": [388, 68], "uv_size": [3, 5]}, + "south": {"uv": [453, 7], "uv_size": [3, 5]}, + "west": {"uv": [395, 69], "uv_size": [3, 5]}, + "up": {"uv": [398, 72], "uv_size": [3, 3]}, + "down": {"uv": [401, 75], "uv_size": [3, -3]} + } + }, + { + "origin": [3.18715, 44.96821, -2.5], + "size": [2, 5, 2], + "pivot": [5.68715, 44.96821, -3], + "rotation": [-22.5, 0, 0], + "uv": { + "north": {"uv": [455, 38], "uv_size": [2, 5]}, + "east": {"uv": [440, 71], "uv_size": [2, 5]}, + "south": {"uv": [442, 71], "uv_size": [2, 5]}, + "west": {"uv": [384, 72], "uv_size": [2, 5]}, + "up": {"uv": [456, 64], "uv_size": [2, 2]}, + "down": {"uv": [456, 68], "uv_size": [2, -2]} + } + }, + { + "origin": [4.08715, 47.39627, -0.62464], + "size": [0.1, 2, 5], + "pivot": [4.18715, 49.39627, -0.62464], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 5]}, + "east": {"uv": [394, 79], "uv_size": [-5, -2], "uv_rotation": 90}, + "south": {"uv": [384, 0], "uv_size": [0, 5]}, + "west": {"uv": [389, 79], "uv_size": [5, -2], "uv_rotation": 90}, + "up": {"uv": [384, 0], "uv_size": [0, 2]}, + "down": {"uv": [384, 2], "uv_size": [0, -2]} + } + } + ] + }, + { + "name": "h_right_horn_furious", + "parent": "h_head_furious", + "pivot": [0, 40.5, 0], + "rotation": [60, 15, 15], + "cubes": [ + { + "origin": [-4.5, 41, -3], + "size": [3, 5, 3], + "pivot": [-2.5, 42.5, -1.5], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [430, 65], "uv_size": [-3, 5]}, + "east": {"uv": [398, 69], "uv_size": [-3, 5]}, + "south": {"uv": [456, 7], "uv_size": [-3, 5]}, + "west": {"uv": [391, 68], "uv_size": [-3, 5]}, + "up": {"uv": [401, 72], "uv_size": [-3, 3]}, + "down": {"uv": [404, 75], "uv_size": [-3, -3]} + } + }, + { + "origin": [-5.18715, 44.96821, -2.5], + "size": [2, 5, 2], + "pivot": [-5.68715, 44.96821, -3], + "rotation": [-22.5, 0, 0], + "uv": { + "north": {"uv": [391, 123], "uv_size": [2, 5]}, + "east": {"uv": [393, 123], "uv_size": [2, 5]}, + "south": {"uv": [389, 123], "uv_size": [2, 5]}, + "west": {"uv": [395, 123], "uv_size": [2, 5]}, + "up": {"uv": [391, 123], "uv_size": [-2, -2]}, + "down": {"uv": [393, 123], "uv_size": [-2, -2]} + } + }, + { + "origin": [-4.28715, 47.39627, -0.62464], + "size": [0.1, 2, 5], + "pivot": [-4.18715, 49.39627, -0.62464], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [395, 85], "uv_size": [-5, -2], "uv_rotation": 90}, + "east": {"uv": [394, 79], "uv_size": [-5, -2], "uv_rotation": 90}, + "south": {"uv": [395, 85], "uv_size": [-5, -2], "uv_rotation": 90}, + "west": {"uv": [389, 79], "uv_size": [5, -2], "uv_rotation": 90}, + "up": {"uv": [390, 83], "uv_size": [5, 2], "uv_rotation": 90}, + "down": {"uv": [390, 83], "uv_size": [5, 2], "uv_rotation": 90} + } + } + ] + }, + { + "name": "left_arm", + "parent": "upper_torso", + "pivot": [6, 32.5, 0], + "rotation": [0, 0, -22.5], + "cubes": [ + { + "origin": [4, 26, -2], + "size": [5, 9, 4], + "uv": { + "north": {"uv": [389, 41], "uv_size": [5, 9]}, + "east": {"uv": [388, 50], "uv_size": [4, 9]}, + "south": {"uv": [394, 41], "uv_size": [5, 9]}, + "west": {"uv": [434, 7], "uv_size": [4, 9]}, + "up": {"uv": [446, 41], "uv_size": [5, 4]}, + "down": {"uv": [436, 66], "uv_size": [5, -4]} + } + }, + { + "origin": [7, 30, -2], + "size": [4, 0.1, 4], + "pivot": [9, 29, 0], + "rotation": [0, -45, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [4, 0]}, + "east": {"uv": [384, 0], "uv_size": [4, 0]}, + "south": {"uv": [384, 0], "uv_size": [4, 0]}, + "west": {"uv": [384, 0], "uv_size": [4, 0]}, + "up": {"uv": [449, 61], "uv_size": [4, 4]}, + "down": {"uv": [449, 65], "uv_size": [4, -4]} + } + }, + { + "origin": [6.75, 29, -1.75], + "size": [4, 0.1, 4], + "pivot": [9, 29, 0], + "rotation": [0, -45, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [4, 0]}, + "east": {"uv": [384, 0], "uv_size": [4, 0]}, + "south": {"uv": [384, 0], "uv_size": [4, 0]}, + "west": {"uv": [384, 0], "uv_size": [4, 0]}, + "up": {"uv": [449, 61], "uv_size": [4, 4]}, + "down": {"uv": [449, 65], "uv_size": [4, -4]} + } + }, + { + "origin": [6.5, 28, -1.5], + "size": [4, 0.1, 4], + "pivot": [9, 29, 0], + "rotation": [0, -45, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [4, 0]}, + "east": {"uv": [384, 0], "uv_size": [4, 0]}, + "south": {"uv": [384, 0], "uv_size": [4, 0]}, + "west": {"uv": [384, 0], "uv_size": [4, 0]}, + "up": {"uv": [449, 61], "uv_size": [4, 4]}, + "down": {"uv": [449, 65], "uv_size": [4, -4]} + } + }, + { + "origin": [6, 31, -3], + "size": [4, 5, 6], + "uv": { + "north": {"uv": [441, 62], "uv_size": [4, 5]}, + "east": {"uv": [396, 56], "uv_size": [6, 5]}, + "south": {"uv": [401, 63], "uv_size": [4, 5]}, + "west": {"uv": [406, 57], "uv_size": [6, 5]}, + "up": {"uv": [445, 57], "uv_size": [4, 6]}, + "down": {"uv": [384, 68], "uv_size": [4, -6]} + } + }, + { + "origin": [10, 31, -2.5], + "size": [3, 0.1, 5], + "pivot": [10, 31, 0], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [384, 0], "uv_size": [3, 0]}, + "east": {"uv": [384, 0], "uv_size": [5, 0]}, + "south": {"uv": [384, 0], "uv_size": [3, 0]}, + "west": {"uv": [384, 0], "uv_size": [5, 0]}, + "up": {"uv": [423, 69], "uv_size": [3, 5]}, + "down": {"uv": [423, 74], "uv_size": [3, -5]} + } + }, + { + "origin": [8.9, 33, -3.5], + "size": [0.1, 6, 7], + "pivot": [9, 36, 0], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 6]}, + "east": {"uv": [438, 23], "uv_size": [-7, 6]}, + "south": {"uv": [384, 0], "uv_size": [0, 6]}, + "west": {"uv": [431, 23], "uv_size": [7, 6]}, + "up": {"uv": [384, 0], "uv_size": [0, 7]}, + "down": {"uv": [384, 7], "uv_size": [0, -7]} + } + } + ] + }, + { + "name": "left_elbow", + "parent": "left_arm", + "pivot": [6.5, 26, 1], + "rotation": [-22.5, 0, 0], + "cubes": [ + { + "origin": [4.5, 17, -2], + "size": [4, 9, 4], + "uv": { + "north": {"uv": [392, 50], "uv_size": [4, 9]}, + "east": {"uv": [413, 51], "uv_size": [4, 9]}, + "south": {"uv": [417, 51], "uv_size": [4, 9]}, + "west": {"uv": [427, 53], "uv_size": [4, 9]}, + "up": {"uv": [451, 49], "uv_size": [4, 4]}, + "down": {"uv": [440, 71], "uv_size": [4, -4]} + } + }, + { + "origin": [5.5, 24, 0.5], + "size": [2, 3, 2], + "uv": { + "north": {"uv": [476, 2], "uv_size": [-2, 3]}, + "east": {"uv": [474, 5], "uv_size": [-2, 3]}, + "south": {"uv": [476, 5], "uv_size": [-2, 3]}, + "west": {"uv": [474, 2], "uv_size": [-2, 3]}, + "up": {"uv": [478, 4], "uv_size": [2, -2]}, + "down": {"uv": [476, 4], "uv_size": [2, -2]} + } + } + ] + }, + { + "name": "hand_boomstick", + "parent": "left_elbow", + "pivot": [6.5, 20, -2], + "cubes": [ + { + "origin": [4.5, 5, -5], + "size": [4, 15, 3], + "uv": { + "north": {"uv": [403, 18], "uv_size": [4, 15]}, + "east": {"uv": [399, 41], "uv_size": [3, 15]}, + "south": {"uv": [407, 18], "uv_size": [4, 15]}, + "west": {"uv": [410, 42], "uv_size": [3, 15]}, + "up": {"uv": [426, 70], "uv_size": [4, 3]}, + "down": {"uv": [436, 73], "uv_size": [4, -3]} + } + }, + { + "origin": [6.75, 4, -5.25], + "size": [2, 13, 2], + "uv": { + "north": {"uv": [412, 60], "uv_size": [2, 13]}, + "east": {"uv": [414, 60], "uv_size": [2, 13]}, + "south": {"uv": [416, 60], "uv_size": [2, 13]}, + "west": {"uv": [418, 60], "uv_size": [2, 13]}, + "up": {"uv": [388, 73], "uv_size": [2, 2]}, + "down": {"uv": [412, 75], "uv_size": [2, -2]} + } + }, + { + "origin": [4.25, 4, -5.25], + "size": [2, 13, 2], + "uv": { + "north": {"uv": [414, 60], "uv_size": [-2, 13]}, + "east": {"uv": [420, 60], "uv_size": [-2, 13]}, + "south": {"uv": [418, 60], "uv_size": [-2, 13]}, + "west": {"uv": [416, 60], "uv_size": [-2, 13]}, + "up": {"uv": [390, 73], "uv_size": [-2, 2]}, + "down": {"uv": [414, 75], "uv_size": [-2, -2]} + } + }, + { + "origin": [5, 17.5, -4], + "size": [3, 3, 7], + "pivot": [6.5, 19, -3], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [456, 19], "uv_size": [3, 3]}, + "east": {"uv": [446, 26], "uv_size": [7, 3]}, + "south": {"uv": [404, 72], "uv_size": [3, 3]}, + "west": {"uv": [423, 62], "uv_size": [7, 3]}, + "up": {"uv": [430, 62], "uv_size": [3, 7]}, + "down": {"uv": [433, 69], "uv_size": [3, -7]} + } + } + ] + }, + { + "name": "right_arm", + "parent": "upper_torso", + "pivot": [-6, 32.5, 0], + "rotation": [0, 0, 22.5], + "cubes": [ + { + "origin": [-9, 26, -2], + "size": [5, 9, 4], + "uv": { + "north": {"uv": [426, 17], "uv_size": [5, 9]}, + "east": {"uv": [431, 53], "uv_size": [4, 9]}, + "south": {"uv": [413, 42], "uv_size": [5, 9]}, + "west": {"uv": [435, 53], "uv_size": [4, 9]}, + "up": {"uv": [447, 21], "uv_size": [5, 4]}, + "down": {"uv": [447, 49], "uv_size": [5, -4]} + } + }, + { + "origin": [-11, 28, -2], + "size": [4, 0.1, 4], + "pivot": [-9, 27, 0], + "rotation": [0, 45, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [4, 0]}, + "east": {"uv": [384, 0], "uv_size": [4, 0]}, + "south": {"uv": [384, 0], "uv_size": [4, 0]}, + "west": {"uv": [384, 0], "uv_size": [4, 0]}, + "up": {"uv": [452, 3], "uv_size": [4, 4]}, + "down": {"uv": [452, 7], "uv_size": [4, -4]} + } + }, + { + "origin": [-10, 29, -3], + "size": [4, 5, 6], + "uv": { + "north": {"uv": [445, 62], "uv_size": [-4, 5]}, + "east": {"uv": [412, 57], "uv_size": [-6, 5]}, + "south": {"uv": [405, 63], "uv_size": [-4, 5]}, + "west": {"uv": [402, 56], "uv_size": [-6, 5]}, + "up": {"uv": [449, 57], "uv_size": [-4, 6]}, + "down": {"uv": [388, 68], "uv_size": [-4, -6]} + } + }, + { + "origin": [-12, 29.41421, -2.5], + "size": [3, 0.1, 5], + "pivot": [-10, 30.41421, 0], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [387, 0], "uv_size": [-3, 0]}, + "east": {"uv": [389, 0], "uv_size": [-5, 0]}, + "south": {"uv": [387, 0], "uv_size": [-3, 0]}, + "west": {"uv": [389, 0], "uv_size": [-5, 0]}, + "up": {"uv": [426, 69], "uv_size": [-3, 5]}, + "down": {"uv": [426, 74], "uv_size": [-3, -5]} + } + }, + { + "origin": [-10.1, 31.41421, -3.5], + "size": [0.1, 6, 7], + "pivot": [-9, 35.41421, 0], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 6]}, + "east": {"uv": [438, 23], "uv_size": [-7, 6]}, + "south": {"uv": [384, 0], "uv_size": [0, 6]}, + "west": {"uv": [431, 23], "uv_size": [7, 6]}, + "up": {"uv": [384, 0], "uv_size": [0, 7]}, + "down": {"uv": [384, 7], "uv_size": [0, -7]} + } + } + ] + }, + { + "name": "right_elbow", + "parent": "right_arm", + "pivot": [-6.5, 26, 1], + "rotation": [-22.5, 0, 0], + "cubes": [ + { + "origin": [-8.5, 17, -2], + "size": [4, 9, 4], + "uv": { + "north": {"uv": [438, 0], "uv_size": [4, 9]}, + "east": {"uv": [438, 9], "uv_size": [4, 9]}, + "south": {"uv": [402, 54], "uv_size": [4, 9]}, + "west": {"uv": [438, 18], "uv_size": [4, 9]}, + "up": {"uv": [399, 68], "uv_size": [4, 4]}, + "down": {"uv": [403, 72], "uv_size": [4, -4]} + } + }, + { + "origin": [-7.5, 24, 0.5], + "size": [2, 3, 2], + "uv": { + "north": {"uv": [474, 2], "uv_size": [2, 3]}, + "east": {"uv": [472, 2], "uv_size": [2, 3]}, + "south": {"uv": [474, 5], "uv_size": [2, 3]}, + "west": {"uv": [472, 5], "uv_size": [2, 3]}, + "up": {"uv": [480, 4], "uv_size": [-2, -2]}, + "down": {"uv": [478, 4], "uv_size": [-2, -2]} + } + } + ] + }, + { + "name": "axe", + "parent": "right_elbow", + "pivot": [-6.5, 19, -1], + "rotation": [45, 45, -15], + "cubes": [ + { + "origin": [-6.6, 10.5, -32], + "size": [0.1, 17, 19], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 17]}, + "east": {"uv": [461, 111], "uv_size": [-19, 17]}, + "south": {"uv": [384, 0], "uv_size": [0, 17]}, + "west": {"uv": [442, 111], "uv_size": [19, 17]}, + "up": {"uv": [384, 0], "uv_size": [0, 19]}, + "down": {"uv": [384, 19], "uv_size": [0, -19]} + } + }, + { + "origin": [-7.5, 18, -26], + "size": [2, 2, 32], + "uv": { + "north": {"uv": [414, 73], "uv_size": [2, 2]}, + "east": {"uv": [421, 31], "uv_size": [24, 2]}, + "south": {"uv": [416, 73], "uv_size": [2, 2]}, + "west": {"uv": [421, 33], "uv_size": [24, 2]}, + "up": {"uv": [408, 33], "uv_size": [2, 24]}, + "down": {"uv": [421, 59], "uv_size": [2, -24]} + } + }, + { + "origin": [-7.5, 17.5, -31], + "size": [2, 3, 3], + "uv": { + "north": {"uv": [399, 65], "uv_size": [2, 3]}, + "east": {"uv": [456, 22], "uv_size": [3, 3]}, + "south": {"uv": [420, 72], "uv_size": [2, 3]}, + "west": {"uv": [407, 72], "uv_size": [3, 3]}, + "up": {"uv": [456, 52], "uv_size": [2, 3]}, + "down": {"uv": [456, 58], "uv_size": [2, -3]} + } + }, + { + "origin": [-6.5, 17.5, -32.5], + "size": [0, 4, 4], + "pivot": [-6.5, 19, -31], + "rotation": [-45, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 4]}, + "east": {"uv": [407, 68], "uv_size": [4, 4]}, + "south": {"uv": [384, 0], "uv_size": [0, 4]}, + "west": {"uv": [411, 68], "uv_size": [-4, 4]}, + "up": {"uv": [384, 0], "uv_size": [0, 4]}, + "down": {"uv": [384, 4], "uv_size": [0, -4]} + } + } + ] + }, + { + "name": "inactive_axe", + "parent": "right_elbow", + "pivot": [-6.5, 19, -1], + "rotation": [45, 45, -15], + "cubes": [ + { + "origin": [-7.5, 18, -26], + "size": [2, 2, 32], + "uv": { + "north": {"uv": [414, 73], "uv_size": [2, 2]}, + "east": {"uv": [421, 31], "uv_size": [24, 2]}, + "south": {"uv": [416, 73], "uv_size": [2, 2]}, + "west": {"uv": [421, 33], "uv_size": [24, 2]}, + "up": {"uv": [408, 33], "uv_size": [2, 24]}, + "down": {"uv": [421, 59], "uv_size": [2, -24]} + } + }, + { + "origin": [-7.5, 17.5, -29], + "size": [2, 3, 3], + "uv": { + "north": {"uv": [404, 75], "uv_size": [2, 3]}, + "east": {"uv": [459, 22], "uv_size": [3, 3]}, + "south": {"uv": [420, 75], "uv_size": [2, 3]}, + "west": {"uv": [407, 75], "uv_size": [3, 3]}, + "up": {"uv": [458, 52], "uv_size": [2, 3]}, + "down": {"uv": [458, 58], "uv_size": [2, -3]} + } + }, + { + "origin": [-6.5, 17.5, -30.5], + "size": [0, 4, 4], + "pivot": [-6.5, 19, -29], + "rotation": [-45, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 4]}, + "east": {"uv": [407, 68], "uv_size": [4, 4]}, + "south": {"uv": [384, 0], "uv_size": [0, 4]}, + "west": {"uv": [411, 68], "uv_size": [-4, 4]}, + "up": {"uv": [384, 0], "uv_size": [0, 4]}, + "down": {"uv": [384, 4], "uv_size": [0, -4]} + } + } + ] + }, + { + "name": "b_torso", + "parent": "torso", + "pivot": [0, 50, 0], + "cubes": [ + { + "origin": [-8, 16, -8], + "size": [16, 16, 16], + "uv": { + "north": {"uv": [384, 0], "uv_size": [16, 16]}, + "east": {"uv": [384, 0], "uv_size": [16, 16]}, + "south": {"uv": [384, 0], "uv_size": [16, 16]}, + "west": {"uv": [384, 0], "uv_size": [16, 16]}, + "up": {"uv": [400, 16], "uv_size": [-16, -16]}, + "down": {"uv": [400, 16], "uv_size": [-16, -16]} + } + } + ] + }, + { + "name": "b_head", + "parent": "torso", + "pivot": [0, 66, 0], + "cubes": [ + { + "origin": [-4, 32, -4], + "size": [8, 8, 8], + "uv": { + "north": {"uv": [384, 0], "uv_size": [8, 8]}, + "east": {"uv": [384, 0], "uv_size": [8, 8]}, + "south": {"uv": [384, 0], "uv_size": [8, 8]}, + "west": {"uv": [384, 0], "uv_size": [8, 8]}, + "up": {"uv": [392, 8], "uv_size": [-8, -8]}, + "down": {"uv": [392, 8], "uv_size": [-8, -8]} + } + } + ] + }, + { + "name": "left_leg", + "parent": "body2", + "pivot": [2.5, 21, 0], + "rotation": [0, -10, -5], + "cubes": [ + { + "origin": [0, 11, -2.5], + "size": [5, 10, 5], + "uv": { + "north": {"uv": [411, 32], "uv_size": [5, 10]}, + "east": {"uv": [416, 32], "uv_size": [5, 10]}, + "south": {"uv": [403, 33], "uv_size": [5, 10]}, + "west": {"uv": [384, 34], "uv_size": [5, 10]}, + "up": {"uv": [426, 26], "uv_size": [5, 5]}, + "down": {"uv": [442, 26], "uv_size": [5, -5]} + } + }, + { + "origin": [2, 17, -2.75], + "size": [3, 5, 0.1], + "pivot": [4, 18.5, -2.75], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [456, 53], "uv_size": [-3, 5]}, + "east": {"uv": [384, 0], "uv_size": [0, 5]}, + "south": {"uv": [453, 53], "uv_size": [3, 5]}, + "west": {"uv": [384, 0], "uv_size": [0, 5]}, + "up": {"uv": [384, 0], "uv_size": [3, 0]}, + "down": {"uv": [384, 0], "uv_size": [3, 0]} + } + }, + { + "origin": [2, 15, -2.75], + "size": [3, 4, 0.1], + "pivot": [4, 15.5, -2.75], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [457, 68], "uv_size": [-3, 4]}, + "east": {"uv": [384, 0], "uv_size": [0, 4]}, + "south": {"uv": [454, 68], "uv_size": [3, 4]}, + "west": {"uv": [384, 0], "uv_size": [0, 4]}, + "up": {"uv": [384, 0], "uv_size": [3, 0]}, + "down": {"uv": [384, 0], "uv_size": [3, 0]} + } + } + ] + }, + { + "name": "left_knee", + "parent": "left_leg", + "pivot": [2.5, 11, -1.5], + "rotation": [5, 0, 0], + "cubes": [ + { + "origin": [0.5, 0, -2.5], + "size": [4, 11, 4], + "uv": { + "north": {"uv": [402, 43], "uv_size": [4, 11]}, + "east": {"uv": [384, 44], "uv_size": [4, 11]}, + "south": {"uv": [428, 35], "uv_size": [4, 11]}, + "west": {"uv": [423, 44], "uv_size": [4, 11]}, + "up": {"uv": [452, 45], "uv_size": [4, 4]}, + "down": {"uv": [444, 72], "uv_size": [4, -4]} + } + }, + { + "origin": [1, 8, -3.5], + "size": [3, 5, 2], + "uv": { + "north": {"uv": [453, 63], "uv_size": [3, 5]}, + "east": {"uv": [391, 72], "uv_size": [2, 5]}, + "south": {"uv": [448, 69], "uv_size": [3, 5]}, + "west": {"uv": [456, 8], "uv_size": [2, 5]}, + "up": {"uv": [453, 19], "uv_size": [3, 2]}, + "down": {"uv": [456, 60], "uv_size": [3, -2]} + } + } + ] + }, + { + "name": "leg_boomstick", + "parent": "left_leg", + "pivot": [6.5, 21, 0], + "cubes": [ + { + "origin": [5, 19, -0.5], + "size": [3, 3, 7], + "pivot": [6.5, 20.5, 0.5], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [456, 19], "uv_size": [3, 3]}, + "east": {"uv": [446, 26], "uv_size": [7, 3]}, + "south": {"uv": [404, 72], "uv_size": [3, 3]}, + "west": {"uv": [423, 62], "uv_size": [7, 3]}, + "up": {"uv": [430, 62], "uv_size": [3, 7]}, + "down": {"uv": [433, 69], "uv_size": [3, -7]} + } + }, + { + "origin": [4.5, 6.5, -1.5], + "size": [4, 15, 3], + "uv": { + "north": {"uv": [403, 18], "uv_size": [4, 15]}, + "east": {"uv": [399, 41], "uv_size": [3, 15]}, + "south": {"uv": [407, 18], "uv_size": [4, 15]}, + "west": {"uv": [410, 42], "uv_size": [3, 15]}, + "up": {"uv": [426, 70], "uv_size": [4, 3]}, + "down": {"uv": [436, 73], "uv_size": [4, -3]} + } + }, + { + "origin": [4.25, 5.5, -1.75], + "size": [2, 13, 2], + "uv": { + "north": {"uv": [414, 60], "uv_size": [-2, 13]}, + "east": {"uv": [420, 60], "uv_size": [-2, 13]}, + "south": {"uv": [418, 60], "uv_size": [-2, 13]}, + "west": {"uv": [416, 60], "uv_size": [-2, 13]}, + "up": {"uv": [390, 73], "uv_size": [-2, 2]}, + "down": {"uv": [414, 75], "uv_size": [-2, -2]} + } + }, + { + "origin": [6.75, 5.5, -1.75], + "size": [2, 13, 2], + "uv": { + "north": {"uv": [412, 60], "uv_size": [2, 13]}, + "east": {"uv": [414, 60], "uv_size": [2, 13]}, + "south": {"uv": [416, 60], "uv_size": [2, 13]}, + "west": {"uv": [418, 60], "uv_size": [2, 13]}, + "up": {"uv": [388, 73], "uv_size": [2, 2]}, + "down": {"uv": [412, 75], "uv_size": [2, -2]} + } + } + ] + }, + { + "name": "right_leg", + "parent": "body2", + "pivot": [-2.5, 21, 0], + "rotation": [0, 10, 5], + "cubes": [ + { + "origin": [-5, 11, -2.5], + "size": [5, 10, 5], + "uv": { + "north": {"uv": [416, 32], "uv_size": [-5, 10]}, + "east": {"uv": [389, 34], "uv_size": [-5, 10]}, + "south": {"uv": [408, 33], "uv_size": [-5, 10]}, + "west": {"uv": [421, 32], "uv_size": [-5, 10]}, + "up": {"uv": [431, 26], "uv_size": [-5, 5]}, + "down": {"uv": [447, 26], "uv_size": [-5, -5]} + } + }, + { + "origin": [-5, 17, -2.75], + "size": [3, 5, 0.1], + "pivot": [-4, 18.5, -2.75], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [453, 53], "uv_size": [3, 5]}, + "east": {"uv": [384, 0], "uv_size": [0, 5]}, + "south": {"uv": [456, 53], "uv_size": [-3, 5]}, + "west": {"uv": [384, 0], "uv_size": [0, 5]}, + "up": {"uv": [387, 0], "uv_size": [-3, 0]}, + "down": {"uv": [387, 0], "uv_size": [-3, 0]} + } + }, + { + "origin": [-5, 15, -2.75], + "size": [3, 4, 0.1], + "pivot": [-4, 15.5, -2.75], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [454, 68], "uv_size": [3, 4]}, + "east": {"uv": [384, 0], "uv_size": [0, 4]}, + "south": {"uv": [457, 68], "uv_size": [-3, 4]}, + "west": {"uv": [384, 0], "uv_size": [0, 4]}, + "up": {"uv": [387, 0], "uv_size": [-3, 0]}, + "down": {"uv": [387, 0], "uv_size": [-3, 0]} + } + } + ] + }, + { + "name": "right_knee", + "parent": "right_leg", + "pivot": [-2.5, 11, -1.5], + "rotation": [5, 0, 0], + "cubes": [ + { + "origin": [-4.5, 0, -2.5], + "size": [4, 11, 4], + "uv": { + "north": {"uv": [406, 43], "uv_size": [-4, 11]}, + "east": {"uv": [427, 44], "uv_size": [-4, 11]}, + "south": {"uv": [432, 35], "uv_size": [-4, 11]}, + "west": {"uv": [388, 44], "uv_size": [-4, 11]}, + "up": {"uv": [456, 45], "uv_size": [-4, 4]}, + "down": {"uv": [448, 72], "uv_size": [-4, -4]} + } + }, + { + "origin": [-4, 8, -3.5], + "size": [3, 5, 2], + "uv": { + "north": {"uv": [456, 63], "uv_size": [-3, 5]}, + "east": {"uv": [458, 8], "uv_size": [-2, 5]}, + "south": {"uv": [451, 69], "uv_size": [-3, 5]}, + "west": {"uv": [393, 72], "uv_size": [-2, 5]}, + "up": {"uv": [456, 19], "uv_size": [-3, 2]}, + "down": {"uv": [459, 60], "uv_size": [-3, -2]} + } + } + ] + }, + { + "name": "h_slash", + "parent": "body2", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash2", + "parent": "h_slash", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash3", + "parent": "h_slash2", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash4", + "parent": "h_slash3", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash5", + "parent": "h_slash4", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash6", + "parent": "h_slash5", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash7", + "parent": "h_slash6", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash8", + "parent": "h_slash7", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash9", + "parent": "h_slash8", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash10", + "parent": "h_slash9", + "pivot": [0, 24, -32], + "cubes": [ + { + "origin": [-0.1, 10, -48], + "size": [0.1, 32, 32], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 32]}, + "east": {"uv": [512, 96], "uv_size": [-32, 32]}, + "south": {"uv": [384, 0], "uv_size": [0, 32]}, + "west": {"uv": [480, 96], "uv_size": [32, 32]}, + "up": {"uv": [384, 32], "uv_size": [0, -32]}, + "down": {"uv": [384, 32], "uv_size": [0, -32]} + } + } + ] + }, + { + "name": "dreadnought_portal", + "pivot": [0, 0, 0] + }, + { + "name": "body", + "parent": "dreadnought_portal", + "pivot": [0, 0, 0] + }, + { + "name": "black", + "parent": "body", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-46, -22, 0], + "size": [92, 92, 0.1], + "uv": { + "north": {"uv": [128, 0], "uv_size": [128, 128]}, + "east": {"uv": [128, 0], "uv_size": [0, 32]}, + "south": {"uv": [256, 0], "uv_size": [-128, 128]}, + "west": {"uv": [128, 0], "uv_size": [0, 32]}, + "up": {"uv": [160, 0], "uv_size": [-32, 0]}, + "down": {"uv": [160, 0], "uv_size": [-32, 0]} + } + } + ] + }, + { + "name": "cluster1", + "parent": "body", + "pivot": [0, 24, 0] + }, + { + "name": "cloud1", + "parent": "cluster1", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud2", + "parent": "cluster1", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud3", + "parent": "cluster1", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud4", + "parent": "cluster1", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster2", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 10] + }, + { + "name": "cloud5", + "parent": "cluster2", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud6", + "parent": "cluster2", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud7", + "parent": "cluster2", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud8", + "parent": "cluster2", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud9", + "parent": "cluster2", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster3", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 22.5] + }, + { + "name": "cloud10", + "parent": "cluster3", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud11", + "parent": "cluster3", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud12", + "parent": "cluster3", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud13", + "parent": "cluster3", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster4", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 32.5] + }, + { + "name": "cloud14", + "parent": "cluster4", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud15", + "parent": "cluster4", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud16", + "parent": "cluster4", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud17", + "parent": "cluster4", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud18", + "parent": "cluster4", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster5", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 45] + }, + { + "name": "cloud19", + "parent": "cluster5", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud20", + "parent": "cluster5", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud21", + "parent": "cluster5", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud22", + "parent": "cluster5", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster6", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 55] + }, + { + "name": "cloud23", + "parent": "cluster6", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud24", + "parent": "cluster6", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud25", + "parent": "cluster6", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud26", + "parent": "cluster6", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud27", + "parent": "cluster6", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster7", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 67.5] + }, + { + "name": "cloud28", + "parent": "cluster7", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud29", + "parent": "cluster7", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud30", + "parent": "cluster7", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud31", + "parent": "cluster7", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster8", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 77.5] + }, + { + "name": "cloud32", + "parent": "cluster8", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud33", + "parent": "cluster8", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud34", + "parent": "cluster8", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud35", + "parent": "cluster8", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud36", + "parent": "cluster8", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster9", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 90] + }, + { + "name": "cloud37", + "parent": "cluster9", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud38", + "parent": "cluster9", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud39", + "parent": "cluster9", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud40", + "parent": "cluster9", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster10", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 100] + }, + { + "name": "cloud41", + "parent": "cluster10", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud42", + "parent": "cluster10", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud43", + "parent": "cluster10", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud44", + "parent": "cluster10", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud45", + "parent": "cluster10", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster11", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 112.5] + }, + { + "name": "cloud46", + "parent": "cluster11", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud47", + "parent": "cluster11", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud48", + "parent": "cluster11", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud49", + "parent": "cluster11", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster12", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 122.5] + }, + { + "name": "cloud50", + "parent": "cluster12", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud51", + "parent": "cluster12", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud52", + "parent": "cluster12", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud53", + "parent": "cluster12", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud54", + "parent": "cluster12", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster13", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 135] + }, + { + "name": "cloud55", + "parent": "cluster13", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud56", + "parent": "cluster13", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud57", + "parent": "cluster13", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud58", + "parent": "cluster13", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster14", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 145] + }, + { + "name": "cloud59", + "parent": "cluster14", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud60", + "parent": "cluster14", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud61", + "parent": "cluster14", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud62", + "parent": "cluster14", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud63", + "parent": "cluster14", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster15", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 157.5] + }, + { + "name": "cloud64", + "parent": "cluster15", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud65", + "parent": "cluster15", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud66", + "parent": "cluster15", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud67", + "parent": "cluster15", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster16", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 167.5] + }, + { + "name": "cloud68", + "parent": "cluster16", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud69", + "parent": "cluster16", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud70", + "parent": "cluster16", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud71", + "parent": "cluster16", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud72", + "parent": "cluster16", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster17", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -180] + }, + { + "name": "cloud73", + "parent": "cluster17", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud74", + "parent": "cluster17", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud75", + "parent": "cluster17", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud76", + "parent": "cluster17", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster18", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -170] + }, + { + "name": "cloud77", + "parent": "cluster18", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud78", + "parent": "cluster18", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud79", + "parent": "cluster18", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud80", + "parent": "cluster18", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud81", + "parent": "cluster18", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster19", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -157.5] + }, + { + "name": "cloud82", + "parent": "cluster19", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud83", + "parent": "cluster19", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud84", + "parent": "cluster19", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud85", + "parent": "cluster19", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster20", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -147.5] + }, + { + "name": "cloud86", + "parent": "cluster20", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud87", + "parent": "cluster20", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud88", + "parent": "cluster20", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud89", + "parent": "cluster20", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud90", + "parent": "cluster20", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster21", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -135] + }, + { + "name": "cloud91", + "parent": "cluster21", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud92", + "parent": "cluster21", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud93", + "parent": "cluster21", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud94", + "parent": "cluster21", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster22", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -125] + }, + { + "name": "cloud95", + "parent": "cluster22", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud96", + "parent": "cluster22", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud97", + "parent": "cluster22", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud98", + "parent": "cluster22", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud99", + "parent": "cluster22", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster23", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -112.5] + }, + { + "name": "cloud100", + "parent": "cluster23", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud101", + "parent": "cluster23", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud102", + "parent": "cluster23", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud103", + "parent": "cluster23", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster24", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -102.5] + }, + { + "name": "cloud104", + "parent": "cluster24", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud105", + "parent": "cluster24", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud106", + "parent": "cluster24", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud107", + "parent": "cluster24", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud108", + "parent": "cluster24", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster25", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -90] + }, + { + "name": "cloud109", + "parent": "cluster25", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud110", + "parent": "cluster25", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud111", + "parent": "cluster25", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud112", + "parent": "cluster25", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster26", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -80] + }, + { + "name": "cloud113", + "parent": "cluster26", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud114", + "parent": "cluster26", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud115", + "parent": "cluster26", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud116", + "parent": "cluster26", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud117", + "parent": "cluster26", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster27", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -67.5] + }, + { + "name": "cloud118", + "parent": "cluster27", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud119", + "parent": "cluster27", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud120", + "parent": "cluster27", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud121", + "parent": "cluster27", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster28", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -57.5] + }, + { + "name": "cloud122", + "parent": "cluster28", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud123", + "parent": "cluster28", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud124", + "parent": "cluster28", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud125", + "parent": "cluster28", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud126", + "parent": "cluster28", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster29", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -45] + }, + { + "name": "cloud127", + "parent": "cluster29", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud128", + "parent": "cluster29", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud129", + "parent": "cluster29", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud130", + "parent": "cluster29", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster30", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -35] + }, + { + "name": "cloud131", + "parent": "cluster30", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud132", + "parent": "cluster30", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud133", + "parent": "cluster30", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud134", + "parent": "cluster30", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud135", + "parent": "cluster30", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster31", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -22.5] + }, + { + "name": "cloud136", + "parent": "cluster31", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud137", + "parent": "cluster31", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud138", + "parent": "cluster31", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud139", + "parent": "cluster31", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster32", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -12.5] + }, + { + "name": "cloud140", + "parent": "cluster32", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud141", + "parent": "cluster32", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud142", + "parent": "cluster32", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud143", + "parent": "cluster32", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud144", + "parent": "cluster32", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/textures/entity/marauder.png b/common/src/main/resources/assets/azurelib/textures/entity/marauder.png new file mode 100644 index 0000000000000000000000000000000000000000..0d1ba734d375a5c0079e4bbecc73cdc36ea2db8f GIT binary patch literal 11573 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 literal 0 HcmV?d00001 diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index ea27c2315..c7423daae 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -19,6 +19,7 @@ import mod.azure.azurelib.fabric.core2.example.blocks.StargateRender; import mod.azure.azurelib.fabric.core2.example.entities.doomhunter.DoomHunterRenderer; import mod.azure.azurelib.fabric.core2.example.entities.drone.DroneRenderer; +import mod.azure.azurelib.fabric.core2.example.entities.marauder.MarauderRenderer; public final class ClientListener implements ClientModInitializer { @@ -70,6 +71,7 @@ public void onInitializeClient() { EntityRendererRegistry.register(ExampleEntityTypes.DRONE, DroneRenderer::new); EntityRendererRegistry.register(ExampleEntityTypes.DOOMHUNTER, DoomHunterRenderer::new); + EntityRendererRegistry.register(ExampleEntityTypes.MARAUDER, MarauderRenderer::new); BlockRenderLayerMap.INSTANCE.putBlock(FabricAzureLibMod.STARGATE, RenderType.translucent()); BlockEntityRenderers.register( ExampleEntityTypes.STARGATE, diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java index b36d16eda..1d3a45152 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java @@ -14,6 +14,7 @@ import mod.azure.azurelib.fabric.core2.example.blocks.StargateBlockEntity; import mod.azure.azurelib.fabric.core2.example.entities.doomhunter.DoomHunter; import mod.azure.azurelib.fabric.core2.example.entities.drone.Drone; +import mod.azure.azurelib.fabric.core2.example.entities.marauder.MarauderEntity; public class ExampleEntityTypes { @@ -27,6 +28,11 @@ public class ExampleEntityTypes { EntityType.Builder.of(DoomHunter::new, MobCategory.MONSTER).sized(3.0f, 7.0f) ); + public static final EntityType MARAUDER = register( + "marauder", + EntityType.Builder.of(MarauderEntity::new, MobCategory.MONSTER).sized(1.5f, 2.6f) + ); + private static EntityType register(String name, EntityType.Builder builder) { var entityType = builder.build(name); var resourceLocation = AzureLib.modResource(name); @@ -43,5 +49,6 @@ private static EntityType register(String name, EntityType public static void initialize() { FabricDefaultAttributeRegistry.register(DRONE, Drone.createMonsterAttributes()); FabricDefaultAttributeRegistry.register(DOOMHUNTER, DoomHunter.createMonsterAttributes()); + FabricDefaultAttributeRegistry.register(MARAUDER, MarauderEntity.createMonsterAttributes()); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java new file mode 100644 index 000000000..f40d09abd --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java @@ -0,0 +1,64 @@ +package mod.azure.azurelib.fabric.core2.example.entities.marauder; + +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.animation.primitive.AzLoopType; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; + +public class MarauderAnimator extends AzEntityAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource( + "animations/entity/marauder.animation.json" + ); + + private static final String IDLE_ANIMATION_NAME = "idle"; + + private static final String WALK_ANIMATION_NAME = "walk"; + + private static final String DEATH_ANIMATION_NAME = "death"; + + private static final String RUN_ANIMATION_NAME = "run"; + + private static final String MELEE_ANIMATION_NAME = "axe_attack"; + + private static final AzRawAnimation IDLE_ANIMATION = AzRawAnimation.begin().thenLoop(IDLE_ANIMATION_NAME); + + private static final AzRawAnimation WALK_ANIMATION = AzRawAnimation.begin().thenLoop(WALK_ANIMATION_NAME); + + private static final AzRawAnimation DEATH_ANIMATION = AzRawAnimation.begin() + .then(WALK_ANIMATION_NAME, AzLoopType.HOLD_ON_LAST_FRAME); + + private static final AzRawAnimation RUN_ANIMATION = AzRawAnimation.begin().thenLoop(RUN_ANIMATION_NAME); + + private static final AzRawAnimation MELEE_ANIMATION = AzRawAnimation.begin() + .then(MELEE_ANIMATION_NAME, AzLoopType.PLAY_ONCE); + + public MarauderAnimator() { + super(AzAnimatorConfig.defaultConfig()); + } + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + AzAnimationController.builder(this, "base_controller") + .setTransitionLength(5) + .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) + .triggerableAnim(WALK_ANIMATION_NAME, WALK_ANIMATION) + .triggerableAnim(RUN_ANIMATION_NAME, RUN_ANIMATION) + .triggerableAnim(MELEE_ANIMATION_NAME, MELEE_ANIMATION) + .triggerableAnim(DEATH_ANIMATION_NAME, DEATH_ANIMATION) + .build() + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(MarauderEntity drone) { + return ANIMATIONS; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java new file mode 100644 index 000000000..1f863d5aa --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java @@ -0,0 +1,87 @@ +package mod.azure.azurelib.fabric.core2.example.entities.marauder; + +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; +import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; +import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; +import net.minecraft.world.entity.ai.navigation.PathNavigation; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.api.common.ai.pathing.AzureNavigation; +import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; +import mod.azure.azurelib.fabric.core2.example.MoveAnalysis; + +public class MarauderEntity extends Monster { + + private final AzAnimationDispatcher animationDispatcher; + + private final MoveAnalysis moveAnalysis; + + private boolean hasPlayedDeath = false; + + public MarauderEntity(EntityType entityType, Level level) { + super(entityType, level); + this.animationDispatcher = new AzAnimationDispatcher<>(this); + this.moveAnalysis = new MoveAnalysis(this); + } + + @Override + protected @NotNull PathNavigation createNavigation(@NotNull Level level) { + return new AzureNavigation(this, level); + } + + @Override + public float maxUpStep() { + return 2.0F; + } + + /** + * TODO: Get this working, also figure out how to change death rotation from the default 90, needs to be 0 for + * animation to be correct + */ + @Override + protected void tickDeath() { + ++this.deathTime; + if (this.deathTime >= 80 && !this.level().isClientSide() && !this.isRemoved()) { + if (this.level().isClientSide && !this.hasPlayedDeath) { + animationDispatcher.dispatchFromClient("base_controller", "death"); + this.hasPlayedDeath = true; + } + this.level().broadcastEntityEvent(this, (byte) 60); + this.remove(RemovalReason.KILLED); + } + } + + public void tick() { + super.tick(); + moveAnalysis.update(); + + if (this.level().isClientSide) { + var isMovingOnGround = moveAnalysis.isMovingHorizontally() && onGround(); + String animName; + if (isMovingOnGround && !this.isAggressive() && this.isAlive()) { + animName = "walk"; + } else if (isMovingOnGround && this.isAggressive() && this.isAlive()) { + animName = "run"; + } else { + animName = "idle"; + } + animationDispatcher.dispatchFromClient("base_controller", animName); + } else { + // Doing other stuff server-side... + } + } + + /** + * TODO: Get longer Melee animations working + */ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.15F)); + this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 0.6F, true)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true)); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java new file mode 100644 index 000000000..4aac37ae6 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java @@ -0,0 +1,40 @@ +package mod.azure.azurelib.fabric.core2.example.entities.marauder; + +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; + +public class MarauderRenderer extends AzEntityRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/entity/marauder.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/marauder.png"); + + public MarauderRenderer(EntityRendererProvider.Context context) { + super(context); + /** + * TODO: Port this to new system, as it currently requries this be a GeoEntity and use the GeoLayers as well + */ + // addRenderLayer(new AutoGlowingGeoLayer<>(this)); + } + + @Override + protected @Nullable AzEntityAnimator createAnimator() { + return new MarauderAnimator(); + } + + @Override + protected @NotNull ResourceLocation getModelLocation(MarauderEntity drone) { + return MODEL; + } + + @Override + public @NotNull ResourceLocation getTextureLocation(@NotNull MarauderEntity drone) { + return TEXTURE; + } +} From 75e0f87017fc9673158f711b3036af1528074f8b Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sun, 15 Dec 2024 12:19:04 -0500 Subject: [PATCH 090/224] Missed this. Signed-off-by: = --- .../java/mod/azure/azurelib/fabric/core2/example/Facehugger.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/Facehugger.java deleted file mode 100644 index e69de29bb..000000000 From f27b761a4bbd58b361f829cd5fd74e1bdc01475f Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sun, 15 Dec 2024 12:47:07 -0500 Subject: [PATCH 091/224] Fixed MarauderEntity. Signed-off-by: = --- .../core2/example/entities/marauder/MarauderEntity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java index 1f863d5aa..c8ac41915 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java @@ -16,7 +16,7 @@ public class MarauderEntity extends Monster { - private final AzAnimationDispatcher animationDispatcher; + private final AzAnimationDispatcher animationDispatcher; private final MoveAnalysis moveAnalysis; @@ -24,7 +24,7 @@ public class MarauderEntity extends Monster { public MarauderEntity(EntityType entityType, Level level) { super(entityType, level); - this.animationDispatcher = new AzAnimationDispatcher<>(this); + this.animationDispatcher = new AzAnimationDispatcher(this); this.moveAnalysis = new MoveAnalysis(this); } From 6e251830f9bfdf1974b49ac317767915006051a8 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sun, 15 Dec 2024 14:47:41 -0500 Subject: [PATCH 092/224] Eliminated AzAnimationProcessor.java proxy for processing animations. Signed-off-by: = --- .../core2/animation/AzAnimationProcessor.java | 67 ----------- .../azurelib/core2/animation/AzAnimator.java | 14 ++- .../AzAbstractAnimationController.java | 66 +++++++++++ .../controller/AzAnimationController.java | 108 +++++++----------- .../controller/AzBoneAnimationQueueCache.java | 22 +++- .../keyframe/AzKeyFrameManager.java | 8 +- .../keyframe/AzKeyFrameProcessor.java | 10 +- 7 files changed, 150 insertions(+), 145 deletions(-) delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAbstractAnimationController.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java deleted file mode 100644 index 6a07115d4..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationProcessor.java +++ /dev/null @@ -1,67 +0,0 @@ -package mod.azure.azurelib.core2.animation; - -import java.util.Map; - -import mod.azure.azurelib.core.animation.EasingType; -import mod.azure.azurelib.core2.animation.controller.AzAnimationController; -import mod.azure.azurelib.core2.model.AzBoneSnapshot; - -public class AzAnimationProcessor { - - private final AzAnimator animator; - - public boolean reloadAnimations; - - public AzAnimationProcessor(AzAnimator animator) { - this.animator = animator; - this.reloadAnimations = false; - } - - /** - * Tick and apply transformations to the model based on the current state of the {@link AzAnimationController} - * - * @param context An animation context provided by the animator. - */ - public void update(AzAnimationContext context) { - var animatable = context.animatable(); - var timer = context.timer(); - var boneCache = context.boneCache(); - - var boneSnapshots = boneCache.getBoneSnapshotsByName(); - - for (var controller : animator.getAnimationControllerContainer().getAll()) { - var easingType = controller.getOverrideEasingTypeFunction().apply(animatable); - - if (this.reloadAnimations) { - controller.forceAnimationReset(); - controller.getBoneAnimationQueues().clear(); - } - - controller.update(context); - - updateBoneSnapshots(controller, boneSnapshots, easingType); - } - - this.reloadAnimations = false; - - boneCache.update(context); - timer.finishFirstTick(); - } - - private void updateBoneSnapshots( - AzAnimationController controller, - Map boneSnapshots, - EasingType easingType - ) { - // Progresses the current bones according to the animation queue. - for (var boneAnimation : controller.getBoneAnimationQueues()) { - var bone = boneAnimation.bone(); - var snapshot = boneSnapshots.get(bone.getName()); - var initialSnapshot = bone.getInitialAzSnapshot(); - - AzBoneAnimationUpdateUtil.updateRotations(boneAnimation, bone, easingType, initialSnapshot, snapshot); - AzBoneAnimationUpdateUtil.updatePositions(boneAnimation, bone, easingType, snapshot); - AzBoneAnimationUpdateUtil.updateScale(boneAnimation, bone, easingType, snapshot); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index 4811f7573..164b128b2 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -22,12 +22,10 @@ public abstract class AzAnimator { // Holds animation controllers. private final AzAnimationControllerContainer animationControllerContainer; - // Processes animations. - private final AzAnimationProcessor animationProcessor; + public boolean reloadAnimations; protected AzAnimator(AzAnimatorConfig config) { this.animationControllerContainer = new AzAnimationControllerContainer<>(); - this.animationProcessor = new AzAnimationProcessor<>(this); var boneCache = new AzBoneCache(); var timer = new AzAnimationTimer(config); @@ -54,7 +52,15 @@ public void animate(T animatable) { var shouldRun = !minecraft.isPaused() || config.shouldPlayAnimationsWhileGamePaused(); if (shouldRun && !boneCache.isEmpty()) { - animationProcessor.update(reusableContext); + + for (var controller : animationControllerContainer.getAll()) { + controller.update(reusableContext); + } + + this.reloadAnimations = false; + + boneCache.update(reusableContext); + timer.finishFirstTick(); } setCustomAnimations(animatable); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAbstractAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAbstractAnimationController.java new file mode 100644 index 000000000..29c33e7eb --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAbstractAnimationController.java @@ -0,0 +1,66 @@ +package mod.azure.azurelib.core2.animation.controller; + +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; + +// TODO: This will eventually be usable in common-side code once animations are moved from assets to data. +public class AzAbstractAnimationController { + + private final String name; + + private final Map triggerableAnimations; + + protected AzRawAnimation currentRawAnimation; + + protected AzRawAnimation triggeredAnimation; + + protected AzAbstractAnimationController( + String name, + Map triggerableAnimations + ) { + this.name = name; + this.triggerableAnimations = triggerableAnimations; + this.triggeredAnimation = null; + } + + public String getName() { + return name; + } + + public @Nullable AzRawAnimation getTriggerableAnimationOrNull(String animationName) { + return triggerableAnimations.get(animationName); + } + + /** + * Attempt to trigger an animation from the list of {@link AzAbstractAnimationController#triggerableAnimations + * triggerable animations} this controller contains. + * + * @param animName The name of the animation to trigger + * @return Whether the controller triggered an animation or not + */ + public boolean tryTriggerAnimation(String animName) { + var anim = getTriggerableAnimationOrNull(animName); + + if (anim == null) { + return false; + } + + this.triggeredAnimation = anim; + + return true; + } + + /** + * Checks whether the last animation that was playing on this controller has finished or not.
      + * This will return true if the controller has had an animation set previously, and it has finished playing and + * isn't going to loop or proceed to another animation.
      + * + * @return Whether the previous animation finished or not + */ + public boolean hasAnimationFinished() { + return currentRawAnimation != null; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 5a79e1db5..73e02a291 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -5,7 +5,6 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; @@ -15,7 +14,6 @@ import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core2.animation.AzAnimationContext; import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameManager; import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPauseState; @@ -33,7 +31,7 @@ * instruction markers. Each controller can only play a single animation at a time - for example you may have one * controller to animate walking, one to control attacks, one to control size, etc. */ -public class AzAnimationController { +public class AzAnimationController extends AzAbstractAnimationController { protected static final Logger LOGGER = LoggerFactory.getLogger(AzAnimationController.class); @@ -41,8 +39,6 @@ public static AzAnimationControllerBuilder builder(AzAnimator animator return new AzAnimationControllerBuilder<>(animator, name); } - private final String name; - private final ToDoubleFunction animationSpeedModifier; private final AzAnimationQueue animationQueue; @@ -51,7 +47,7 @@ public static AzAnimationControllerBuilder builder(AzAnimator animator private final AzAnimator animator; - private final AzBoneAnimationQueueCache boneAnimationQueueCache; + private final AzBoneAnimationQueueCache boneAnimationQueueCache; private final AzBoneSnapshotCache boneSnapshotCache; @@ -61,18 +57,12 @@ public static AzAnimationControllerBuilder builder(AzAnimator animator private final double transitionLength; - private final Map triggerableAnimations; - protected AzQueuedAnimation currentAnimation; - protected AzRawAnimation currentRawAnimation; - protected boolean needsAnimationReload = false; protected double tickOffset; - protected AzRawAnimation triggeredAnimation = null; - /** * Instantiates a new {@code AnimationController}.
      * @@ -89,17 +79,22 @@ public static AzAnimationControllerBuilder builder(AzAnimator animator Function overrideEasingTypeFunction, Map triggerableAnimations ) { - this.name = name; + super(name, triggerableAnimations); + this.animator = animator; this.transitionLength = transitionTickTime; this.animationSpeedModifier = animationSpeedModifier; this.overrideEasingTypeFunction = overrideEasingTypeFunction; - this.triggerableAnimations = triggerableAnimations; this.animationQueue = new AzAnimationQueue(); - this.boneAnimationQueueCache = new AzBoneAnimationQueueCache(animator.context().boneCache()); + this.boneAnimationQueueCache = new AzBoneAnimationQueueCache<>(animator.context().boneCache()); this.boneSnapshotCache = new AzBoneSnapshotCache(); - this.keyFrameManager = new AzKeyFrameManager<>(this, boneAnimationQueueCache, keyFrameCallbacks); + this.keyFrameManager = new AzKeyFrameManager<>( + this, + boneAnimationQueueCache, + boneSnapshotCache, + keyFrameCallbacks + ); var stateHolder = new AzAnimationControllerStateMachine.StateHolder( new AzAnimationPlayState<>(), @@ -111,6 +106,11 @@ public static AzAnimationControllerBuilder builder(AzAnimator animator this.stateMachine = new AzAnimationControllerStateMachine<>(stateHolder, this, animator.context()); } + @Override + public boolean hasAnimationFinished() { + return super.hasAnimationFinished() && stateMachine.isStopped(); + } + /** * Computes the current animation speed modifier.
      * This modifier defines the relative speed in which animations will be played based on the current state of the @@ -122,17 +122,6 @@ public double computeAnimationSpeed(T animatable) { return animationSpeedModifier.applyAsDouble(animatable); } - /** - * Marks the controller as needing to reset its animation and state the next time - * {@link AzAnimationController#setAnimation(T, AzRawAnimation)} is called.
      - *
      - * Use this if you have a {@link AzRawAnimation} with multiple stages and you want it to start again from the first - * stage, or if you want to reset the currently playing animation to the start - */ - public void forceAnimationReset() { - this.needsAnimationReload = true; - } - /** * Populates the animation queue with the given {@link AzRawAnimation} * @@ -175,7 +164,6 @@ public List tryCreateAnimationQueue(T animatable, AzRawAnimat public void setAnimation(T animatable, AzRawAnimation rawAnimation) { if (rawAnimation == null || rawAnimation.getAnimationStages().isEmpty()) { stateMachine.stop(); - return; } @@ -188,7 +176,6 @@ public void setAnimation(T animatable, AzRawAnimation rawAnimation) { this.currentRawAnimation = rawAnimation; stateMachine.transition(); this.needsAnimationReload = false; - return; } @@ -196,27 +183,15 @@ public void setAnimation(T animatable, AzRawAnimation rawAnimation) { } } - /** - * Attempt to trigger an animation from the list of {@link AzAnimationController#triggerableAnimations triggerable - * animations} this controller contains. - * - * @param animName The name of the animation to trigger - * @return Whether the controller triggered an animation or not - */ + @Override public boolean tryTriggerAnimation(String animName) { - var anim = triggerableAnimations.get(animName); - - if (anim == null) { - return false; - } + var triggeredSuccessfully = super.tryTriggerAnimation(animName); - this.triggeredAnimation = anim; - - if (stateMachine.isStopped()) { + if (triggeredSuccessfully && stateMachine.isStopped()) { stateMachine.transition(); } - return true; + return triggeredSuccessfully; } /** @@ -244,6 +219,10 @@ private void handleAnimationState(T animatable) { * logic. */ public void update(AzAnimationContext context) { + if (animator.reloadAnimations) { + forceAnimationReset(); + } + var animatable = context.animatable(); var timer = context.timer(); var seekTime = timer.getAnimTime(); @@ -265,6 +244,20 @@ public void update(AzAnimationContext context) { this.needsAnimationReload = false; stateMachine.getContext().adjustedTick = adjustTick(animatable, seekTime); } + + boneAnimationQueueCache.update(context, overrideEasingTypeFunction); + } + + /** + * Marks the controller as needing to reset its animation and state the next time + * {@link AzAnimationController#setAnimation(T, AzRawAnimation)} is called.
      + *
      + * Use this if you have a {@link AzRawAnimation} with multiple stages and you want it to start again from the first + * stage, or if you want to reset the currently playing animation to the start + */ + private void forceAnimationReset() { + this.needsAnimationReload = true; + boneAnimationQueueCache.clear(); } /** @@ -293,14 +286,10 @@ public AzAnimationQueue getAnimationQueue() { return animationQueue; } - public AzBoneAnimationQueueCache getBoneAnimationQueueCache() { + public AzBoneAnimationQueueCache getBoneAnimationQueueCache() { return boneAnimationQueueCache; } - public Collection getBoneAnimationQueues() { - return boneAnimationQueueCache.values(); - } - public AzBoneSnapshotCache getBoneSnapshotCache() { return boneSnapshotCache; } @@ -313,14 +302,6 @@ public AzKeyFrameManager getKeyFrameManager() { return keyFrameManager; } - public String getName() { - return name; - } - - public Function getOverrideEasingTypeFunction() { - return overrideEasingTypeFunction; - } - public AzAnimationControllerStateMachine getStateMachine() { return stateMachine; } @@ -329,17 +310,6 @@ public double getTransitionLength() { return transitionLength; } - /** - * Checks whether the last animation that was playing on this controller has finished or not.
      - * This will return true if the controller has had an animation set previously, and it has finished playing and - * isn't going to loop or proceed to another animation.
      - * - * @return Whether the previous animation finished or not - */ - public boolean hasAnimationFinished() { - return currentRawAnimation != null && stateMachine.isStopped(); - } - public void setShouldResetTick(boolean shouldResetTick) { stateMachine.setShouldResetTick(shouldResetTick); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java index b854aded6..2211e3315 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java @@ -5,11 +5,15 @@ import java.util.Collection; import java.util.Map; +import java.util.function.Function; +import mod.azure.azurelib.core.animation.EasingType; +import mod.azure.azurelib.core2.animation.AzAnimationContext; +import mod.azure.azurelib.core2.animation.AzBoneAnimationUpdateUtil; import mod.azure.azurelib.core2.animation.cache.AzBoneCache; import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; -public class AzBoneAnimationQueueCache { +public class AzBoneAnimationQueueCache { private final Map boneAnimationQueues; @@ -20,6 +24,22 @@ public AzBoneAnimationQueueCache(AzBoneCache boneCache) { this.boneCache = boneCache; } + public void update(AzAnimationContext context, Function overridingEasingTypeFunction) { + var animatable = context.animatable(); + var boneSnapshots = boneCache.getBoneSnapshotsByName(); + var easingType = overridingEasingTypeFunction.apply(animatable); + + for (var boneAnimation : boneAnimationQueues.values()) { + var bone = boneAnimation.bone(); + var snapshot = boneSnapshots.get(bone.getName()); + var initialSnapshot = bone.getInitialAzSnapshot(); + + AzBoneAnimationUpdateUtil.updateRotations(boneAnimation, bone, easingType, initialSnapshot, snapshot); + AzBoneAnimationUpdateUtil.updatePositions(boneAnimation, bone, easingType, snapshot); + AzBoneAnimationUpdateUtil.updateScale(boneAnimation, bone, easingType, snapshot); + } + } + public Collection values() { return boneAnimationQueues.values(); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java index 3c96e2941..71d84d21a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java @@ -2,6 +2,7 @@ import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; +import mod.azure.azurelib.core2.animation.controller.AzBoneSnapshotCache; public class AzKeyFrameManager { @@ -12,10 +13,15 @@ public class AzKeyFrameManager { public AzKeyFrameManager( AzAnimationController animationController, AzBoneAnimationQueueCache boneAnimationQueueCache, + AzBoneSnapshotCache boneSnapshotCache, AzKeyFrameCallbacks keyFrameCallbacks ) { this.keyFrameCallbackHandler = new AzKeyFrameCallbackHandler<>(animationController, keyFrameCallbacks); - this.keyFrameProcessor = new AzKeyFrameProcessor<>(animationController, boneAnimationQueueCache); + this.keyFrameProcessor = new AzKeyFrameProcessor<>( + animationController, + boneAnimationQueueCache, + boneSnapshotCache + ); } public AzKeyFrameCallbackHandler keyFrameCallbackHandler() { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java index 5d725cb2b..390670799 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java @@ -14,20 +14,25 @@ import mod.azure.azurelib.core.object.Axis; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; +import mod.azure.azurelib.core2.animation.controller.AzBoneSnapshotCache; import mod.azure.azurelib.core2.model.AzBone; public class AzKeyFrameProcessor { private final AzAnimationController animationController; - private final AzBoneAnimationQueueCache boneAnimationQueueCache; + private final AzBoneAnimationQueueCache boneAnimationQueueCache; + + private final AzBoneSnapshotCache boneSnapshotCache; public AzKeyFrameProcessor( AzAnimationController animationController, - AzBoneAnimationQueueCache boneAnimationQueueCache + AzBoneAnimationQueueCache boneAnimationQueueCache, + AzBoneSnapshotCache boneSnapshotCache ) { this.animationController = animationController; this.boneAnimationQueueCache = boneAnimationQueueCache; + this.boneSnapshotCache = boneSnapshotCache; } /** @@ -171,7 +176,6 @@ public void transitionFromCurrentAnimation( boolean crashWhenCantFindBone, double adjustedTick ) { - var boneSnapshotCache = animationController.getBoneSnapshotCache(); var currentAnimation = animationController.getCurrentAnimation(); var transitionLength = animationController.getTransitionLength(); From 1e13f0eeb69aca5deebcfe27e5489be13a524318 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sun, 15 Dec 2024 16:31:21 -0500 Subject: [PATCH 093/224] Split up AzKeyFrameProcessor.java. Signed-off-by: = --- .../keyframe/AzAbstractKeyFrameExecutor.java | 76 +++++ .../keyframe/AzKeyFrameExecutor.java | 152 +++++++++ .../keyframe/AzKeyFrameManager.java | 17 +- .../keyframe/AzKeyFrameProcessor.java | 297 ------------------ .../keyframe/AzKeyFrameTransitioner.java | 120 +++++++ .../state/impl/AzAnimationPlayState.java | 4 +- .../impl/AzAnimationTransitionState.java | 5 +- 7 files changed, 365 insertions(+), 306 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAbstractKeyFrameExecutor.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameTransitioner.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAbstractKeyFrameExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAbstractKeyFrameExecutor.java new file mode 100644 index 000000000..eed08259d --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAbstractKeyFrameExecutor.java @@ -0,0 +1,76 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import java.util.List; + +import mod.azure.azurelib.core.keyframe.AnimationPoint; +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.keyframe.KeyframeLocation; +import mod.azure.azurelib.core.math.Constant; +import mod.azure.azurelib.core.math.IValue; +import mod.azure.azurelib.core.object.Axis; + +public class AzAbstractKeyFrameExecutor { + + protected AzAbstractKeyFrameExecutor() { + + } + + /** + * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} + */ + protected AnimationPoint getAnimationPointAtTick( + List> frames, + double tick, + boolean isRotation, + Axis axis + ) { + var location = getCurrentKeyFrameLocation(frames, tick); + var currentFrame = location.keyframe(); + var startValue = currentFrame.startValue().get(); + var endValue = currentFrame.endValue().get(); + + if (isRotation) { + if (!(currentFrame.startValue() instanceof Constant)) { + startValue = Math.toRadians(startValue); + + if (axis == Axis.X || axis == Axis.Y) { + startValue *= -1; + } + } + + if (!(currentFrame.endValue() instanceof Constant)) { + endValue = Math.toRadians(endValue); + + if (axis == Axis.X || axis == Axis.Y) { + endValue *= -1; + } + } + } + + return new AnimationPoint(currentFrame, location.startTick(), currentFrame.length(), startValue, endValue); + } + + /** + * Returns the {@link Keyframe} relevant to the current tick time + * + * @param frames The list of {@code KeyFrames} to filter through + * @param ageInTicks The current tick time + * @return A new {@code KeyFrameLocation} containing the current {@code KeyFrame} and the tick time used to find it + */ + protected KeyframeLocation> getCurrentKeyFrameLocation( + List> frames, + double ageInTicks + ) { + var totalFrameTime = 0.0; + + for (var frame : frames) { + totalFrameTime += frame.length(); + + if (totalFrameTime > ageInTicks) { + return new KeyframeLocation<>(frame, (ageInTicks - (totalFrameTime - frame.length()))); + } + } + + return new KeyframeLocation<>(frames.get(frames.size() - 1), ageInTicks); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java new file mode 100644 index 000000000..7c13bf975 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java @@ -0,0 +1,152 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import java.util.NoSuchElementException; + +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.keyframe.KeyframeStack; +import mod.azure.azurelib.core.math.IValue; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.MolangQueries; +import mod.azure.azurelib.core.object.Axis; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; + +public class AzKeyFrameExecutor extends AzAbstractKeyFrameExecutor { + + private final AzAnimationController animationController; + + private final AzBoneAnimationQueueCache boneAnimationQueueCache; + + public AzKeyFrameExecutor( + AzAnimationController animationController, + AzBoneAnimationQueueCache boneAnimationQueueCache + ) { + this.animationController = animationController; + this.boneAnimationQueueCache = boneAnimationQueueCache; + } + + /** + * Handle the current animation's state modifications and translations + * + * @param seekTime The lerped tick (current tick + partial tick) + * @param crashWhenCantFindBone Whether the controller should throw an exception when unable to find the required + * bone, or continue with the remaining bones + */ + public void execute(T animatable, double seekTime, boolean crashWhenCantFindBone) { + var animationQueue = animationController.getAnimationQueue(); + var currentAnimation = animationController.getCurrentAnimation(); + var keyFrameCallbackHandler = animationController.getKeyFrameManager().keyFrameCallbackHandler(); + var stateMachine = animationController.getStateMachine(); + var stateMachineContext = stateMachine.getContext(); + var transitionLength = animationController.getTransitionLength(); + + var hasAnimationFinished = stateMachineContext.adjustedTick >= currentAnimation.animation().length(); + + // TODO: This logic REALLY doesn't belong here... it belongs in the play state. + if (hasAnimationFinished) { + var shouldPlayAgain = currentAnimation.loopType() + .shouldPlayAgain(animatable, animationController, currentAnimation.animation()); + + if (shouldPlayAgain) { + var isNotPaused = !stateMachine.isPaused(); + + if (isNotPaused) { + animationController.setShouldResetTick(true); + + stateMachineContext.adjustedTick = animationController.adjustTick(animatable, seekTime); + keyFrameCallbackHandler.reset(); + } + } else { + var nextAnimation = animationQueue.peek(); + + keyFrameCallbackHandler.reset(); + + if (nextAnimation == null) { + stateMachine.stop(); + + return; + } else { + stateMachine.transition(); + animationController.setShouldResetTick(true); + animationController.setCurrentAnimation(nextAnimation); + } + } + } + + final double finalAdjustedTick = stateMachineContext.adjustedTick; + + MolangParser.INSTANCE.setMemoizedValue(MolangQueries.ANIM_TIME, () -> finalAdjustedTick / 20d); + + for (var boneAnimation : currentAnimation.animation().boneAnimations()) { + var boneAnimationQueue = boneAnimationQueueCache.getOrNull(boneAnimation.boneName()); + + if (boneAnimationQueue == null) { + if (crashWhenCantFindBone) + throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); + + continue; + } + + var rotationKeyFrames = boneAnimation.rotationKeyFrames(); + var positionKeyFrames = boneAnimation.positionKeyFrames(); + var scaleKeyFrames = boneAnimation.scaleKeyFrames(); + var adjustedTick = stateMachineContext.adjustedTick; + + updateRotation(rotationKeyFrames, boneAnimationQueue, adjustedTick); + updatePosition(positionKeyFrames, boneAnimationQueue, adjustedTick); + updateScale(scaleKeyFrames, boneAnimationQueue, adjustedTick); + } + + stateMachineContext.adjustedTick += transitionLength; + + keyFrameCallbackHandler.handle(animatable, stateMachineContext.adjustedTick); + } + + private void updateRotation( + KeyframeStack> keyFrames, + AzBoneAnimationQueue queue, + double adjustedTick + ) { + if (keyFrames.xKeyframes().isEmpty()) { + return; + } + + var x = getAnimationPointAtTick(keyFrames.xKeyframes(), adjustedTick, true, Axis.X); + var y = getAnimationPointAtTick(keyFrames.yKeyframes(), adjustedTick, true, Axis.Y); + var z = getAnimationPointAtTick(keyFrames.zKeyframes(), adjustedTick, true, Axis.Z); + + queue.addRotations(x, y, z); + } + + private void updatePosition( + KeyframeStack> keyFrames, + AzBoneAnimationQueue queue, + double adjustedTick + ) { + if (keyFrames.xKeyframes().isEmpty()) { + return; + } + + var x = getAnimationPointAtTick(keyFrames.xKeyframes(), adjustedTick, false, Axis.X); + var y = getAnimationPointAtTick(keyFrames.yKeyframes(), adjustedTick, false, Axis.Y); + var z = getAnimationPointAtTick(keyFrames.zKeyframes(), adjustedTick, false, Axis.Z); + + queue.addPositions(x, y, z); + } + + private void updateScale( + KeyframeStack> keyFrames, + AzBoneAnimationQueue queue, + double adjustedTick + ) { + if (keyFrames.xKeyframes().isEmpty()) { + return; + } + + var x = getAnimationPointAtTick(keyFrames.xKeyframes(), adjustedTick, false, Axis.X); + var y = getAnimationPointAtTick(keyFrames.yKeyframes(), adjustedTick, false, Axis.Y); + var z = getAnimationPointAtTick(keyFrames.zKeyframes(), adjustedTick, false, Axis.Z); + + queue.addScales(x, y, z); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java index 71d84d21a..28f8132d2 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameManager.java @@ -8,16 +8,19 @@ public class AzKeyFrameManager { private final AzKeyFrameCallbackHandler keyFrameCallbackHandler; - private final AzKeyFrameProcessor keyFrameProcessor; + private final AzKeyFrameExecutor keyFrameExecutor; + + private final AzKeyFrameTransitioner keyFrameTransitioner; public AzKeyFrameManager( AzAnimationController animationController, - AzBoneAnimationQueueCache boneAnimationQueueCache, + AzBoneAnimationQueueCache boneAnimationQueueCache, AzBoneSnapshotCache boneSnapshotCache, AzKeyFrameCallbacks keyFrameCallbacks ) { this.keyFrameCallbackHandler = new AzKeyFrameCallbackHandler<>(animationController, keyFrameCallbacks); - this.keyFrameProcessor = new AzKeyFrameProcessor<>( + this.keyFrameExecutor = new AzKeyFrameExecutor<>(animationController, boneAnimationQueueCache); + this.keyFrameTransitioner = new AzKeyFrameTransitioner<>( animationController, boneAnimationQueueCache, boneSnapshotCache @@ -28,7 +31,11 @@ public AzKeyFrameCallbackHandler keyFrameCallbackHandler() { return keyFrameCallbackHandler; } - public AzKeyFrameProcessor getKeyFrameProcessor() { - return keyFrameProcessor; + public AzKeyFrameExecutor getKeyFrameExecutor() { + return keyFrameExecutor; + } + + public AzKeyFrameTransitioner getKeyFrameTransitioner() { + return keyFrameTransitioner; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java deleted file mode 100644 index 390670799..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameProcessor.java +++ /dev/null @@ -1,297 +0,0 @@ -package mod.azure.azurelib.core2.animation.controller.keyframe; - -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; - -import mod.azure.azurelib.core.keyframe.AnimationPoint; -import mod.azure.azurelib.core.keyframe.Keyframe; -import mod.azure.azurelib.core.keyframe.KeyframeLocation; -import mod.azure.azurelib.core.math.Constant; -import mod.azure.azurelib.core.math.IValue; -import mod.azure.azurelib.core.molang.MolangParser; -import mod.azure.azurelib.core.molang.MolangQueries; -import mod.azure.azurelib.core.object.Axis; -import mod.azure.azurelib.core2.animation.controller.AzAnimationController; -import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; -import mod.azure.azurelib.core2.animation.controller.AzBoneSnapshotCache; -import mod.azure.azurelib.core2.model.AzBone; - -public class AzKeyFrameProcessor { - - private final AzAnimationController animationController; - - private final AzBoneAnimationQueueCache boneAnimationQueueCache; - - private final AzBoneSnapshotCache boneSnapshotCache; - - public AzKeyFrameProcessor( - AzAnimationController animationController, - AzBoneAnimationQueueCache boneAnimationQueueCache, - AzBoneSnapshotCache boneSnapshotCache - ) { - this.animationController = animationController; - this.boneAnimationQueueCache = boneAnimationQueueCache; - this.boneSnapshotCache = boneSnapshotCache; - } - - /** - * Handle the current animation's state modifications and translations - * - * @param seekTime The lerped tick (current tick + partial tick) - * @param crashWhenCantFindBone Whether the controller should throw an exception when unable to find the required - * bone, or continue with the remaining bones - */ - public void runCurrentAnimation(T animatable, double seekTime, boolean crashWhenCantFindBone) { - var animationQueue = animationController.getAnimationQueue(); - var currentAnimation = animationController.getCurrentAnimation(); - var keyFrameCallbackHandler = animationController.getKeyFrameManager().keyFrameCallbackHandler(); - var stateMachine = animationController.getStateMachine(); - var stateMachineContext = stateMachine.getContext(); - var transitionLength = animationController.getTransitionLength(); - - if (stateMachineContext.adjustedTick >= currentAnimation.animation().length()) { - if ( - currentAnimation.loopType() - .shouldPlayAgain(animatable, animationController, currentAnimation.animation()) - ) { - if (!stateMachine.isPaused()) { - animationController.setShouldResetTick(true); - - stateMachineContext.adjustedTick = animationController.adjustTick(animatable, seekTime); - keyFrameCallbackHandler.reset(); - } - } else { - var nextAnimation = animationQueue.peek(); - - keyFrameCallbackHandler.reset(); - - if (nextAnimation == null) { - stateMachine.stop(); - - return; - } else { - stateMachine.transition(); - animationController.setShouldResetTick(true); - animationController.setCurrentAnimation(nextAnimation); - } - } - } - - final double finalAdjustedTick = stateMachineContext.adjustedTick; - - MolangParser.INSTANCE.setMemoizedValue(MolangQueries.ANIM_TIME, () -> finalAdjustedTick / 20d); - - for (var boneAnimation : currentAnimation.animation().boneAnimations()) { - var boneAnimationQueue = boneAnimationQueueCache.getOrNull(boneAnimation.boneName()); - - if (boneAnimationQueue == null) { - if (crashWhenCantFindBone) - throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); - - continue; - } - - var rotationKeyFrames = boneAnimation.rotationKeyFrames(); - var positionKeyFrames = boneAnimation.positionKeyFrames(); - var scaleKeyFrames = boneAnimation.scaleKeyFrames(); - - if (!rotationKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addRotations( - getAnimationPointAtTick( - rotationKeyFrames.xKeyframes(), - stateMachineContext.adjustedTick, - true, - Axis.X - ), - getAnimationPointAtTick( - rotationKeyFrames.yKeyframes(), - stateMachineContext.adjustedTick, - true, - Axis.Y - ), - getAnimationPointAtTick( - rotationKeyFrames.zKeyframes(), - stateMachineContext.adjustedTick, - true, - Axis.Z - ) - ); - } - - if (!positionKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addPositions( - getAnimationPointAtTick( - positionKeyFrames.xKeyframes(), - stateMachineContext.adjustedTick, - false, - Axis.X - ), - getAnimationPointAtTick( - positionKeyFrames.yKeyframes(), - stateMachineContext.adjustedTick, - false, - Axis.Y - ), - getAnimationPointAtTick( - positionKeyFrames.zKeyframes(), - stateMachineContext.adjustedTick, - false, - Axis.Z - ) - ); - } - - if (!scaleKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addScales( - getAnimationPointAtTick( - scaleKeyFrames.xKeyframes(), - stateMachineContext.adjustedTick, - false, - Axis.X - ), - getAnimationPointAtTick( - scaleKeyFrames.yKeyframes(), - stateMachineContext.adjustedTick, - false, - Axis.Y - ), - getAnimationPointAtTick( - scaleKeyFrames.zKeyframes(), - stateMachineContext.adjustedTick, - false, - Axis.Z - ) - ); - } - } - - stateMachineContext.adjustedTick += transitionLength; - - keyFrameCallbackHandler.handle(animatable, stateMachineContext.adjustedTick); - } - - public void transitionFromCurrentAnimation( - Map bones, - boolean crashWhenCantFindBone, - double adjustedTick - ) { - var currentAnimation = animationController.getCurrentAnimation(); - var transitionLength = animationController.getTransitionLength(); - - MolangParser.INSTANCE.setValue(MolangQueries.ANIM_TIME, () -> 0); - - for (var boneAnimation : currentAnimation.animation().boneAnimations()) { - var boneAnimationQueue = boneAnimationQueueCache.getOrNull(boneAnimation.boneName()); - var boneSnapshot = boneSnapshotCache.getOrNull(boneAnimation.boneName()); - var bone = bones.get(boneAnimation.boneName()); - - if (bone == null) { - if (crashWhenCantFindBone) - throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); - - continue; - } - - var rotationKeyFrames = boneAnimation.rotationKeyFrames(); - var positionKeyFrames = boneAnimation.positionKeyFrames(); - var scaleKeyFrames = boneAnimation.scaleKeyFrames(); - - if (!rotationKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addNextRotation( - null, - adjustedTick, - transitionLength, - boneSnapshot, - bone.getInitialAzSnapshot(), - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) - ); - } - - if (!positionKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addNextPosition( - null, - adjustedTick, - transitionLength, - boneSnapshot, - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) - ); - } - - if (!scaleKeyFrames.xKeyframes().isEmpty()) { - boneAnimationQueue.addNextScale( - null, - adjustedTick, - transitionLength, - boneSnapshot, - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) - ); - } - } - } - - /** - * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} - */ - private AnimationPoint getAnimationPointAtTick( - List> frames, - double tick, - boolean isRotation, - Axis axis - ) { - var location = getCurrentKeyFrameLocation(frames, tick); - var currentFrame = location.keyframe(); - var startValue = currentFrame.startValue().get(); - var endValue = currentFrame.endValue().get(); - - if (isRotation) { - if (!(currentFrame.startValue() instanceof Constant)) { - startValue = Math.toRadians(startValue); - - if (axis == Axis.X || axis == Axis.Y) { - startValue *= -1; - } - } - - if (!(currentFrame.endValue() instanceof Constant)) { - endValue = Math.toRadians(endValue); - - if (axis == Axis.X || axis == Axis.Y) { - endValue *= -1; - } - } - } - - return new AnimationPoint(currentFrame, location.startTick(), currentFrame.length(), startValue, endValue); - } - - /** - * Returns the {@link Keyframe} relevant to the current tick time - * - * @param frames The list of {@code KeyFrames} to filter through - * @param ageInTicks The current tick time - * @return A new {@code KeyFrameLocation} containing the current {@code KeyFrame} and the tick time used to find it - */ - protected KeyframeLocation> getCurrentKeyFrameLocation( - List> frames, - double ageInTicks - ) { - var totalFrameTime = 0.0; - - for (var frame : frames) { - totalFrameTime += frame.length(); - - if (totalFrameTime > ageInTicks) { - return new KeyframeLocation<>(frame, (ageInTicks - (totalFrameTime - frame.length()))); - } - } - - return new KeyframeLocation<>(frames.get(frames.size() - 1), ageInTicks); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameTransitioner.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameTransitioner.java new file mode 100644 index 000000000..eaa300fc8 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameTransitioner.java @@ -0,0 +1,120 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import java.util.Map; +import java.util.NoSuchElementException; + +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.keyframe.KeyframeStack; +import mod.azure.azurelib.core.math.IValue; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.MolangQueries; +import mod.azure.azurelib.core.object.Axis; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; +import mod.azure.azurelib.core2.animation.controller.AzBoneSnapshotCache; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; + +public class AzKeyFrameTransitioner extends AzAbstractKeyFrameExecutor { + + private final AzAnimationController animationController; + + private final AzBoneAnimationQueueCache boneAnimationQueueCache; + + private final AzBoneSnapshotCache boneSnapshotCache; + + public AzKeyFrameTransitioner( + AzAnimationController animationController, + AzBoneAnimationQueueCache boneAnimationQueueCache, + AzBoneSnapshotCache boneSnapshotCache + ) { + this.animationController = animationController; + this.boneAnimationQueueCache = boneAnimationQueueCache; + this.boneSnapshotCache = boneSnapshotCache; + } + + public void transition(Map bones, boolean crashWhenCantFindBone, double adjustedTick) { + var currentAnimation = animationController.getCurrentAnimation(); + var transitionLength = animationController.getTransitionLength(); + + MolangParser.INSTANCE.setValue(MolangQueries.ANIM_TIME, () -> 0); + + for (var boneAnimation : currentAnimation.animation().boneAnimations()) { + var bone = bones.get(boneAnimation.boneName()); + + if (bone == null) { + if (crashWhenCantFindBone) + throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); + + continue; + } + + var queue = boneAnimationQueueCache.getOrNull(boneAnimation.boneName()); + var snapshot = boneSnapshotCache.getOrNull(boneAnimation.boneName()); + + var rotationKeyFrames = boneAnimation.rotationKeyFrames(); + var positionKeyFrames = boneAnimation.positionKeyFrames(); + var scaleKeyFrames = boneAnimation.scaleKeyFrames(); + + transitionRotation(adjustedTick, rotationKeyFrames, queue, transitionLength, snapshot, bone); + transitionPosition(adjustedTick, positionKeyFrames, queue, transitionLength, snapshot); + transitionScale(adjustedTick, scaleKeyFrames, queue, transitionLength, snapshot); + } + } + + private void transitionRotation( + double adjustedTick, + KeyframeStack> keyFrames, + AzBoneAnimationQueue queue, + double transitionLength, + AzBoneSnapshot snapshot, + AzBone bone + ) { + if (keyFrames.xKeyframes().isEmpty()) { + return; + } + + var initialSnapshot = bone.getInitialAzSnapshot(); + var x = getAnimationPointAtTick(keyFrames.xKeyframes(), 0, true, Axis.X); + var y = getAnimationPointAtTick(keyFrames.yKeyframes(), 0, true, Axis.Y); + var z = getAnimationPointAtTick(keyFrames.zKeyframes(), 0, true, Axis.Z); + + queue.addNextRotation(null, adjustedTick, transitionLength, snapshot, initialSnapshot, x, y, z); + } + + private void transitionPosition( + double adjustedTick, + KeyframeStack> keyFrames, + AzBoneAnimationQueue queue, + double transitionLength, + AzBoneSnapshot snapshot + ) { + if (keyFrames.xKeyframes().isEmpty()) { + return; + } + + var x = getAnimationPointAtTick(keyFrames.xKeyframes(), 0, false, Axis.X); + var y = getAnimationPointAtTick(keyFrames.yKeyframes(), 0, false, Axis.Y); + var z = getAnimationPointAtTick(keyFrames.zKeyframes(), 0, false, Axis.Z); + + queue.addNextPosition(null, adjustedTick, transitionLength, snapshot, x, y, z); + } + + private void transitionScale( + double adjustedTick, + KeyframeStack> keyFrames, + AzBoneAnimationQueue queue, + double transitionLength, + AzBoneSnapshot snapshot + ) { + if (keyFrames.xKeyframes().isEmpty()) { + return; + } + + var x = getAnimationPointAtTick(keyFrames.xKeyframes(), 0, false, Axis.X); + var y = getAnimationPointAtTick(keyFrames.yKeyframes(), 0, false, Axis.Y); + var z = getAnimationPointAtTick(keyFrames.zKeyframes(), 0, false, Axis.Z); + + queue.addNextScale(null, adjustedTick, transitionLength, snapshot, x, y, z); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java index af71bde89..a2a7fa5ff 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java @@ -15,7 +15,7 @@ public void onEnter(AzAnimationControllerStateMachine.Context context) { @Override public void onUpdate(AzAnimationControllerStateMachine.Context context) { var controller = context.getAnimationController(); - var keyFrameProcessor = controller.getKeyFrameManager().getKeyFrameProcessor(); + var keyFrameExecutor = controller.getKeyFrameManager().getKeyFrameExecutor(); var animContext = context.getAnimationContext(); var timer = animContext.timer(); @@ -24,7 +24,7 @@ public void onUpdate(AzAnimationControllerStateMachine.Context context) { var crashWhenCantFindBone = animContext.config().crashIfBoneMissing(); // Run the current animation. - keyFrameProcessor.runCurrentAnimation(animatable, animTime, crashWhenCantFindBone); + keyFrameExecutor.execute(animatable, animTime, crashWhenCantFindBone); } @Override diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java index 8c21310a0..8e494f3ce 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java @@ -54,8 +54,9 @@ public void onUpdate(AzAnimationControllerStateMachine.Context context) { if (controller.getCurrentAnimation() != null) { var bones = boneCache.getBakedModel().getBonesByName(); var crashWhenCantFindBone = animContext.config().crashIfBoneMissing(); - var keyFrameProcessor = controller.getKeyFrameManager().getKeyFrameProcessor(); - keyFrameProcessor.transitionFromCurrentAnimation(bones, crashWhenCantFindBone, context.adjustedTick); + var keyFrameTransitioner = controller.getKeyFrameManager().getKeyFrameTransitioner(); + + keyFrameTransitioner.transition(bones, crashWhenCantFindBone, context.adjustedTick); } } From 6d05a20856bd55ed4c6e028e071ee27800a672fe Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sun, 15 Dec 2024 17:20:49 -0500 Subject: [PATCH 094/224] Moved state management out of AzKeyFrameExecutor and into AzAnimationPlayState. Signed-off-by: = --- .../keyframe/AzAbstractKeyFrameExecutor.java | 4 +- .../keyframe/AzKeyFrameExecutor.java | 44 ++------- .../state/impl/AzAnimationPlayState.java | 96 +++++++++++++++++-- .../impl/AzAnimationTransitionState.java | 6 +- 4 files changed, 97 insertions(+), 53 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAbstractKeyFrameExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAbstractKeyFrameExecutor.java index eed08259d..48a878f5b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAbstractKeyFrameExecutor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAbstractKeyFrameExecutor.java @@ -11,9 +11,7 @@ public class AzAbstractKeyFrameExecutor { - protected AzAbstractKeyFrameExecutor() { - - } + protected AzAbstractKeyFrameExecutor() {} /** * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java index 7c13bf975..927222f84 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java @@ -1,5 +1,7 @@ package mod.azure.azurelib.core2.animation.controller.keyframe; +import org.jetbrains.annotations.NotNull; + import java.util.NoSuchElementException; import mod.azure.azurelib.core.keyframe.Keyframe; @@ -10,6 +12,7 @@ import mod.azure.azurelib.core.object.Axis; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; public class AzKeyFrameExecutor extends AzAbstractKeyFrameExecutor { @@ -28,51 +31,15 @@ public AzKeyFrameExecutor( /** * Handle the current animation's state modifications and translations * - * @param seekTime The lerped tick (current tick + partial tick) * @param crashWhenCantFindBone Whether the controller should throw an exception when unable to find the required * bone, or continue with the remaining bones */ - public void execute(T animatable, double seekTime, boolean crashWhenCantFindBone) { - var animationQueue = animationController.getAnimationQueue(); - var currentAnimation = animationController.getCurrentAnimation(); + public void execute(@NotNull AzQueuedAnimation currentAnimation, T animatable, boolean crashWhenCantFindBone) { var keyFrameCallbackHandler = animationController.getKeyFrameManager().keyFrameCallbackHandler(); var stateMachine = animationController.getStateMachine(); var stateMachineContext = stateMachine.getContext(); var transitionLength = animationController.getTransitionLength(); - var hasAnimationFinished = stateMachineContext.adjustedTick >= currentAnimation.animation().length(); - - // TODO: This logic REALLY doesn't belong here... it belongs in the play state. - if (hasAnimationFinished) { - var shouldPlayAgain = currentAnimation.loopType() - .shouldPlayAgain(animatable, animationController, currentAnimation.animation()); - - if (shouldPlayAgain) { - var isNotPaused = !stateMachine.isPaused(); - - if (isNotPaused) { - animationController.setShouldResetTick(true); - - stateMachineContext.adjustedTick = animationController.adjustTick(animatable, seekTime); - keyFrameCallbackHandler.reset(); - } - } else { - var nextAnimation = animationQueue.peek(); - - keyFrameCallbackHandler.reset(); - - if (nextAnimation == null) { - stateMachine.stop(); - - return; - } else { - stateMachine.transition(); - animationController.setShouldResetTick(true); - animationController.setCurrentAnimation(nextAnimation); - } - } - } - final double finalAdjustedTick = stateMachineContext.adjustedTick; MolangParser.INSTANCE.setMemoizedValue(MolangQueries.ANIM_TIME, () -> finalAdjustedTick / 20d); @@ -81,8 +48,9 @@ public void execute(T animatable, double seekTime, boolean crashWhenCantFindBone var boneAnimationQueue = boneAnimationQueueCache.getOrNull(boneAnimation.boneName()); if (boneAnimationQueue == null) { - if (crashWhenCantFindBone) + if (crashWhenCantFindBone) { throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); + } continue; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java index a2a7fa5ff..ab8dd6ccd 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java @@ -2,6 +2,7 @@ import mod.azure.azurelib.core2.animation.controller.state.AzAnimationState; import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; public final class AzAnimationPlayState extends AzAnimationState { @@ -10,25 +11,102 @@ public AzAnimationPlayState() {} @Override public void onEnter(AzAnimationControllerStateMachine.Context context) { super.onEnter(context); + var controller = context.getAnimationController(); + var stateMachine = context.getStateMachine(); + var animContext = context.getAnimationContext(); + var animatable = animContext.animatable(); + var animTime = animContext.timer().getAnimTime(); + + stateMachine.setShouldResetTick(true); + context.adjustedTick = controller.adjustTick(animatable, animTime); } @Override public void onUpdate(AzAnimationControllerStateMachine.Context context) { var controller = context.getAnimationController(); - var keyFrameExecutor = controller.getKeyFrameManager().getKeyFrameExecutor(); - var animContext = context.getAnimationContext(); - var timer = animContext.timer(); + var currentAnimation = controller.getCurrentAnimation(); + + if (currentAnimation == null) { + // If the current animation is null, we should try to play the next animation. + tryPlayNextOrStop(context); + return; + } + // At this point we have an animation currently playing. We need to query if that animation has finished. + + var animContext = context.getAnimationContext(); var animatable = animContext.animatable(); - var animTime = timer.getAnimTime(); + var hasAnimationFinished = context.adjustedTick >= currentAnimation.animation().length(); + + if (hasAnimationFinished) { + tryPlayAgain(context, currentAnimation); + // Regardless of if we should play again, the animation has finished, so return. + return; + } + + // The animation is still running at this point, proceed with updating the bones according to keyframes. + + var keyFrameManager = controller.getKeyFrameManager(); + var keyFrameExecutor = keyFrameManager.getKeyFrameExecutor(); var crashWhenCantFindBone = animContext.config().crashIfBoneMissing(); - // Run the current animation. - keyFrameExecutor.execute(animatable, animTime, crashWhenCantFindBone); + keyFrameExecutor.execute(currentAnimation, animatable, crashWhenCantFindBone); } - @Override - public void onExit(AzAnimationControllerStateMachine.Context context) { - super.onExit(context); + private void tryPlayNextOrStop(AzAnimationControllerStateMachine.Context context) { + var controller = context.getAnimationController(); + var stateMachine = context.getStateMachine(); + var keyFrameManager = controller.getKeyFrameManager(); + var keyFrameCallbackHandler = keyFrameManager.keyFrameCallbackHandler(); + + keyFrameCallbackHandler.reset(); + + var animationQueue = controller.getAnimationQueue(); + var nextAnimation = animationQueue.peek(); + var canPlayNextSuccessfully = nextAnimation != null; + + if (!canPlayNextSuccessfully) { + // If we can't play the next animation for some reason, then there's nothing to play. + // So we should put the state machine in the 'stop' state. + stateMachine.stop(); + return; + } + + // If we can play the next animation successfully, then let's do that. + stateMachine.transition(); + controller.setShouldResetTick(true); + controller.setCurrentAnimation(nextAnimation); + } + + private void tryPlayAgain( + AzAnimationControllerStateMachine.Context context, + AzQueuedAnimation currentAnimation + ) { + var animatable = context.getAnimationContext().animatable(); + var controller = context.getAnimationController(); + + // If it has, we then need to see if the animation should play again. + var shouldPlayAgain = currentAnimation.loopType() + .shouldPlayAgain(animatable, controller, currentAnimation.animation()); + + if (shouldPlayAgain) { + // If it should play again, then we simply play the animation again. + playAgain(context); + } + } + + private void playAgain(AzAnimationControllerStateMachine.Context context) { + var controller = context.getAnimationController(); + var keyFrameManager = controller.getKeyFrameManager(); + var keyFrameCallbackHandler = keyFrameManager.keyFrameCallbackHandler(); + + var animContext = context.getAnimationContext(); + var timer = animContext.timer(); + var animatable = animContext.animatable(); + var animTime = timer.getAnimTime(); + + controller.setShouldResetTick(true); + context.adjustedTick = controller.adjustTick(animatable, animTime); + keyFrameCallbackHandler.reset(); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java index 8e494f3ce..e2ab8087d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java @@ -43,11 +43,11 @@ public void onUpdate(AzAnimationControllerStateMachine.Context context) { boneSnapshotCache.put(controller.getCurrentAnimation(), snapshots.values()); } - if (context.adjustedTick >= controller.getTransitionLength()) { + var hasFinishedTransitioning = context.adjustedTick >= controller.getTransitionLength(); + + if (hasFinishedTransitioning) { // If we've exceeded the amount of time we should be transitioning, then switch to play state. - stateMachine.setShouldResetTick(true); stateMachine.play(); - context.adjustedTick = controller.adjustTick(animatable, animTime); return; } From c58e93a13020a7378726762c8875ae8e6a2788d9 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sun, 15 Dec 2024 18:47:28 -0500 Subject: [PATCH 095/224] Cleaned up pause/stop states. Signed-off-by: = --- .../controller/state/impl/AzAnimationPauseState.java | 10 ---------- .../controller/state/impl/AzAnimationStopState.java | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java index 87bcf5b5a..7f6d44667 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java @@ -7,18 +7,8 @@ public final class AzAnimationPauseState extends AzAnimationState { public AzAnimationPauseState() {} - @Override - public void onEnter(AzAnimationControllerStateMachine.Context context) { - super.onEnter(context); - } - @Override public void onUpdate(AzAnimationControllerStateMachine.Context context) { // Pause state does not need to do anything. } - - @Override - public void onExit(AzAnimationControllerStateMachine.Context context) { - super.onExit(context); - } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationStopState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationStopState.java index e2c81211c..189fd2b79 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationStopState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationStopState.java @@ -7,18 +7,8 @@ public final class AzAnimationStopState extends AzAnimationState { public AzAnimationStopState() {} - @Override - public void onEnter(AzAnimationControllerStateMachine.Context context) { - super.onEnter(context); - } - @Override public void onUpdate(AzAnimationControllerStateMachine.Context context) { // Stop state does not need to do anything. } - - @Override - public void onExit(AzAnimationControllerStateMachine.Context context) { - super.onExit(context); - } } From bd4ced0e33b89487a16ed3ef4c7d7239b5b6367c Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sun, 15 Dec 2024 18:47:49 -0500 Subject: [PATCH 096/224] createContext should be protected. Signed-off-by: = --- .../main/java/mod/azure/azurelib/core2/util/StateMachine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/StateMachine.java b/common/src/main/java/mod/azure/azurelib/core2/util/StateMachine.java index 99522a2e5..0ce384fad 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/util/StateMachine.java +++ b/common/src/main/java/mod/azure/azurelib/core2/util/StateMachine.java @@ -11,7 +11,7 @@ public StateMachine(T initialState) { this.reusableContext = createContext(); } - public abstract C createContext(); + protected abstract C createContext(); public void update(C context) { state.onUpdate(context); From db8b7462c55cea6d00a97fa8413adff8b66bab6f Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sun, 15 Dec 2024 19:15:13 -0500 Subject: [PATCH 097/224] Implemented AzAnimationControllerTimer. Signed-off-by: = --- .../controller/AzAnimationController.java | 45 +++++------------ .../AzAnimationControllerTimer.java | 49 +++++++++++++++++++ .../keyframe/AzKeyFrameExecutor.java | 12 ++--- .../state/impl/AzAnimationPlayState.java | 21 +++----- .../impl/AzAnimationTransitionState.java | 23 +++------ .../AzAnimationControllerStateMachine.java | 12 ----- 6 files changed, 81 insertions(+), 81 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerTimer.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 73e02a291..06cb0eac7 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -39,6 +39,8 @@ public static AzAnimationControllerBuilder builder(AzAnimator animator return new AzAnimationControllerBuilder<>(animator, name); } + private final AzAnimationControllerTimer controllerTimer; + private final ToDoubleFunction animationSpeedModifier; private final AzAnimationQueue animationQueue; @@ -61,8 +63,6 @@ public static AzAnimationControllerBuilder builder(AzAnimator animator protected boolean needsAnimationReload = false; - protected double tickOffset; - /** * Instantiates a new {@code AnimationController}.
      * @@ -82,6 +82,7 @@ public static AzAnimationControllerBuilder builder(AzAnimator animator super(name, triggerableAnimations); this.animator = animator; + this.controllerTimer = new AzAnimationControllerTimer<>(this); this.transitionLength = transitionTickTime; this.animationSpeedModifier = animationSpeedModifier; this.overrideEasingTypeFunction = overrideEasingTypeFunction; @@ -224,13 +225,11 @@ public void update(AzAnimationContext context) { } var animatable = context.animatable(); - var timer = context.timer(); - var seekTime = timer.getAnimTime(); handleAnimationState(animatable); // Adjust the tick before making any updates. - stateMachine.getContext().adjustedTick = adjustTick(animatable, seekTime); + controllerTimer.update(); // Run state machine updates. stateMachine.update(); @@ -242,7 +241,7 @@ public void update(AzAnimationContext context) { } this.needsAnimationReload = false; - stateMachine.getContext().adjustedTick = adjustTick(animatable, seekTime); + controllerTimer.update(); } boneAnimationQueueCache.update(context, overrideEasingTypeFunction); @@ -260,32 +259,14 @@ private void forceAnimationReset() { boneAnimationQueueCache.clear(); } - /** - * Adjust a tick value depending on the controller's current state and speed modifier.
      - * Is used when starting a new animation, transitioning, and a few other key areas - * - * @param tick The currently used tick value - * @return 0 if {@link AzAnimationControllerStateMachine#shouldResetTick()} is set to false, or a - * {@link AzAnimationController#animationSpeedModifier} modified value otherwise - */ - public double adjustTick(T animatable, double tick) { - if (!stateMachine.shouldResetTick()) { - return animationSpeedModifier.applyAsDouble(animatable) * Math.max(tick - tickOffset, 0); - } - - if (!stateMachine.isStopped()) { - this.tickOffset = tick; - } - - stateMachine.setShouldResetTick(false); - - return 0; - } - public AzAnimationQueue getAnimationQueue() { return animationQueue; } + public ToDoubleFunction getAnimationSpeedModifier() { + return animationSpeedModifier; + } + public AzBoneAnimationQueueCache getBoneAnimationQueueCache() { return boneAnimationQueueCache; } @@ -294,6 +275,10 @@ public AzBoneSnapshotCache getBoneSnapshotCache() { return boneSnapshotCache; } + public AzAnimationControllerTimer getControllerTimer() { + return controllerTimer; + } + public @Nullable AzQueuedAnimation getCurrentAnimation() { return currentAnimation; } @@ -310,10 +295,6 @@ public double getTransitionLength() { return transitionLength; } - public void setShouldResetTick(boolean shouldResetTick) { - stateMachine.setShouldResetTick(shouldResetTick); - } - public void setCurrentAnimation(AzQueuedAnimation currentAnimation) { this.currentAnimation = currentAnimation; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerTimer.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerTimer.java new file mode 100644 index 000000000..436d2dda4 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerTimer.java @@ -0,0 +1,49 @@ +package mod.azure.azurelib.core2.animation.controller; + +public class AzAnimationControllerTimer { + + private final AzAnimationController animationController; + + private double adjustedTick; + + private double tickOffset; + + public AzAnimationControllerTimer(AzAnimationController animationController) { + this.animationController = animationController; + } + + /** + * Adjust a tick value depending on the controller's current state and speed modifier.
      + * Is used when starting a new animation, transitioning, and a few other key areas + */ + public void update() { + var modifier = animationController.getAnimationSpeedModifier(); + var stateMachine = animationController.getStateMachine(); + var animContext = stateMachine.getContext().getAnimationContext(); + var animatable = animContext.animatable(); + var tick = animContext.timer().getAnimTime(); + + var animationSpeed = modifier.applyAsDouble(animatable); + adjustedTick = animationSpeed * Math.max(tick - tickOffset, 0); + } + + public void reset() { + var stateMachine = animationController.getStateMachine(); + var animContext = stateMachine.getContext().getAnimationContext(); + var tick = animContext.timer().getAnimTime(); + + if (!stateMachine.isStopped()) { + this.tickOffset = tick; + } + + this.adjustedTick = 0; + } + + public double getAdjustedTick() { + return adjustedTick; + } + + public void addToAdjustedTick(double adjustedTick) { + this.adjustedTick += adjustedTick; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java index 927222f84..a06525fef 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyFrameExecutor.java @@ -36,11 +36,10 @@ public AzKeyFrameExecutor( */ public void execute(@NotNull AzQueuedAnimation currentAnimation, T animatable, boolean crashWhenCantFindBone) { var keyFrameCallbackHandler = animationController.getKeyFrameManager().keyFrameCallbackHandler(); - var stateMachine = animationController.getStateMachine(); - var stateMachineContext = stateMachine.getContext(); + var controllerTimer = animationController.getControllerTimer(); var transitionLength = animationController.getTransitionLength(); - final double finalAdjustedTick = stateMachineContext.adjustedTick; + final double finalAdjustedTick = controllerTimer.getAdjustedTick(); MolangParser.INSTANCE.setMemoizedValue(MolangQueries.ANIM_TIME, () -> finalAdjustedTick / 20d); @@ -58,16 +57,17 @@ public void execute(@NotNull AzQueuedAnimation currentAnimation, T animatable, b var rotationKeyFrames = boneAnimation.rotationKeyFrames(); var positionKeyFrames = boneAnimation.positionKeyFrames(); var scaleKeyFrames = boneAnimation.scaleKeyFrames(); - var adjustedTick = stateMachineContext.adjustedTick; + var adjustedTick = controllerTimer.getAdjustedTick(); updateRotation(rotationKeyFrames, boneAnimationQueue, adjustedTick); updatePosition(positionKeyFrames, boneAnimationQueue, adjustedTick); updateScale(scaleKeyFrames, boneAnimationQueue, adjustedTick); } - stateMachineContext.adjustedTick += transitionLength; + // TODO: Is this correct??? + controllerTimer.addToAdjustedTick(transitionLength); - keyFrameCallbackHandler.handle(animatable, stateMachineContext.adjustedTick); + keyFrameCallbackHandler.handle(animatable, controllerTimer.getAdjustedTick()); } private void updateRotation( diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java index ab8dd6ccd..2e3f4bfbb 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java @@ -12,18 +12,15 @@ public AzAnimationPlayState() {} public void onEnter(AzAnimationControllerStateMachine.Context context) { super.onEnter(context); var controller = context.getAnimationController(); - var stateMachine = context.getStateMachine(); - var animContext = context.getAnimationContext(); - var animatable = animContext.animatable(); - var animTime = animContext.timer().getAnimTime(); + var controllerTimer = controller.getControllerTimer(); - stateMachine.setShouldResetTick(true); - context.adjustedTick = controller.adjustTick(animatable, animTime); + controllerTimer.reset(); } @Override public void onUpdate(AzAnimationControllerStateMachine.Context context) { var controller = context.getAnimationController(); + var controllerTimer = controller.getControllerTimer(); var currentAnimation = controller.getCurrentAnimation(); if (currentAnimation == null) { @@ -36,7 +33,7 @@ public void onUpdate(AzAnimationControllerStateMachine.Context context) { var animContext = context.getAnimationContext(); var animatable = animContext.animatable(); - var hasAnimationFinished = context.adjustedTick >= currentAnimation.animation().length(); + var hasAnimationFinished = controllerTimer.getAdjustedTick() >= currentAnimation.animation().length(); if (hasAnimationFinished) { tryPlayAgain(context, currentAnimation); @@ -74,7 +71,6 @@ private void tryPlayNextOrStop(AzAnimationControllerStateMachine.Context cont // If we can play the next animation successfully, then let's do that. stateMachine.transition(); - controller.setShouldResetTick(true); controller.setCurrentAnimation(nextAnimation); } @@ -97,16 +93,11 @@ private void tryPlayAgain( private void playAgain(AzAnimationControllerStateMachine.Context context) { var controller = context.getAnimationController(); + var controllerTimer = controller.getControllerTimer(); var keyFrameManager = controller.getKeyFrameManager(); var keyFrameCallbackHandler = keyFrameManager.keyFrameCallbackHandler(); - var animContext = context.getAnimationContext(); - var timer = animContext.timer(); - var animatable = animContext.animatable(); - var animTime = timer.getAnimTime(); - - controller.setShouldResetTick(true); - context.adjustedTick = controller.adjustTick(animatable, animTime); + controllerTimer.reset(); keyFrameCallbackHandler.reset(); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java index e2ab8087d..ae685b6c1 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java @@ -10,26 +10,22 @@ public AzAnimationTransitionState() {} @Override public void onEnter(AzAnimationControllerStateMachine.Context context) { super.onEnter(context); - context.getStateMachine().setShouldResetTick(true); + var controller = context.getAnimationController(); + var controllerTimer = controller.getControllerTimer(); + controllerTimer.reset(); } @Override public void onUpdate(AzAnimationControllerStateMachine.Context context) { var controller = context.getAnimationController(); + var controllerTimer = controller.getControllerTimer(); var boneSnapshotCache = controller.getBoneSnapshotCache(); var animContext = context.getAnimationContext(); - var timer = animContext.timer(); - var animatable = animContext.animatable(); - var animTime = timer.getAnimTime(); var stateMachine = context.getStateMachine(); var boneCache = animContext.boneCache(); - if (stateMachine.shouldResetTick()) { - context.adjustedTick = controller.adjustTick(animatable, animTime); - } - - if (context.adjustedTick == 0 || stateMachine.isJustStarting()) { + if (controllerTimer.getAdjustedTick() == 0 || stateMachine.isJustStarting()) { controller.setCurrentAnimation(controller.getAnimationQueue().next()); controller.getKeyFrameManager().keyFrameCallbackHandler().reset(); @@ -43,7 +39,7 @@ public void onUpdate(AzAnimationControllerStateMachine.Context context) { boneSnapshotCache.put(controller.getCurrentAnimation(), snapshots.values()); } - var hasFinishedTransitioning = context.adjustedTick >= controller.getTransitionLength(); + var hasFinishedTransitioning = controllerTimer.getAdjustedTick() >= controller.getTransitionLength(); if (hasFinishedTransitioning) { // If we've exceeded the amount of time we should be transitioning, then switch to play state. @@ -56,12 +52,7 @@ public void onUpdate(AzAnimationControllerStateMachine.Context context) { var crashWhenCantFindBone = animContext.config().crashIfBoneMissing(); var keyFrameTransitioner = controller.getKeyFrameManager().getKeyFrameTransitioner(); - keyFrameTransitioner.transition(bones, crashWhenCantFindBone, context.adjustedTick); + keyFrameTransitioner.transition(bones, crashWhenCantFindBone, controllerTimer.getAdjustedTick()); } } - - @Override - public void onExit(AzAnimationControllerStateMachine.Context context) { - super.onExit(context); - } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java index c2d5e1670..5b87066e2 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java @@ -16,8 +16,6 @@ public class AzAnimationControllerStateMachine extends StateMachine stateHolder, AzAnimationController animationController, @@ -76,14 +74,6 @@ public boolean isTransitioning() { return getState() == stateHolder.transitionState; } - public void setShouldResetTick(boolean shouldResetTick) { - this.shouldResetTick = shouldResetTick; - } - - public boolean shouldResetTick() { - return shouldResetTick; - } - public boolean isJustStarting() { return isJustStarting; } @@ -107,8 +97,6 @@ public static class Context implements StateMachineContext { private AzAnimationControllerStateMachine stateMachine; - public double adjustedTick; - private Context() {} public AzAnimationContext getAnimationContext() { From 958f29708fed538a5cda64f0ce46459bf75257b5 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sun, 15 Dec 2024 19:51:33 -0500 Subject: [PATCH 098/224] alpha13 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 85d36b323..653466653 100644 --- a/gradle.properties +++ b/gradle.properties @@ -51,5 +51,5 @@ mod_logo = azurelib.png mod_name = AzureLib mod_sources = https://github.com/AzureDoom/AzureLib mod_url = https://modrinth.com/mod/azurelib -version = 3.0.0-alpha12 +version = 3.0.0-alpha13 modrinth_id = 7zlUOZvb From 9c6c6db7dfa5f9966d829f0fc76b07a14c410a4d Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Mon, 16 Dec 2024 02:08:57 -0500 Subject: [PATCH 099/224] Refactored renderer pipelines to be cleaner. Signed-off-by: = --- .../core2/render/layer/AzRenderLayer.java | 40 +- .../render/pipeline/AzRendererPipeline.java | 493 +++--------------- .../pipeline/AzRendererPipelineContext.java | 150 ++++++ .../impl/AzEntityRendererPipeline.java | 258 ++------- .../impl/AzEntityRendererPipelineContext.java | 47 ++ 5 files changed, 326 insertions(+), 662 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipelineContext.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java index aebfa564f..1d180b284 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java @@ -1,13 +1,11 @@ package mod.azure.azurelib.core2.render.layer; -import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; /** * Render layer base class for rendering additional layers of effects or textures over an existing model at runtime.
      @@ -22,33 +20,13 @@ public AzRenderLayer() {} * {@link AzRendererPipeline#preRender} has been called.
      * This allows for RenderLayers to perform pre-render manipulations such as hiding or showing bones */ - public abstract void preRender( - PoseStack poseStack, - T animatable, - AzBakedModel bakedModel, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay - ); + public abstract void preRender(AzRendererPipelineContext context); /** * This is the method that is actually called by the render for your render layer to function.
      * This is called after the animatable has been rendered, but before supplementary rendering like nametags. */ - public abstract void render( - PoseStack poseStack, - T animatable, - AzBakedModel bakedModel, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay - ); + public abstract void render(AzRendererPipelineContext context); /** * This method is called by the {@link AzRendererPipeline} for each bone being rendered.
      @@ -62,15 +40,5 @@ public abstract void render( * If you do use it, and you render something that changes the {@link VertexConsumer buffer}, you need to * reset it back to the previous buffer using {@link MultiBufferSource#getBuffer} before ending the method */ - public abstract void renderForBone( - PoseStack poseStack, - T animatable, - AzBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay - ); + public abstract void renderForBone(AzRendererPipelineContext context, AzBone bone); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index 702f593bd..dee609ae2 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -4,7 +4,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,26 +19,21 @@ import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core.object.Color; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; public abstract class AzRendererPipeline { - protected abstract @NotNull ResourceLocation getTextureLocation(@NotNull T animatable); + private final AzRendererPipelineContext context; - /** - * Gets the {@link RenderType} to render the given animatable with.
      - * Uses the {@link RenderType#entityCutoutNoCull} {@code RenderType} by default.
      - * Override this to change the way a model will render (such as translucent models, etc) - */ - public abstract RenderType getDefaultRenderType( - T animatable, - ResourceLocation texture, - @Nullable MultiBufferSource bufferSource, - float partialTick - ); + protected AzRendererPipeline() { + this.context = createContext(this); + } + + protected abstract AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline); + + protected abstract @NotNull ResourceLocation getTextureLocation(@NotNull T animatable); /** * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this @@ -50,35 +44,6 @@ public abstract RenderType getDefaultRenderType( */ protected abstract void updateAnimatedTextureFrame(T animatable); - /** - * Create and fire the relevant {@code CompileLayers} event hook for this renderer - */ - protected abstract void fireCompileRenderLayersEvent(); - - /** - * Create and fire the relevant {@code Pre-Render} event hook for this renderer.
      - * - * @return Whether the renderer should proceed based on the cancellation state of the event - */ - protected abstract boolean firePreRenderEvent( - PoseStack poseStack, - AzBakedModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight - ); - - /** - * Create and fire the relevant {@code Post-Render} event hook for this renderer - */ - protected abstract void firePostRenderEvent( - PoseStack poseStack, - AzBakedModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight - ); - /** * Initial access point for rendering. It all begins here.
      * All AzureLib renderers should immediately defer their respective default {@code render} calls to this, for @@ -95,96 +60,24 @@ public void render( float partialTick, int packedLight ) { + context.populate(animatable, model, bufferSource, packedLight, partialTick, poseStack, renderType, buffer); poseStack.pushPose(); - var renderColor = getRenderColor(animatable, partialTick, packedLight).argbInt(); - var packedOverlay = getPackedOverlay(animatable, 0, partialTick); - - if (renderType == null) { - renderType = getDefaultRenderType(animatable, getTextureLocation(animatable), bufferSource, partialTick); - } + preRender(context, false); - if (buffer == null) { - buffer = bufferSource.getBuffer(renderType); - } - - preRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - false, - partialTick, - packedLight, - packedOverlay, - renderColor - ); - - if (firePreRenderEvent(poseStack, model, bufferSource, partialTick, packedLight)) { - preApplyRenderLayers( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - packedLight, - packedLight, - packedOverlay - ); - actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - false, - partialTick, - packedLight, - packedOverlay, - renderColor - ); - applyRenderLayers( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - false, - partialTick, - packedLight, - packedOverlay, - renderColor - ); - firePostRenderEvent(poseStack, model, bufferSource, partialTick, packedLight); - } + // TODO: + // if (firePreRenderEvent(poseStack, model, bufferSource, partialTick, packedLight)) { + preApplyRenderLayers(context); + actuallyRender(context, false); + applyRenderLayers(context); + postRender(context, false); + // TODO: + // firePostRenderEvent(poseStack, model, bufferSource, partialTick, packedLight); + // } poseStack.popPose(); - renderFinal( - poseStack, - animatable, - model, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - renderColor - ); + renderFinal(context); doPostRenderCleanup(); } @@ -193,161 +86,60 @@ public void render( * Usually you'd use this for rendering alternate {@link RenderType} layers or for sub-model rendering whilst inside * a {@link AzRenderLayer} or similar */ - protected void reRender( - AzBakedModel model, - PoseStack poseStack, - MultiBufferSource bufferSource, - T animatable, - RenderType renderType, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour - ) { + protected void reRender(AzRendererPipelineContext context) { + var poseStack = context.poseStack(); poseStack.pushPose(); - preRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - true, - partialTick, - packedLight, - packedOverlay, - colour - ); - actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - true, - partialTick, - packedLight, - packedOverlay, - colour - ); - postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - true, - partialTick, - packedLight, - packedOverlay, - colour - ); + preRender(context, true); + actuallyRender(context, true); + postRender(context, true); poseStack.popPose(); } /** * The actual render method that sub-type renderers should override to handle their specific rendering tasks.
      */ - protected void actuallyRender( - PoseStack poseStack, - T animatable, - AzBakedModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour - ) { + protected void actuallyRender(AzRendererPipelineContext context, boolean isReRender) { + var animatable = context.animatable(); + var model = context.bakedModel(); + updateAnimatedTextureFrame(animatable); for (var bone : model.getTopLevelBones()) { - renderRecursively( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour - ); + renderRecursively(context, bone, isReRender); } } /** * Renders the provided {@link AzBone} and its associated child bones */ - protected void renderRecursively( - PoseStack poseStack, - T animatable, - AzBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour - ) { + protected void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + var poseStack = context.poseStack(); + poseStack.pushPose(); RenderUtils.prepMatrixForBone(poseStack, bone); - renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); + renderCubesOfBone(context, bone); if (!isReRender) { - applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); + applyRenderLayersForBone(context, bone); } - renderChildBones( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour - ); + renderChildBones(context, bone, isReRender); poseStack.popPose(); } /** * Renders the {@link GeoCube GeoCubes} associated with a given {@link AzBone} */ - protected void renderCubesOfBone( - PoseStack poseStack, - AzBone bone, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour - ) { - if (bone.isHidden()) + protected void renderCubesOfBone(AzRendererPipelineContext context, AzBone bone) { + if (bone.isHidden()) { return; + } + + var poseStack = context.poseStack(); - for (GeoCube cube : bone.getCubes()) { + for (var cube : bone.getCubes()) { poseStack.pushPose(); - renderCube(poseStack, cube, buffer, packedLight, packedOverlay, colour); + renderCube(context, cube); poseStack.popPose(); } } @@ -357,36 +149,12 @@ protected void renderCubesOfBone( * Note that this does not render the bone itself. That should be done through * {@link AzRendererPipeline#renderCubesOfBone} separately */ - protected void renderChildBones( - PoseStack poseStack, - T animatable, - AzBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour - ) { + protected void renderChildBones(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { if (bone.isHidingChildren()) return; for (var childBone : bone.getChildBones()) { - renderRecursively( - poseStack, - animatable, - childBone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour - ); + renderRecursively(context, childBone, isReRender); } } @@ -394,14 +162,9 @@ protected void renderChildBones( * Renders an individual {@link GeoCube}.
      * This tends to be called recursively from something like {@link AzRendererPipeline#renderCubesOfBone} */ - protected void renderCube( - PoseStack poseStack, - GeoCube cube, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour - ) { + protected void renderCube(AzRendererPipelineContext context, GeoCube cube) { + var poseStack = context.poseStack(); + RenderUtils.translateToPivotPoint(poseStack, cube); RenderUtils.rotateMatrixAroundCube(poseStack, cube); RenderUtils.translateAwayFromPivotPoint(poseStack, cube); @@ -409,15 +172,16 @@ protected void renderCube( Matrix3f normalisedPoseState = poseStack.last().normal(); Matrix4f poseState = new Matrix4f(poseStack.last().pose()); - for (GeoQuad quad : cube.quads()) { - if (quad == null) + for (var quad : cube.quads()) { + if (quad == null) { continue; + } // TODO: Optimize - Vector3f normal = normalisedPoseState.transform(new Vector3f(quad.normal())); + var normal = normalisedPoseState.transform(new Vector3f(quad.normal())); RenderUtils.fixInvertedFlatCube(cube, normal); - createVerticesOfQuad(quad, poseState, normal, buffer, packedLight, packedOverlay, colour); + createVerticesOfQuad(context, quad, poseState, normal); } } @@ -426,14 +190,16 @@ protected void renderCube( * rendering */ protected void createVerticesOfQuad( + AzRendererPipelineContext context, GeoQuad quad, Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + Vector3f normal ) { + var buffer = context.vertexConsumer(); + var color = context.renderColor(); + var packedOverlay = context.packedOverlay(); + var packedLight = context.packedLight(); + for (var vertex : quad.vertices()) { var position = vertex.position(); // TODO: Optimize @@ -443,7 +209,7 @@ protected void createVerticesOfQuad( vector4f.x(), vector4f.y(), vector4f.z(), - colour, + color, vertex.texU(), vertex.texV(), packedOverlay, @@ -459,29 +225,9 @@ protected void createVerticesOfQuad( * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their * {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#preRender pre-render} actions. */ - protected void preApplyRenderLayers( - PoseStack poseStack, - T animatable, - AzBakedModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay - ) { + protected void preApplyRenderLayers(AzRendererPipelineContext context) { for (var renderLayer : getRenderLayers()) { - renderLayer.preRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); + renderLayer.preRender(context); } } @@ -489,58 +235,18 @@ protected void preApplyRenderLayers( * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their * {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#renderForBone per-bone} render actions. */ - protected void applyRenderLayersForBone( - PoseStack poseStack, - T animatable, - AzBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay - ) { + protected void applyRenderLayersForBone(AzRendererPipelineContext context, AzBone bone) { for (var renderLayer : getRenderLayers()) { - renderLayer.renderForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); + renderLayer.renderForBone(context, bone); } } /** * Render the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer */ - protected void applyRenderLayers( - PoseStack poseStack, - T animatable, - AzBakedModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay - ) { + protected void applyRenderLayers(AzRendererPipelineContext context) { for (var renderLayer : getRenderLayers()) { - renderLayer.render( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); + renderLayer.render(context); } } @@ -549,51 +255,19 @@ protected void applyRenderLayers( * and translating.
      * {@link PoseStack} translations made here are kept until the end of the render process */ - protected void preRender( - PoseStack poseStack, - T animatable, - AzBakedModel model, - @Nullable MultiBufferSource bufferSource, - @Nullable VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour - ) {} + protected void preRender(AzRendererPipelineContext context, boolean isReRender) {} /** * Called after rendering the model to buffer. Post-render modifications should be performed here.
      * {@link PoseStack} transformations will be unused and lost once this method ends */ - protected void postRender( - PoseStack poseStack, - T animatable, - AzBakedModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour - ) {} + protected void postRender(AzRendererPipelineContext context, boolean isReRender) {} /** * Call after all other rendering work has taken place, including reverting the {@link PoseStack}'s state. This * method is not called in {@link AzRendererPipeline#reRender re-render} */ - protected void renderFinal( - PoseStack poseStack, - T animatable, - AzBakedModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour - ) {} + protected void renderFinal(AzRendererPipelineContext context) {} /** * Called after all render operations are completed and the render pass is considered functionally complete. @@ -610,38 +284,17 @@ protected void doPostRenderCleanup() {} * entities) */ protected void scaleModelForRender( + AzRendererPipelineContext context, float widthScale, float heightScale, - PoseStack poseStack, - T animatable, - AzBakedModel model, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay + boolean isReRender ) { if (!isReRender && (widthScale != 1 || heightScale != 1)) { + var poseStack = context.poseStack(); poseStack.scale(widthScale, heightScale, widthScale); } } - /** - * Gets a tint-applying color to render the given animatable with.
      - * Returns {@link Color#WHITE} by default - */ - protected Color getRenderColor(T animatable, float partialTick, int packedLight) { - return Color.WHITE; - } - - /** - * Gets a packed overlay coordinate pair for rendering.
      - * Mostly just used for the red tint when an entity is hurt, but can be used for other things like the - * {@link net.minecraft.world.entity.monster.Creeper} white tint when exploding. - */ - protected int getPackedOverlay(T animatable, float u, float partialTick) { - return OverlayTexture.NO_OVERLAY; - } - /** * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer */ diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java new file mode 100644 index 000000000..d60eb7c53 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java @@ -0,0 +1,150 @@ +package mod.azure.azurelib.core2.render.pipeline; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +import mod.azure.azurelib.core.object.Color; +import mod.azure.azurelib.core2.model.AzBakedModel; + +public abstract class AzRendererPipelineContext { + + private final AzRendererPipeline rendererPipeline; + + private T animatable; + + private AzBakedModel bakedModel; + + private MultiBufferSource multiBufferSource; + + private int packedLight; + + private int packedOverlay; + + private float partialTick; + + private PoseStack poseStack; + + private int renderColor; + + private @Nullable RenderType renderType; + + private VertexConsumer vertexConsumer; + + protected AzRendererPipelineContext(AzRendererPipeline rendererPipeline) { + this.rendererPipeline = rendererPipeline; + } + + public void populate( + T animatable, + AzBakedModel bakedModel, + MultiBufferSource multiBufferSource, + int packedLight, + float partialTick, + PoseStack poseStack, + RenderType renderType, + VertexConsumer vertexConsumer + ) { + this.animatable = animatable; + this.bakedModel = bakedModel; + this.multiBufferSource = multiBufferSource; + this.packedLight = packedLight; + this.packedOverlay = getPackedOverlay(animatable, 0, partialTick); + this.partialTick = partialTick; + this.poseStack = poseStack; + this.renderType = renderType; + this.vertexConsumer = vertexConsumer; + this.renderColor = getRenderColor(animatable, partialTick, packedLight).argbInt(); + + if (renderType == null) { + var textureLocation = rendererPipeline.getTextureLocation(animatable); + this.renderType = getDefaultRenderType(animatable, textureLocation, multiBufferSource, partialTick); + } + + Objects.requireNonNull(this.renderType); + + if (vertexConsumer == null) { + this.vertexConsumer = multiBufferSource.getBuffer(this.renderType); + } + } + + /** + * Gets the {@link RenderType} to render the given animatable with.
      + * Uses the {@link RenderType#entityCutoutNoCull} {@code RenderType} by default.
      + * Override this to change the way a model will render (such as translucent models, etc) + */ + public abstract @NotNull RenderType getDefaultRenderType( + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ); + + /** + * Gets a tint-applying color to render the given animatable with.
      + * Returns {@link Color#WHITE} by default + */ + protected Color getRenderColor(T animatable, float partialTick, int packedLight) { + return Color.WHITE; + } + + /** + * Gets a packed overlay coordinate pair for rendering.
      + * Mostly just used for the red tint when an entity is hurt, but can be used for other things like the + * {@link net.minecraft.world.entity.monster.Creeper} white tint when exploding. + */ + protected int getPackedOverlay(T animatable, float u, float partialTick) { + return OverlayTexture.NO_OVERLAY; + } + + public T animatable() { + return animatable; + } + + public AzBakedModel bakedModel() { + return bakedModel; + } + + public MultiBufferSource multiBufferSource() { + return multiBufferSource; + } + + public int packedLight() { + return packedLight; + } + + public int packedOverlay() { + return packedOverlay; + } + + public float partialTick() { + return partialTick; + } + + public PoseStack poseStack() { + return poseStack; + } + + public int renderColor() { + return renderColor; + } + + public @Nullable RenderType renderType() { + return renderType; + } + + public VertexConsumer vertexConsumer() { + return vertexConsumer; + } + + public void setVertexConsumer(VertexConsumer vertexConsumer) { + this.vertexConsumer = vertexConsumer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java index 2d6abad67..7dc8dbabb 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -2,13 +2,9 @@ import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.LivingEntityRenderer; -import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; @@ -17,17 +13,16 @@ import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Pose; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.render.entity.AzEntityLeashRenderUtil; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; public class AzEntityRendererPipeline extends AzRendererPipeline { @@ -42,18 +37,13 @@ public AzEntityRendererPipeline(AzEntityRenderer azEntityRenderer) { } @Override - protected @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { - return azEntityRenderer.getTextureLocation(animatable); + protected AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { + return new AzEntityRendererPipelineContext<>(this); } @Override - public RenderType getDefaultRenderType( - T animatable, - ResourceLocation texture, - @Nullable MultiBufferSource bufferSource, - float partialTick - ) { - return RenderType.entityCutoutNoCull(texture); + protected @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { + return azEntityRenderer.getTextureLocation(animatable); } /** @@ -77,30 +67,15 @@ public void updateAnimatedTextureFrame(T entity) { * {@link PoseStack} translations made here are kept until the end of the render process */ @Override - public void preRender( - PoseStack poseStack, - T animatable, - AzBakedModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour - ) { + public void preRender(AzRendererPipelineContext context, boolean isReRender) { + var poseStack = context.poseStack(); this.entityRenderTranslations = new Matrix4f(poseStack.last().pose()); scaleModelForRender( + context, this.azEntityRenderer.getScaleWidth(), this.azEntityRenderer.getScaleHeight(), - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + isReRender ); } @@ -110,19 +85,11 @@ public void preRender( * {@link AzEntityRendererPipeline#postRender} will be called directly after */ @Override - public void actuallyRender( - PoseStack poseStack, - T animatable, - AzBakedModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour - ) { + public void actuallyRender(AzRendererPipelineContext context, boolean isReRender) { + var animatable = context.animatable(); + var partialTick = context.partialTick(); + var poseStack = context.poseStack(); + poseStack.pushPose(); LivingEntity livingEntity = animatable instanceof LivingEntity entity ? entity : null; @@ -186,11 +153,13 @@ public void actuallyRender( ); limbSwing = livingEntity.walkAnimation.position() - livingEntity.walkAnimation.speed() * (1 - partialTick); - if (livingEntity.isBaby()) + if (livingEntity.isBaby()) { limbSwing *= 3f; + } - if (limbSwingAmount > 1f) + if (limbSwingAmount > 1f) { limbSwingAmount = 1f; + } } if (!isReRender) { @@ -225,19 +194,7 @@ public void actuallyRender( this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); if (!animatable.isInvisibleTo(Minecraft.getInstance().player)) { - AzEntityRendererPipeline.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour - ); + AzEntityRendererPipeline.super.actuallyRender(context, isReRender); } poseStack.popPose(); @@ -247,29 +204,11 @@ public void actuallyRender( * Render the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer */ @Override - public void applyRenderLayers( - PoseStack poseStack, - T animatable, - AzBakedModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay - ) { + public void applyRenderLayers(AzRendererPipelineContext context) { + var animatable = context.animatable(); + if (!animatable.isSpectator()) { - AzEntityRendererPipeline.super.applyRenderLayers( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); + AzEntityRendererPipeline.super.applyRenderLayers(context); } } @@ -277,19 +216,13 @@ public void applyRenderLayers( * Renders the provided {@link AzBone} and its associated child bones */ @Override - public void renderRecursively( - PoseStack poseStack, - T entity, - AzBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour - ) { + public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + var buffer = context.vertexConsumer(); + var bufferSource = context.multiBufferSource(); + var entity = context.animatable(); + var poseStack = context.poseStack(); + var renderType = context.renderType(); + poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); RenderUtils.translateToPivotPoint(poseStack, bone); @@ -311,113 +244,42 @@ public void renderRecursively( RenderUtils.translateAwayFromPivotPoint(poseStack, bone); - if (!isReRender && buffer instanceof BufferBuilder builder && !builder.building) - buffer = bufferSource.getBuffer(renderType); + if (!isReRender && buffer instanceof BufferBuilder builder && !builder.building) { + context.setVertexConsumer(bufferSource.getBuffer(renderType)); + } - renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); + renderCubesOfBone(context, bone); - if (!isReRender) - applyRenderLayersForBone( - poseStack, - entity, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); + if (!isReRender) { + applyRenderLayersForBone(context, bone); + } - renderChildBones( - poseStack, - entity, - bone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour - ); + renderChildBones(context, bone, isReRender); poseStack.popPose(); } @Override - public void renderFinal( - PoseStack poseStack, - T entity, - AzBakedModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour - ) { + public void renderFinal(AzRendererPipelineContext context) { + var bufferSource = context.multiBufferSource(); + var entity = context.animatable(); + var packedLight = context.packedLight(); + var partialTick = context.partialTick(); + var poseStack = context.poseStack(); + azEntityRenderer.superRender(entity, 0, partialTick, poseStack, bufferSource, packedLight); - if (entity instanceof Mob mob) { - var leashHolder = mob.getLeashHolder(); - - if (leashHolder != null) { - AzEntityLeashRenderUtil.renderLeash( - azEntityRenderer, - mob, - partialTick, - poseStack, - bufferSource, - leashHolder - ); - } + if (!(entity instanceof Mob mob)) { + return; } - } - /** - * Create and fire the relevant {@code CompileLayers} event hook for this renderer - */ - @Override - public void fireCompileRenderLayersEvent() { - // FIXME: - // Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireCompileEntityRenderLayers(geoEntityRenderer); - } + var leashHolder = mob.getLeashHolder(); - /** - * Create and fire the relevant {@code Pre-Render} event hook for this renderer.
      - * - * @return Whether the renderer should proceed based on the cancellation state of the event - */ - @Override - public boolean firePreRenderEvent( - PoseStack poseStack, - AzBakedModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight - ) { - // FIXME: - return true; - // return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPreRender(geoEntityRenderer, poseStack, model, - // bufferSource, partialTick, packedLight); - } + if (leashHolder == null) { + return; + } - /** - * Create and fire the relevant {@code Post-Render} event hook for this renderer - */ - @Override - public void firePostRenderEvent( - PoseStack poseStack, - AzBakedModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight - ) { - // FIXME: - // Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPostRender(geoEntityRenderer, poseStack, model, - // bufferSource, partialTick, packedLight); + AzEntityLeashRenderUtil.renderLeash(azEntityRenderer, mob, partialTick, poseStack, bufferSource, leashHolder); } /** @@ -495,20 +357,4 @@ public boolean isShaking(T entity) { return entity.isFullyFrozen(); } - /** - * Gets a packed overlay coordinate pair for rendering.
      - * Mostly just used for the red tint when an entity is hurt, but can be used for other things like the - * {@link net.minecraft.world.entity.monster.Creeper} white tint when exploding. - */ - @Override - public int getPackedOverlay(T entity, float u, float partialTick) { - if (!(entity instanceof LivingEntity livingEntity)) { - return OverlayTexture.NO_OVERLAY; - } - - return OverlayTexture.pack( - OverlayTexture.u(u), - OverlayTexture.v(livingEntity.hurtTime > 0 || livingEntity.deathTime > 0) - ); - } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipelineContext.java new file mode 100644 index 000000000..d0bb6bb08 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipelineContext.java @@ -0,0 +1,47 @@ +package mod.azure.azurelib.core2.render.pipeline.impl; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; + +public class AzEntityRendererPipelineContext extends AzRendererPipelineContext { + + public AzEntityRendererPipelineContext(AzRendererPipeline rendererPipeline) { + super(rendererPipeline); + } + + @Override + public @NotNull RenderType getDefaultRenderType( + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ) { + return RenderType.entityCutoutNoCull(texture); + } + + /** + * Gets a packed overlay coordinate pair for rendering.
      + * Mostly just used for the red tint when an entity is hurt, but can be used for other things like the + * {@link net.minecraft.world.entity.monster.Creeper} white tint when exploding. + */ + @Override + public int getPackedOverlay(T entity, float u, float partialTick) { + if (!(entity instanceof LivingEntity livingEntity)) { + return OverlayTexture.NO_OVERLAY; + } + + return OverlayTexture.pack( + OverlayTexture.u(u), + OverlayTexture.v(livingEntity.hurtTime > 0 || livingEntity.deathTime > 0) + ); + } +} From 34436ab907e5be36f5211fddb99e2ba29386dfb6 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Mon, 16 Dec 2024 03:20:17 -0500 Subject: [PATCH 100/224] Ported item rendering to rewritten render/pipeline code. Signed-off-by: = --- .../core2/animation/impl/AzItemAnimator.java | 13 + .../core2/render/entity/AzEntityRenderer.java | 12 +- .../core2/render/item/AzItemRenderer.java | 268 ++++++++++++++++++ .../render/pipeline/AzRendererPipeline.java | 4 + .../impl/AzEntityRendererPipeline.java | 24 +- .../pipeline/impl/AzItemRendererPipeline.java | 129 +++++++++ .../impl/AzItemRendererPipelineContext.java | 29 ++ .../azurelib/models/item/az_pistol.json | 96 +++++++ .../azurelib/fabric/FabricAzureLibMod.java | 6 + .../fabric/core2/example/items/AzPistol.java | 93 ++++++ .../core2/example/items/AzPistolRender.java | 28 ++ 11 files changed, 684 insertions(+), 18 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java create mode 100644 common/src/main/resources/assets/azurelib/models/item/az_pistol.json create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRender.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java new file mode 100644 index 000000000..59352efe9 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java @@ -0,0 +1,13 @@ +package mod.azure.azurelib.core2.animation.impl; + +import net.minecraft.world.item.Item; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; + +public abstract class AzItemAnimator extends AzAnimator { + + protected AzItemAnimator(AzAnimatorConfig config) { + super(config); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 28839bb51..ec4d749f7 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -22,20 +22,20 @@ public abstract class AzEntityRenderer extends EntityRenderer { - private float scaleWidth = 1; + private final AzEntityRendererPipeline rendererPipeline; - private float scaleHeight = 1; + private final List> renderLayers; - private final AzEntityRendererPipeline azEntityRendererPipeline; + private float scaleWidth = 1; - private final List> renderLayers; + private float scaleHeight = 1; @Nullable private AzEntityAnimator reusedAzEntityAnimator; protected AzEntityRenderer(EntityRendererProvider.Context context) { super(context); - this.azEntityRendererPipeline = new AzEntityRendererPipeline<>(this); + this.rendererPipeline = new AzEntityRendererPipeline<>(this); this.renderLayers = new ObjectArrayList<>(); } @@ -72,7 +72,7 @@ public void render( reusedAzEntityAnimator = cachedEntityAnimator; // Execute the render pipeline. - azEntityRendererPipeline.render( + rendererPipeline.render( poseStack, azBakedModel, entity, diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java new file mode 100644 index 000000000..82335de5f --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -0,0 +1,268 @@ +package mod.azure.azurelib.core2.render.item; + +import com.mojang.blaze3d.platform.Lighting; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.geom.EntityModelSet; +import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import mod.azure.azurelib.core2.render.pipeline.impl.AzItemRendererPipeline; + +public abstract class AzItemRenderer extends BlockEntityWithoutLevelRenderer { + + private final AzItemRendererPipeline rendererPipeline; + + private final List> renderLayers; + + protected float scaleWidth = 1; + + protected float scaleHeight = 1; + + protected boolean useEntityGuiLighting = false; + + @Nullable + private AzItemAnimator reusedAzItemAnimator; + + protected AzItemRenderer() { + this(Minecraft.getInstance().getBlockEntityRenderDispatcher(), Minecraft.getInstance().getEntityModels()); + } + + protected AzItemRenderer(BlockEntityRenderDispatcher dispatcher, EntityModelSet modelSet) { + super(dispatcher, modelSet); + this.rendererPipeline = new AzItemRendererPipeline<>(this); + this.renderLayers = new ObjectArrayList<>(); + } + + protected abstract @NotNull ResourceLocation getModelLocation(T item); + + public abstract @NotNull ResourceLocation getTextureLocation(T item); + + @Override + public void renderByItem( + ItemStack stack, + @NotNull ItemDisplayContext transformType, + @NotNull PoseStack poseStack, + @NotNull MultiBufferSource bufferSource, + int packedLight, + int packedOverlay + ) { + @SuppressWarnings("unchecked") + var animatable = (T) stack.getItem(); + var currentItemStack = stack; + // TODO: What was this used for? + var renderPerspective = transformType; + + var cachedEntityAnimator = provideAnimator(animatable); + var azBakedModel = provideBakedModel(animatable); + + if (cachedEntityAnimator != null && azBakedModel != null) { + cachedEntityAnimator.setActiveModel(azBakedModel); + } + + // Point the renderer's current animator reference to the cached entity animator before rendering. + reusedAzItemAnimator = cachedEntityAnimator; + + if (transformType == ItemDisplayContext.GUI) { + renderInGui( + animatable, + azBakedModel, + currentItemStack, + transformType, + poseStack, + bufferSource, + packedLight, + packedOverlay + ); + } else { + var renderType = rendererPipeline.getContext() + .getDefaultRenderType( + animatable, + getTextureLocation(animatable), + bufferSource, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() + ); + var buffer = ItemRenderer.getFoilBufferDirect( + bufferSource, + renderType, + false, + // TODO: Why the null check here? + currentItemStack != null && currentItemStack.hasFoil() + ); + + rendererPipeline.render( + poseStack, + azBakedModel, + animatable, + bufferSource, + renderType, + buffer, + 0, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), + packedLight + ); + } + } + + /** + * Wrapper method to handle rendering the item in a GUI context (defined by + * {@link net.minecraft.world.item.ItemDisplayContext#GUI} normally).
      + * Just includes some additional required transformations and settings. + */ + protected void renderInGui( + T animatable, + AzBakedModel azBakedModel, + ItemStack currentItemStack, + ItemDisplayContext transformType, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight, + int packedOverlay + ) { + if (this.useEntityGuiLighting) { + Lighting.setupForEntityInInventory(); + } else { + Lighting.setupForFlatItems(); + } + MultiBufferSource.BufferSource defaultBufferSource = + bufferSource instanceof MultiBufferSource.BufferSource bufferSource2 + ? bufferSource2 + : Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); + RenderType renderType = rendererPipeline.getContext() + .getDefaultRenderType( + animatable, + getTextureLocation(animatable), + defaultBufferSource, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() + ); + VertexConsumer buffer = ItemRenderer.getFoilBufferDirect( + bufferSource, + renderType, + true, + currentItemStack != null && currentItemStack.hasFoil() + ); + + poseStack.pushPose(); + rendererPipeline.render( + poseStack, + azBakedModel, + animatable, + defaultBufferSource, + renderType, + buffer, + 0, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), + packedLight + ); + defaultBufferSource.endBatch(); + RenderSystem.enableDepthTest(); + Lighting.setupFor3DItems(); + poseStack.popPose(); + } + + protected @Nullable AzItemAnimator createAnimator() { + return null; + } + + protected @Nullable AzBakedModel provideBakedModel(@NotNull T item) { + var modelResourceLocation = getModelLocation(item); + return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); + } + + protected @Nullable AzItemAnimator provideAnimator(T item) { + // // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for + // the + // // item. + // var accessor = AzAnimatorAccessor.cast(item); + // // TODO: This won't work for items. Need to use an itemStack + id, instead. + // var cachedItemAnimator = (AzItemAnimator) accessor.getAnimatorOrNull(); + // + // if (cachedItemAnimator == null) { + // // If the cached animator is null, create a new one. We use a separate reference here just for some + // cachedItemAnimator = createAnimator(); + // + // if (cachedItemAnimator != null) { + // // If the new animator we created is not null, then register its controllers. + // cachedItemAnimator.registerControllers(cachedItemAnimator.getAnimationControllerContainer()); + // // Also cache the animator so that the next time we fetch the animator, it's ready for us. + // accessor.setAnimator(cachedItemAnimator); + // } + // } + // + // return cachedItemAnimator; + // FIXME: + return null; + } + + /** + * Mark this renderer so that it uses an alternate lighting scheme when rendering the item in GUI + *

      + * This can help with improperly lit 3d models + */ + public AzItemRenderer useAlternateGuiLighting() { + this.useEntityGuiLighting = true; + return this; + } + + /** + * Sets a scale override for this renderer, telling AzureLib to pre-scale the model + */ + public AzItemRenderer withScale(float scale) { + return withScale(scale, scale); + } + + /** + * Sets a scale override for this renderer, telling AzureLib to pre-scale the model + */ + public AzItemRenderer withScale(float scaleWidth, float scaleHeight) { + this.scaleWidth = scaleWidth; + this.scaleHeight = scaleHeight; + return this; + } + + /** + * Returns the list of registered {@link GeoRenderLayer GeoRenderLayers} for this renderer + */ + public List> getRenderLayers() { + return renderLayers; + } + + /** + * Adds a {@link GeoRenderLayer} to this renderer, to be called after the main model is rendered each frame + */ + public AzItemRenderer addRenderLayer(AzRenderLayer renderLayer) { + this.renderLayers.add(renderLayer); + return this; + } + + public @Nullable AzItemAnimator getAnimator() { + return reusedAzItemAnimator; + } + + public float getScaleHeight() { + return scaleHeight; + } + + public float getScaleWidth() { + return scaleWidth; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index dee609ae2..3189a1cf5 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -295,6 +295,10 @@ protected void scaleModelForRender( } } + public AzRendererPipelineContext getContext() { + return context; + } + /** * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer */ diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java index 7dc8dbabb..df897081e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -26,14 +26,14 @@ public class AzEntityRendererPipeline extends AzRendererPipeline { - private final AzEntityRenderer azEntityRenderer; + private final AzEntityRenderer entityRenderer; protected Matrix4f entityRenderTranslations = new Matrix4f(); protected Matrix4f modelRenderTranslations = new Matrix4f(); - public AzEntityRendererPipeline(AzEntityRenderer azEntityRenderer) { - this.azEntityRenderer = azEntityRenderer; + public AzEntityRendererPipeline(AzEntityRenderer entityRenderer) { + this.entityRenderer = entityRenderer; } @Override @@ -43,7 +43,7 @@ protected AzRendererPipelineContext createContext(AzRendererPipeline rende @Override protected @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { - return azEntityRenderer.getTextureLocation(animatable); + return entityRenderer.getTextureLocation(animatable); } /** @@ -73,8 +73,8 @@ public void preRender(AzRendererPipelineContext context, boolean isReRender) scaleModelForRender( context, - this.azEntityRenderer.getScaleWidth(), - this.azEntityRenderer.getScaleHeight(), + this.entityRenderer.getScaleWidth(), + this.entityRenderer.getScaleHeight(), isReRender ); } @@ -184,7 +184,7 @@ public void actuallyRender(AzRendererPipelineContext context, boolean isReRen // // this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); - var animator = azEntityRenderer.getAnimator(); + var animator = entityRenderer.getAnimator(); if (animator != null) { animator.animate(animatable); @@ -194,7 +194,7 @@ public void actuallyRender(AzRendererPipelineContext context, boolean isReRen this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); if (!animatable.isInvisibleTo(Minecraft.getInstance().player)) { - AzEntityRendererPipeline.super.actuallyRender(context, isReRender); + super.actuallyRender(context, isReRender); } poseStack.popPose(); @@ -208,7 +208,7 @@ public void applyRenderLayers(AzRendererPipelineContext context) { var animatable = context.animatable(); if (!animatable.isSpectator()) { - AzEntityRendererPipeline.super.applyRenderLayers(context); + super.applyRenderLayers(context); } } @@ -235,7 +235,7 @@ public void renderRecursively(AzRendererPipelineContext context, AzBone bone, bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, azEntityRenderer.getRenderOffset(entity, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, entityRenderer.getRenderOffset(entity, 1).toVector3f()) ); bone.setWorldSpaceMatrix( RenderUtils.translateMatrix(new Matrix4f(localMatrix), entity.position().toVector3f()) @@ -267,7 +267,7 @@ public void renderFinal(AzRendererPipelineContext context) { var partialTick = context.partialTick(); var poseStack = context.poseStack(); - azEntityRenderer.superRender(entity, 0, partialTick, poseStack, bufferSource, packedLight); + entityRenderer.superRender(entity, 0, partialTick, poseStack, bufferSource, packedLight); if (!(entity instanceof Mob mob)) { return; @@ -279,7 +279,7 @@ public void renderFinal(AzRendererPipelineContext context) { return; } - AzEntityLeashRenderUtil.renderLeash(azEntityRenderer, mob, partialTick, poseStack, bufferSource, leashHolder); + AzEntityLeashRenderUtil.renderLeash(entityRenderer, mob, partialTick, poseStack, bufferSource, leashHolder); } /** diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java new file mode 100644 index 000000000..bc0d89ac9 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java @@ -0,0 +1,129 @@ +package mod.azure.azurelib.core2.render.pipeline.impl; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; + +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.item.AzItemRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; + +public class AzItemRendererPipeline extends AzRendererPipeline { + + private final AzItemRenderer itemRenderer; + + protected Matrix4f itemRenderTranslations = new Matrix4f(); + + protected Matrix4f modelRenderTranslations = new Matrix4f(); + + public AzItemRendererPipeline(AzItemRenderer itemRenderer) { + this.itemRenderer = itemRenderer; + } + + @Override + protected AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { + return new AzItemRendererPipelineContext<>(this); + } + + @Override + protected @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { + return itemRenderer.getTextureLocation(animatable); + } + + /** + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
      + * {@link PoseStack} translations made here are kept until the end of the render process + */ + @Override + public void preRender(AzRendererPipelineContext context, boolean isReRender) { + var poseStack = context.poseStack(); + this.itemRenderTranslations = new Matrix4f(poseStack.last().pose()); + + scaleModelForRender(context, this.itemRenderer.getScaleWidth(), this.itemRenderer.getScaleHeight(), isReRender); + + if (!isReRender) { + poseStack.translate(0.5f, this.useNewOffset() ? 0.0f : 0.51f, 0.5f); + } + } + + /** + * The actual render method that subtype renderers should override to handle their specific rendering tasks.
      + * {@link GeoRenderer#preRender} has already been called by this stage, and {@link GeoRenderer#postRender} will be + * called directly after + */ + @Override + public void actuallyRender(AzRendererPipelineContext context, boolean isReRender) { + if (!isReRender) { + var animatable = context.animatable(); + var animator = itemRenderer.getAnimator(); + + if (animator != null) { + animator.animate(animatable); + } + } + + var poseStack = context.poseStack(); + + this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); + + super.actuallyRender(context, isReRender); + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + @Override + public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + if (bone.isTrackingMatrices()) { + var animatable = context.animatable(); + var poseStack = context.poseStack(); + var poseState = new Matrix4f(poseStack.last().pose()); + var localMatrix = RenderUtils.invertAndMultiplyMatrices(poseState, this.itemRenderTranslations); + + bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); + bone.setLocalSpaceMatrix( + RenderUtils.translateMatrix(localMatrix, getRenderOffset(animatable, 1).toVector3f()) + ); + } + + super.renderRecursively(context, bone, isReRender); + } + + /** + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
      + * This should only be called immediately prior to rendering, and only + * + * @see AnimatableTexture#setAndUpdate(ResourceLocation, int) + */ + @Override + public void updateAnimatedTextureFrame(T animatable) { + AnimatableTexture.setAndUpdate( + getTextureLocation(animatable), + Item.getId(animatable) + (int) RenderUtils.getCurrentTick() + ); + } + + public Vec3 getRenderOffset(Item entity, float f) { + return Vec3.ZERO; + } + + /** + * Determines whether to apply the y offset for a model due to the change in BlockBench 4.11. + * + * @return {@code false} by default, meaning the Y-offset will be {@code 0.51f}. Override this method or change the + * return value to {@code true} to use the new Y-offset of {@code 0.0f} for anything created in 4.11+ of + * Blockbench. + */ + public boolean useNewOffset() { + return false; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java new file mode 100644 index 000000000..9c090ff54 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java @@ -0,0 +1,29 @@ +package mod.azure.azurelib.core2.render.pipeline.impl; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; + +public class AzItemRendererPipelineContext extends AzRendererPipelineContext { + + public AzItemRendererPipelineContext(AzRendererPipeline rendererPipeline) { + super(rendererPipeline); + } + + // TODO: This is what Geckolib does, but it feels wrong to have this render type getter for an ITEM... + @Override + public @NotNull RenderType getDefaultRenderType( + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ) { + return RenderType.entityCutoutNoCull(texture); + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/az_pistol.json b/common/src/main/resources/assets/azurelib/models/item/az_pistol.json new file mode 100644 index 000000000..4164a6ee9 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/az_pistol.json @@ -0,0 +1,96 @@ +{ + "credit": "Made with Blockbench", + "parent": "builtin/entity", + "texture_size": [ + 128, + 64 + ], + "display": { + "thirdperson_righthand": { + "translation": [ + 0, + -1.25, + -0.25 + ], + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "thirdperson_lefthand": { + "translation": [ + 0, + -1.25, + -0.25 + ], + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "firstperson_righthand": { + "translation": [ + -9.5, + -5.5, + -5.75 + ] + }, + "firstperson_lefthand": { + "translation": [ + -8.75, + -5.5, + -5.75 + ] + }, + "ground": { + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "gui": { + "rotation": [ + 40, + -38, + 0 + ], + "translation": [ + -1, + -1.25, + 0 + ], + "scale": [ + 0.7, + 0.7, + 0.7 + ] + }, + "head": { + "scale": [ + 0, + 0, + 0 + ] + }, + "fixed": { + "rotation": [ + 0, + -90, + 0 + ], + "translation": [ + -1.75, + -2.5, + -0.25 + ], + "scale": [ + 0.8, + 0.8, + 0.8 + ] + } + } +} \ No newline at end of file diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 21f8e118a..82ea79e91 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -28,6 +28,7 @@ import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; import mod.azure.azurelib.fabric.core2.example.armors.DoomArmor; import mod.azure.azurelib.fabric.core2.example.blocks.Stargate; +import mod.azure.azurelib.fabric.core2.example.items.AzPistol; import mod.azure.azurelib.fabric.core2.example.items.Pistol; import mod.azure.azurelib.fabric.platform.FabricAzureLibNetwork; @@ -64,6 +65,11 @@ public void onInitialize() { AzureLib.modResource("pistol"), new Pistol() ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("az_pistol"), + new AzPistol() + ); Registry.register( BuiltInRegistries.ITEM, AzureLib.modResource("doomicorn_helmet"), diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java new file mode 100644 index 000000000..5b0b36cdb --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java @@ -0,0 +1,93 @@ +package mod.azure.azurelib.fabric.core2.example.items; + +import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; + +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; +import mod.azure.azurelib.core.animation.AnimatableManager; +import mod.azure.azurelib.core.animation.Animation; +import mod.azure.azurelib.core.animation.AnimationController; +import mod.azure.azurelib.core.animation.RawAnimation; +import mod.azure.azurelib.core.object.PlayState; + +public class AzPistol extends Item implements GeoItem { + + private final AnimatableInstanceCache cache = AzureLibUtil.createInstanceCache(this); + + private static final String FIRING_ANIMATION_NAME = "firing"; + + private static final RawAnimation FIRING_ANIMATION = RawAnimation.begin() + .then(FIRING_ANIMATION_NAME, Animation.LoopType.PLAY_ONCE); + + public AzPistol() { + super(new Properties()); + SingletonGeoAnimatable.registerSyncedAnimatable(this); // Needed to make triggerable animations work + } + + @Override + public void onUseTick(Level level, LivingEntity livingEntity, ItemStack stack, int remainingUseDuration) { + super.onUseTick(level, livingEntity, stack, remainingUseDuration); + if (livingEntity instanceof Player player && !level.isClientSide()) { + triggerAnim( + player, + GeoItem.getOrAssignId(stack, (ServerLevel) level), + "base_controller", + FIRING_ANIMATION_NAME + ); + } + } + + @Override + public @NotNull InteractionResultHolder use( + @NotNull Level world, + Player user, + @NotNull InteractionHand hand + ) { + final var itemStack = user.getItemInHand(hand); + user.startUsingItem(hand); + return InteractionResultHolder.consume(itemStack); + } + + @Override + public void createRenderer(Consumer consumer) { + consumer.accept(new RenderProvider() { + + private AzPistolRender renderer = null; + + @Override + public BlockEntityWithoutLevelRenderer getCustomRenderer() { + this.renderer = new AzPistolRender(); + return this.renderer; + } + }); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { + controllers.add( + new AnimationController<>(this, "base_controller", event -> PlayState.CONTINUE).triggerableAnim( + FIRING_ANIMATION_NAME, + FIRING_ANIMATION + ) + ); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return cache; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRender.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRender.java new file mode 100644 index 000000000..ab259d6ee --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRender.java @@ -0,0 +1,28 @@ +package mod.azure.azurelib.fabric.core2.example.items; + +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.render.item.AzItemRenderer; + +public class AzPistolRender extends AzItemRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/item/pistol.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/item/pistol.png"); + + public AzPistolRender() { + super(); + } + + @Override + protected @NotNull ResourceLocation getModelLocation(AzPistol item) { + return MODEL; + } + + @Override + public @NotNull ResourceLocation getTextureLocation(AzPistol item) { + return TEXTURE; + } +} From 38e8b883707279f21a2b12a840d26017e9728cee Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Mon, 16 Dec 2024 13:01:54 -0500 Subject: [PATCH 101/224] Fixed HOLD_ON_LAST_FRAME not holding on last frame. Signed-off-by: = --- .../state/impl/AzAnimationPauseState.java | 14 ++++++++++++-- .../state/impl/AzAnimationPlayState.java | 5 ++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java index 7f6d44667..df3af2a1a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java @@ -1,14 +1,24 @@ package mod.azure.azurelib.core2.animation.controller.state.impl; -import mod.azure.azurelib.core2.animation.controller.state.AzAnimationState; import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; -public final class AzAnimationPauseState extends AzAnimationState { +public final class AzAnimationPauseState extends AzAnimationPlayState { public AzAnimationPauseState() {} + @Override + public void onEnter(AzAnimationControllerStateMachine.Context context) { + // Do nothing, because the pause state shouldn't reset on enter. + } + @Override public void onUpdate(AzAnimationControllerStateMachine.Context context) { + super.onUpdate(context); // Pause state does not need to do anything. } + + @Override + protected void playAgain(AzAnimationControllerStateMachine.Context context) { + // Do nothing, because the pause state shouldn't reset before playing again. + } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java index 2e3f4bfbb..5a6a44e28 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java @@ -4,7 +4,7 @@ import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; -public final class AzAnimationPlayState extends AzAnimationState { +public class AzAnimationPlayState extends AzAnimationState { public AzAnimationPlayState() {} @@ -38,7 +38,6 @@ public void onUpdate(AzAnimationControllerStateMachine.Context context) { if (hasAnimationFinished) { tryPlayAgain(context, currentAnimation); // Regardless of if we should play again, the animation has finished, so return. - return; } // The animation is still running at this point, proceed with updating the bones according to keyframes. @@ -91,7 +90,7 @@ private void tryPlayAgain( } } - private void playAgain(AzAnimationControllerStateMachine.Context context) { + protected void playAgain(AzAnimationControllerStateMachine.Context context) { var controller = context.getAnimationController(); var controllerTimer = controller.getControllerTimer(); var keyFrameManager = controller.getKeyFrameManager(); From e453677e7a6fce6ab989a00ce6b0059293681aa9 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Mon, 16 Dec 2024 13:11:09 -0500 Subject: [PATCH 102/224] Added full AVPR drone code for testing purposes. Signed-off-by: = --- .../LivingEntityMixin_EDARefManagement.java | 57 ++++++++ .../mod/azure/azurelib/core2/util/EDARef.java | 132 +++++++++++++++++ .../azurelib/core2/util/EDARefHolder.java | 6 + .../core2/util/EDARefSerializers.java | 19 +++ .../azurelib/core2/util/EDASerializer.java | 10 ++ .../core2/example/entities/drone/Drone.java | 138 ++++++++++++++++-- .../drone/DroneAnimationDispatcher.java | 42 ++++++ .../entities/drone/DroneAnimationRefs.java | 44 ++++++ .../example/entities/drone/DroneAnimator.java | 30 ++-- .../drone/util/CrawlPathNodeEvaluator.java | 15 ++ .../resources/azurelib.fabric.mixins.json | 1 + .../main/resources/azurelib.neo.mixins.json | 1 + 12 files changed, 469 insertions(+), 26 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/common/internal/mixins/LivingEntityMixin_EDARefManagement.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/util/EDARef.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/util/EDARefHolder.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/util/EDARefSerializers.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/util/EDASerializer.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationDispatcher.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationRefs.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/util/CrawlPathNodeEvaluator.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/LivingEntityMixin_EDARefManagement.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/LivingEntityMixin_EDARefManagement.java new file mode 100644 index 000000000..237c64c04 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/LivingEntityMixin_EDARefManagement.java @@ -0,0 +1,57 @@ +package mod.azure.azurelib.common.internal.mixins; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.world.entity.LivingEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.ArrayList; +import java.util.List; + +import mod.azure.azurelib.core2.util.EDARef; +import mod.azure.azurelib.core2.util.EDARefHolder; + +@Mixin(LivingEntity.class) +public abstract class LivingEntityMixin_EDARefManagement implements EDARefHolder { + + private final List> edaRefs = new ArrayList<>(); + + @Inject(at = @At("RETURN"), method = "onSyncedDataUpdated(Lnet/minecraft/network/syncher/EntityDataAccessor;)V") + private void onSyncedDataUpdated(EntityDataAccessor entityDataAccessor, CallbackInfo callbackInfo) { + for (var edaRef : edaRefs) { + var accessor = edaRef.getEntityDataAccessor(); + + if (!accessor.equals(entityDataAccessor)) { + continue; + } + + var syncUpdateCallback = edaRef.getSyncUpdateCallback(); + + if (syncUpdateCallback != null) { + syncUpdateCallback.run(); + } + } + } + + @Inject(at = @At("RETURN"), method = "addAdditionalSaveData") + private void addAdditionalSaveData(CompoundTag compoundTag, CallbackInfo callbackInfo) { + for (var edaRef : edaRefs) { + edaRef.serialize(compoundTag); + } + } + + @Inject(at = @At("RETURN"), method = "readAdditionalSaveData") + private void readAdditionalSaveData(CompoundTag compoundTag, CallbackInfo callbackInfo) { + for (var edaRef : edaRefs) { + edaRef.deserialize(compoundTag); + } + } + + @Override + public void addRef(EDARef edaRef) { + edaRefs.add(edaRef); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/EDARef.java b/common/src/main/java/mod/azure/azurelib/core2/util/EDARef.java new file mode 100644 index 000000000..9f83da1b6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/EDARef.java @@ -0,0 +1,132 @@ +package mod.azure.azurelib.core2.util; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; + +public class EDARef { + + private final Entity entity; + + private final EntityDataAccessor entityDataAccessor; + + private final @Nullable String name; + + private final @Nullable EDASerializer serializer; + + private final @Nullable Consumer setterCallback; + + private final @Nullable Runnable syncUpdateCallback; + + private EDARef( + Entity entity, + EntityDataAccessor entityDataAccessor, + @Nullable String name, + @Nullable EDASerializer serializer, + @Nullable Consumer setterCallback, + @Nullable Runnable syncUpdateCallback + ) { + this.entity = entity; + this.entityDataAccessor = entityDataAccessor; + this.name = name; + this.serializer = serializer; + this.setterCallback = setterCallback; + this.syncUpdateCallback = syncUpdateCallback; + + if (entity instanceof EDARefHolder edaRefHolder) { + edaRefHolder.addRef(this); + } + } + + public T get() { + return entity.getEntityData().get(entityDataAccessor); + } + + public void set(T value) { + entity.getEntityData().set(entityDataAccessor, value); + + if (setterCallback != null) { + setterCallback.accept(value); + } + } + + public void deserialize(CompoundTag compoundTag) { + if (name == null || serializer == null) { + return; + } + + var deserializedValue = serializer.deserialize(compoundTag, name); + set(deserializedValue); + } + + public void serialize(CompoundTag compoundTag) { + if (name == null || serializer == null) { + return; + } + + serializer.serialize(compoundTag, name, get()); + } + + public EntityDataAccessor getEntityDataAccessor() { + return entityDataAccessor; + } + + public @Nullable EDASerializer getSerializer() { + return serializer; + } + + public @Nullable Runnable getSyncUpdateCallback() { + return syncUpdateCallback; + } + + public static Builder builder(Entity entity, EntityDataAccessor entityDataAccessor) { + return new Builder<>(entity, entityDataAccessor); + } + + public static EDARef create(Entity entity, EntityDataAccessor entityDataAccessor) { + return new EDARef<>(entity, entityDataAccessor, null, null, null, null); + } + + public static class Builder { + + private final Entity entity; + + private final EntityDataAccessor entityDataAccessor; + + private @Nullable String name; + + private @Nullable EDASerializer serializer; + + private @Nullable Consumer setterCallback; + + private @Nullable Runnable syncUpdateCallback; + + private Builder(Entity entity, EntityDataAccessor entityDataAccessor) { + this.entity = entity; + this.entityDataAccessor = entityDataAccessor; + } + + public Builder setSetterCallback(@Nullable Consumer setterCallback) { + this.setterCallback = setterCallback; + return this; + } + + public Builder setSerializer(String name, @Nullable EDASerializer serializer) { + this.name = name; + this.serializer = serializer; + return this; + } + + public Builder setSyncUpdateCallback(@Nullable Runnable syncUpdateCallback) { + this.syncUpdateCallback = syncUpdateCallback; + return this; + } + + public EDARef build() { + return new EDARef<>(entity, entityDataAccessor, name, serializer, setterCallback, syncUpdateCallback); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/EDARefHolder.java b/common/src/main/java/mod/azure/azurelib/core2/util/EDARefHolder.java new file mode 100644 index 000000000..b577ca59d --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/EDARefHolder.java @@ -0,0 +1,6 @@ +package mod.azure.azurelib.core2.util; + +public interface EDARefHolder { + + void addRef(EDARef edaRef); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/EDARefSerializers.java b/common/src/main/java/mod/azure/azurelib/core2/util/EDARefSerializers.java new file mode 100644 index 000000000..109ff547c --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/EDARefSerializers.java @@ -0,0 +1,19 @@ +package mod.azure.azurelib.core2.util; + +import net.minecraft.nbt.CompoundTag; + +public class EDARefSerializers { + + public static final EDASerializer BOOLEAN = new EDASerializer<>() { + + @Override + public Boolean deserialize(CompoundTag compoundTag, String name) { + return compoundTag.getBoolean(name); + } + + @Override + public void serialize(CompoundTag compoundTag, String name, Boolean value) { + compoundTag.putBoolean(name, value); + } + }; +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/EDASerializer.java b/common/src/main/java/mod/azure/azurelib/core2/util/EDASerializer.java new file mode 100644 index 000000000..64745f0c8 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/EDASerializer.java @@ -0,0 +1,10 @@ +package mod.azure.azurelib.core2.util; + +import net.minecraft.nbt.CompoundTag; + +public interface EDASerializer { + + T deserialize(CompoundTag compoundTag, String name); + + void serialize(CompoundTag compoundTag, String name, T Value); +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/Drone.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/Drone.java index 3efae62cf..d2173f97f 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/Drone.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/Drone.java @@ -1,42 +1,154 @@ package mod.azure.azurelib.fabric.core2.example.entities.drone; +import net.minecraft.core.BlockPos; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; +import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; +import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; +import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; +import net.minecraft.world.entity.ai.navigation.PathNavigation; import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; +import net.minecraft.world.level.pathfinder.PathFinder; +import org.jetbrains.annotations.NotNull; -import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; +import mod.azure.azurelib.core2.util.EDARef; +import mod.azure.azurelib.core2.util.EDARefSerializers; import mod.azure.azurelib.fabric.core2.example.MoveAnalysis; +import mod.azure.azurelib.fabric.core2.example.entities.drone.util.CrawlPathNodeEvaluator; public class Drone extends Monster { - private final AzAnimationDispatcher animationDispatcher; + private static final EntityDataAccessor IS_CRAWLING = SynchedEntityData.defineId( + Drone.class, + EntityDataSerializers.BOOLEAN + ); + + private final DroneAnimationDispatcher animationDispatcher; private final MoveAnalysis moveAnalysis; - public Drone(EntityType entityType, Level level) { + public final EDARef isCrawlingRef; + + public Drone(EntityType entityType, Level level) { super(entityType, level); - this.animationDispatcher = new AzAnimationDispatcher(this); + this.animationDispatcher = new DroneAnimationDispatcher(this); this.moveAnalysis = new MoveAnalysis(this); + this.isCrawlingRef = EDARef.builder(this, IS_CRAWLING) + .setSerializer("crawling", EDARefSerializers.BOOLEAN) + .setSetterCallback($ -> refreshDimensions()) + .setSyncUpdateCallback(this::refreshDimensions) + .build(); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(IS_CRAWLING, false); + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, false)); + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.5)); + this.targetSelector.addGoal(1, (new HurtByTargetGoal(this)).setAlertOthers(Drone.class)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); } + @Override + protected @NotNull PathNavigation createNavigation(Level level) { + return new GroundPathNavigation(this, level) { + + @Override + protected @NotNull PathFinder createPathFinder(int i) { + this.nodeEvaluator = new CrawlPathNodeEvaluator(); + this.nodeEvaluator.setCanPassDoors(true); + return new PathFinder(this.nodeEvaluator, i); + } + }; + } + + @Override public void tick() { super.tick(); moveAnalysis.update(); - if (this.level().isClientSide) { - var isMovingOnGround = moveAnalysis.isMovingHorizontally() && onGround(); - var animName = isMovingOnGround - ? "animation.walk" - : "animation.idle"; - animationDispatcher.dispatchFromClient("base_controller", animName); + if (level().isClientSide) { + runPassiveAnimations(); + } else { + tryToCrawl(); + } + } + + private void tryToCrawl() { + var path = navigation.getPath(); + + var current = blockPosition(); + var isTight = isTightSpace(current); + + if (path != null && path.getNextNodeIndex() < path.getNodeCount()) { + var previousNode = path.getPreviousNode(); + isTight = isTight || previousNode != null && isTightSpace(previousNode.asBlockPos()); + var nextNode = path.getNextNode(); + isTight = isTight || isTightSpace(nextNode.asBlockPos()); + } + + isCrawlingRef.set(isTight); + } + + private boolean isTightSpace(BlockPos blockPos) { + var above = blockPos.above(); + var aboveState = level().getBlockState(above); + return !aboveState.isAir(); + } + + private void runPassiveAnimations() { + var dispatcher = animationDispatcher; + var isMovingOnGround = moveAnalysis.isMovingHorizontally() && onGround(); + var isShort = getBbHeight() <= 1; + Runnable animFunction; + + if (isUnderWater()) { + // TODO: idle swim + animFunction = dispatcher::clientSwim; + } else if (isMovingOnGround) { + animFunction = isShort ? dispatcher::clientCrawl : dispatcher::clientWalk; } else { - // Doing other stuff server-side... + // TODO: idle crawl + animFunction = isShort ? dispatcher::clientCrawlHold : dispatcher::clientIdle; } + + animFunction.run(); } @Override - protected void registerGoals() { - this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.25F)); + public boolean doHurtTarget(Entity entity) { + var result = super.doHurtTarget(entity); + + if (result) { + var isClawAttack = random.nextBoolean(); + + if (isClawAttack) { + animationDispatcher.serverClawAttack(); + } else { + animationDispatcher.serverTailAttack(); + } + } + + return result; + } + + @Override + public @NotNull EntityDimensions getDefaultDimensions(@NotNull Pose pose) { + var defaultDimensions = getType().getDimensions(); + return defaultDimensions.scale(1, isCrawlingRef.get() ? 0.4f : 1); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationDispatcher.java new file mode 100644 index 000000000..71a9fc393 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationDispatcher.java @@ -0,0 +1,42 @@ +package mod.azure.azurelib.fabric.core2.example.entities.drone; + +import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; + +public class DroneAnimationDispatcher extends AzAnimationDispatcher { + + public DroneAnimationDispatcher(Drone entity) { + super(entity); + } + + public void clientCrawl() { + dispatchFromClient(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.CRAWL_ANIMATION_NAME); + } + + public void clientCrawlHold() { + dispatchFromClient(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.CRAWL_HOLD_ANIMATION_NAME); + } + + public void clientIdle() { + dispatchFromClient(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.IDLE_ANIMATION_NAME); + } + + public void clientRun() { + dispatchFromClient(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.RUN_ANIMATION_NAME); + } + + public void clientSwim() { + dispatchFromClient(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.SWIM_ANIMATION_NAME); + } + + public void clientWalk() { + dispatchFromClient(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.WALK_ANIMATION_NAME); + } + + public void serverClawAttack() { + dispatchFromServer(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.ATTACK_CLAW_ANIMATION_NAME); + } + + public void serverTailAttack() { + dispatchFromServer(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.ATTACK_TAIL_ANIMATION_NAME); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationRefs.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationRefs.java new file mode 100644 index 000000000..7d9c410b1 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationRefs.java @@ -0,0 +1,44 @@ +package mod.azure.azurelib.fabric.core2.example.entities.drone; + +import mod.azure.azurelib.core2.animation.primitive.AzLoopType; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; + +public class DroneAnimationRefs { + + public static final String FULL_BODY_CONTROLLER_NAME = "full_body"; + + public static final String ATTACK_CLAW_ANIMATION_NAME = "animation.attackclaw"; + + public static final String ATTACK_TAIL_ANIMATION_NAME = "animation.attacktail"; + + public static final String CRAWL_ANIMATION_NAME = "animation.crawl"; + + public static final String CRAWL_HOLD_ANIMATION_NAME = "animation.crawlhold"; + + public static final String IDLE_ANIMATION_NAME = "animation.idle"; + + public static final String RUN_ANIMATION_NAME = "animation.run"; + + public static final String SWIM_ANIMATION_NAME = "animation.swim"; + + public static final String WALK_ANIMATION_NAME = "animation.walk"; + + public static final AzRawAnimation ATTACK_CLAW_ANIMATION = AzRawAnimation.begin() + .then(ATTACK_CLAW_ANIMATION_NAME, AzLoopType.PLAY_ONCE); + + public static final AzRawAnimation ATTACK_TAIL_ANIMATION = AzRawAnimation.begin() + .then(ATTACK_TAIL_ANIMATION_NAME, AzLoopType.PLAY_ONCE); + + public static final AzRawAnimation CRAWL_ANIMATION = AzRawAnimation.begin().thenLoop(CRAWL_ANIMATION_NAME); + + public static final AzRawAnimation CRAWL_HOLD_ANIMATION = AzRawAnimation.begin() + .then(CRAWL_ANIMATION_NAME, AzLoopType.HOLD_ON_LAST_FRAME); + + public static final AzRawAnimation IDLE_ANIMATION = AzRawAnimation.begin().thenLoop(IDLE_ANIMATION_NAME); + + public static final AzRawAnimation RUN_ANIMATION = AzRawAnimation.begin().thenLoop(RUN_ANIMATION_NAME); + + public static final AzRawAnimation SWIM_ANIMATION = AzRawAnimation.begin().thenLoop(SWIM_ANIMATION_NAME); + + public static final AzRawAnimation WALK_ANIMATION = AzRawAnimation.begin().thenLoop(WALK_ANIMATION_NAME); +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimator.java index 09fdd52f0..bc4472418 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimator.java @@ -8,20 +8,11 @@ import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; -import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; public class DroneAnimator extends AzEntityAnimator { private static final ResourceLocation ANIMATIONS = AzureLib.modResource("animations/entity/drone.animation.json"); - private static final String IDLE_ANIMATION_NAME = "animation.idle"; - - private static final String WALK_ANIMATION_NAME = "animation.walk"; - - private static final AzRawAnimation IDLE_ANIMATION = AzRawAnimation.begin().thenLoop(IDLE_ANIMATION_NAME); - - private static final AzRawAnimation WALK_ANIMATION = AzRawAnimation.begin().thenLoop(WALK_ANIMATION_NAME); - public DroneAnimator() { super(AzAnimatorConfig.defaultConfig()); } @@ -29,16 +20,29 @@ public DroneAnimator() { @Override public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( - AzAnimationController.builder(this, "base_controller") + AzAnimationController.builder(this, DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME) .setTransitionLength(5) - .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) - .triggerableAnim(WALK_ANIMATION_NAME, WALK_ANIMATION) + .triggerableAnim( + DroneAnimationRefs.ATTACK_CLAW_ANIMATION_NAME, + DroneAnimationRefs.ATTACK_CLAW_ANIMATION + ) + .triggerableAnim( + DroneAnimationRefs.ATTACK_TAIL_ANIMATION_NAME, + DroneAnimationRefs.ATTACK_TAIL_ANIMATION + ) + .triggerableAnim(DroneAnimationRefs.CRAWL_ANIMATION_NAME, DroneAnimationRefs.CRAWL_ANIMATION) + .triggerableAnim(DroneAnimationRefs.CRAWL_HOLD_ANIMATION_NAME, DroneAnimationRefs.CRAWL_HOLD_ANIMATION) + .triggerableAnim(DroneAnimationRefs.IDLE_ANIMATION_NAME, DroneAnimationRefs.IDLE_ANIMATION) + .triggerableAnim(DroneAnimationRefs.RUN_ANIMATION_NAME, DroneAnimationRefs.RUN_ANIMATION) + .triggerableAnim(DroneAnimationRefs.SWIM_ANIMATION_NAME, DroneAnimationRefs.SWIM_ANIMATION) + .triggerableAnim(DroneAnimationRefs.WALK_ANIMATION_NAME, DroneAnimationRefs.WALK_ANIMATION) .build() ); } @Override - public @NotNull ResourceLocation getAnimationLocation(Drone drone) { + public @NotNull ResourceLocation getAnimationLocation(Drone animatable) { return ANIMATIONS; } + } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/util/CrawlPathNodeEvaluator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/util/CrawlPathNodeEvaluator.java new file mode 100644 index 000000000..94de3e6d1 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/util/CrawlPathNodeEvaluator.java @@ -0,0 +1,15 @@ +package mod.azure.azurelib.fabric.core2.example.entities.drone.util; + +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.level.PathNavigationRegion; +import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; + +public class CrawlPathNodeEvaluator extends WalkNodeEvaluator { + + @Override + public void prepare(PathNavigationRegion pathNavigationRegion, Mob mob) { + super.prepare(pathNavigationRegion, mob); + this.entityHeight = Mth.floor((mob.getBbHeight() / 2) + 1.0F); + } +} diff --git a/fabric/src/main/resources/azurelib.fabric.mixins.json b/fabric/src/main/resources/azurelib.fabric.mixins.json index 0d7b0271d..2cb6f7576 100644 --- a/fabric/src/main/resources/azurelib.fabric.mixins.json +++ b/fabric/src/main/resources/azurelib.fabric.mixins.json @@ -11,6 +11,7 @@ "client": [ "EntityMixin_AzEntityAnimatorCache", "ItemRendererAccessor", + "LivingEntityMixin_EDARefManagement", "MinecraftMixin", "MixinHumanoidArmorLayer", "MixinItemRenderer", diff --git a/neo/src/main/resources/azurelib.neo.mixins.json b/neo/src/main/resources/azurelib.neo.mixins.json index 325c5ea4d..05846b1d3 100644 --- a/neo/src/main/resources/azurelib.neo.mixins.json +++ b/neo/src/main/resources/azurelib.neo.mixins.json @@ -11,6 +11,7 @@ "client": [ "EntityMixin_AzEntityAnimatorCache", "ItemRendererAccessor", + "LivingEntityMixin_EDARefManagement", "MinecraftMixin", "MixinItemRenderer", "TextureManagerMixin" From 0a05ad329edfa7bdaa96e349eac3375f13234611 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Mon, 16 Dec 2024 13:46:08 -0500 Subject: [PATCH 103/224] Refactor. Signed-off-by: = --- .../internal/mixins/LivingEntityMixin_EDARefManagement.java | 4 ++-- .../core2/animation/controller/state/AzAnimationState.java | 2 +- .../state/machine/AzAnimationControllerStateMachine.java | 4 ++-- .../mod/azure/azurelib/core2/util/StateMachineContext.java | 3 --- .../java/mod/azure/azurelib/core2/util/{ => eda}/EDARef.java | 2 +- .../mod/azure/azurelib/core2/util/{ => eda}/EDARefHolder.java | 2 +- .../azurelib/core2/util/{ => eda}/EDARefSerializers.java | 2 +- .../azure/azurelib/core2/util/{ => eda}/EDASerializer.java | 2 +- .../java/mod/azure/azurelib/core2/util/{ => state}/State.java | 2 +- .../azure/azurelib/core2/util/{ => state}/StateMachine.java | 2 +- .../azure/azurelib/core2/util/state/StateMachineContext.java | 3 +++ .../azurelib/fabric/core2/example/entities/drone/Drone.java | 4 ++-- 12 files changed, 16 insertions(+), 16 deletions(-) delete mode 100644 common/src/main/java/mod/azure/azurelib/core2/util/StateMachineContext.java rename common/src/main/java/mod/azure/azurelib/core2/util/{ => eda}/EDARef.java (98%) rename common/src/main/java/mod/azure/azurelib/core2/util/{ => eda}/EDARefHolder.java (62%) rename common/src/main/java/mod/azure/azurelib/core2/util/{ => eda}/EDARefSerializers.java (91%) rename common/src/main/java/mod/azure/azurelib/core2/util/{ => eda}/EDASerializer.java (82%) rename common/src/main/java/mod/azure/azurelib/core2/util/{ => state}/State.java (76%) rename common/src/main/java/mod/azure/azurelib/core2/util/{ => state}/StateMachine.java (93%) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachineContext.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/LivingEntityMixin_EDARefManagement.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/LivingEntityMixin_EDARefManagement.java index 237c64c04..5e1d53684 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/LivingEntityMixin_EDARefManagement.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/LivingEntityMixin_EDARefManagement.java @@ -11,8 +11,8 @@ import java.util.ArrayList; import java.util.List; -import mod.azure.azurelib.core2.util.EDARef; -import mod.azure.azurelib.core2.util.EDARefHolder; +import mod.azure.azurelib.core2.util.eda.EDARef; +import mod.azure.azurelib.core2.util.eda.EDARefHolder; @Mixin(LivingEntity.class) public abstract class LivingEntityMixin_EDARefManagement implements EDARefHolder { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/AzAnimationState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/AzAnimationState.java index 34e71f7e3..7e135a365 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/AzAnimationState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/AzAnimationState.java @@ -1,7 +1,7 @@ package mod.azure.azurelib.core2.animation.controller.state; import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; -import mod.azure.azurelib.core2.util.State; +import mod.azure.azurelib.core2.util.state.State; public abstract class AzAnimationState implements State> { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java index 5b87066e2..7beb4594a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java @@ -7,8 +7,8 @@ import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPlayState; import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationStopState; import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationTransitionState; -import mod.azure.azurelib.core2.util.StateMachine; -import mod.azure.azurelib.core2.util.StateMachineContext; +import mod.azure.azurelib.core2.util.state.StateMachine; +import mod.azure.azurelib.core2.util.state.StateMachineContext; public class AzAnimationControllerStateMachine extends StateMachine, AzAnimationState> { diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/StateMachineContext.java b/common/src/main/java/mod/azure/azurelib/core2/util/StateMachineContext.java deleted file mode 100644 index 9fab72c87..000000000 --- a/common/src/main/java/mod/azure/azurelib/core2/util/StateMachineContext.java +++ /dev/null @@ -1,3 +0,0 @@ -package mod.azure.azurelib.core2.util; - -public interface StateMachineContext {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/EDARef.java b/common/src/main/java/mod/azure/azurelib/core2/util/eda/EDARef.java similarity index 98% rename from common/src/main/java/mod/azure/azurelib/core2/util/EDARef.java rename to common/src/main/java/mod/azure/azurelib/core2/util/eda/EDARef.java index 9f83da1b6..9f8c9861c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/util/EDARef.java +++ b/common/src/main/java/mod/azure/azurelib/core2/util/eda/EDARef.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.util; +package mod.azure.azurelib.core2.util.eda; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.syncher.EntityDataAccessor; diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/EDARefHolder.java b/common/src/main/java/mod/azure/azurelib/core2/util/eda/EDARefHolder.java similarity index 62% rename from common/src/main/java/mod/azure/azurelib/core2/util/EDARefHolder.java rename to common/src/main/java/mod/azure/azurelib/core2/util/eda/EDARefHolder.java index b577ca59d..3666db041 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/util/EDARefHolder.java +++ b/common/src/main/java/mod/azure/azurelib/core2/util/eda/EDARefHolder.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.util; +package mod.azure.azurelib.core2.util.eda; public interface EDARefHolder { diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/EDARefSerializers.java b/common/src/main/java/mod/azure/azurelib/core2/util/eda/EDARefSerializers.java similarity index 91% rename from common/src/main/java/mod/azure/azurelib/core2/util/EDARefSerializers.java rename to common/src/main/java/mod/azure/azurelib/core2/util/eda/EDARefSerializers.java index 109ff547c..0bb3f083e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/util/EDARefSerializers.java +++ b/common/src/main/java/mod/azure/azurelib/core2/util/eda/EDARefSerializers.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.util; +package mod.azure.azurelib.core2.util.eda; import net.minecraft.nbt.CompoundTag; diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/EDASerializer.java b/common/src/main/java/mod/azure/azurelib/core2/util/eda/EDASerializer.java similarity index 82% rename from common/src/main/java/mod/azure/azurelib/core2/util/EDASerializer.java rename to common/src/main/java/mod/azure/azurelib/core2/util/eda/EDASerializer.java index 64745f0c8..1d3cef42c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/util/EDASerializer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/util/eda/EDASerializer.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.util; +package mod.azure.azurelib.core2.util.eda; import net.minecraft.nbt.CompoundTag; diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/State.java b/common/src/main/java/mod/azure/azurelib/core2/util/state/State.java similarity index 76% rename from common/src/main/java/mod/azure/azurelib/core2/util/State.java rename to common/src/main/java/mod/azure/azurelib/core2/util/state/State.java index 32f9e496a..91f8fc1e6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/util/State.java +++ b/common/src/main/java/mod/azure/azurelib/core2/util/state/State.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.util; +package mod.azure.azurelib.core2.util.state; public interface State { diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/StateMachine.java b/common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachine.java similarity index 93% rename from common/src/main/java/mod/azure/azurelib/core2/util/StateMachine.java rename to common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachine.java index 0ce384fad..dbf296049 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/util/StateMachine.java +++ b/common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachine.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.util; +package mod.azure.azurelib.core2.util.state; public abstract class StateMachine> { diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachineContext.java b/common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachineContext.java new file mode 100644 index 000000000..24518fec1 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachineContext.java @@ -0,0 +1,3 @@ +package mod.azure.azurelib.core2.util.state; + +public interface StateMachineContext {} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/Drone.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/Drone.java index d2173f97f..95f72d3cb 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/Drone.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/Drone.java @@ -20,8 +20,8 @@ import net.minecraft.world.level.pathfinder.PathFinder; import org.jetbrains.annotations.NotNull; -import mod.azure.azurelib.core2.util.EDARef; -import mod.azure.azurelib.core2.util.EDARefSerializers; +import mod.azure.azurelib.core2.util.eda.EDARef; +import mod.azure.azurelib.core2.util.eda.EDARefSerializers; import mod.azure.azurelib.fabric.core2.example.MoveAnalysis; import mod.azure.azurelib.fabric.core2.example.entities.drone.util.CrawlPathNodeEvaluator; From cc8b456d6274aa95464bdac2c94d89af11fd61df Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:49:32 -0500 Subject: [PATCH 104/224] Implement Marauder keyframes --- .../entities/marauder/MarauderAnimator.java | 39 +++++++++++++++++++ .../entities/marauder/MarauderEntity.java | 5 +++ 2 files changed, 44 insertions(+) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java index f40d09abd..d3071da17 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java @@ -1,12 +1,15 @@ package mod.azure.azurelib.fabric.core2.example.entities.marauder; import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; import org.jetbrains.annotations.NotNull; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.core2.animation.AzAnimatorConfig; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.animation.primitive.AzLoopType; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; @@ -48,6 +51,42 @@ public void registerControllers(AzAnimationControllerContainer a animationControllerContainer.add( AzAnimationController.builder(this, "base_controller") .setTransitionLength(5) + .setKeyFrameCallbacks( + AzKeyFrameCallbacks.builder() + .setSoundKeyframeHandler( + event -> { + if (event.getKeyframeData().getSound().equals("walk")) { + event.getAnimatable() + .level() + .playLocalSound( + event.getAnimatable().getX(), + event.getAnimatable().getY(), + event.getAnimatable().getZ(), + SoundEvents.METAL_STEP, + SoundSource.HOSTILE, + 1.00F, + 1.0F, + true + ); + } + if (event.getKeyframeData().getSound().equals("run")) { + event.getAnimatable() + .level() + .playLocalSound( + event.getAnimatable().getX(), + event.getAnimatable().getY(), + event.getAnimatable().getZ(), + SoundEvents.SKELETON_STEP, + SoundSource.HOSTILE, + 1.00F, + 1.0F, + true + ); + } + } + ) + .build() + ) .triggerableAnim(IDLE_ANIMATION_NAME, IDLE_ANIMATION) .triggerableAnim(WALK_ANIMATION_NAME, WALK_ANIMATION) .triggerableAnim(RUN_ANIMATION_NAME, RUN_ANIMATION) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java index c8ac41915..c7120b8fe 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java @@ -1,5 +1,6 @@ package mod.azure.azurelib.fabric.core2.example.entities.marauder; +import net.minecraft.core.BlockPos; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; @@ -8,6 +9,7 @@ import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.entity.npc.AbstractVillager; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.NotNull; import mod.azure.azurelib.common.api.common.ai.pathing.AzureNavigation; @@ -84,4 +86,7 @@ protected void registerGoals() { this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 0.6F, true)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true)); } + + @Override + protected void playStepSound(BlockPos pos, BlockState state) {} } From 6d8f0908d368fe2db2de5bd89695977ebbdecc42 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:50:09 -0500 Subject: [PATCH 105/224] Add missing Override --- .../fabric/core2/example/entities/marauder/MarauderEntity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java index c7120b8fe..ef44fca94 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java @@ -57,6 +57,7 @@ protected void tickDeath() { } } + @Override public void tick() { super.tick(); moveAnalysis.update(); From 5d9740d5e1b9ddcebaf9fed62ea87eabb8916f41 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:33:29 -0500 Subject: [PATCH 106/224] Add death and spawn animations to Marauder that play properly-ish (spawn is a bit weird) --- .../entities/marauder/MarauderAnimator.java | 35 ++++++++++++++++++- .../entities/marauder/MarauderEntity.java | 32 ++++++++++------- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java index d3071da17..570c195fd 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java @@ -24,6 +24,8 @@ public class MarauderAnimator extends AzEntityAnimator { private static final String WALK_ANIMATION_NAME = "walk"; + private static final String SPAWN_ANIMATION_NAME = "spawn"; + private static final String DEATH_ANIMATION_NAME = "death"; private static final String RUN_ANIMATION_NAME = "run"; @@ -34,8 +36,10 @@ public class MarauderAnimator extends AzEntityAnimator { private static final AzRawAnimation WALK_ANIMATION = AzRawAnimation.begin().thenLoop(WALK_ANIMATION_NAME); + private static final AzRawAnimation SPAWN_ANIMATION = AzRawAnimation.begin().then(SPAWN_ANIMATION_NAME, AzLoopType.PLAY_ONCE); + private static final AzRawAnimation DEATH_ANIMATION = AzRawAnimation.begin() - .then(WALK_ANIMATION_NAME, AzLoopType.HOLD_ON_LAST_FRAME); + .then(DEATH_ANIMATION_NAME, AzLoopType.HOLD_ON_LAST_FRAME); private static final AzRawAnimation RUN_ANIMATION = AzRawAnimation.begin().thenLoop(RUN_ANIMATION_NAME); @@ -83,6 +87,34 @@ public void registerControllers(AzAnimationControllerContainer a true ); } + if (event.getKeyframeData().getSound().equals("portal")) { + event.getAnimatable() + .level() + .playLocalSound( + event.getAnimatable().getX(), + event.getAnimatable().getY(), + event.getAnimatable().getZ(), + SoundEvents.PORTAL_AMBIENT, + SoundSource.HOSTILE, + 0.20F, + 1.0F, + true + ); + } + if (event.getKeyframeData().getSound().equals("axe")) { + event.getAnimatable() + .level() + .playLocalSound( + event.getAnimatable().getX(), + event.getAnimatable().getY(), + event.getAnimatable().getZ(), + SoundEvents.ENDER_EYE_LAUNCH, + SoundSource.HOSTILE, + 1.00F, + 1.0F, + true + ); + } } ) .build() @@ -92,6 +124,7 @@ public void registerControllers(AzAnimationControllerContainer a .triggerableAnim(RUN_ANIMATION_NAME, RUN_ANIMATION) .triggerableAnim(MELEE_ANIMATION_NAME, MELEE_ANIMATION) .triggerableAnim(DEATH_ANIMATION_NAME, DEATH_ANIMATION) + .triggerableAnim(SPAWN_ANIMATION_NAME, SPAWN_ANIMATION) .build() ); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java index ef44fca94..f42ce2008 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java @@ -40,19 +40,11 @@ public float maxUpStep() { return 2.0F; } - /** - * TODO: Get this working, also figure out how to change death rotation from the default 90, needs to be 0 for - * animation to be correct - */ @Override protected void tickDeath() { ++this.deathTime; if (this.deathTime >= 80 && !this.level().isClientSide() && !this.isRemoved()) { - if (this.level().isClientSide && !this.hasPlayedDeath) { - animationDispatcher.dispatchFromClient("base_controller", "death"); - this.hasPlayedDeath = true; - } - this.level().broadcastEntityEvent(this, (byte) 60); + this.level().broadcastEntityEvent(this, (byte)60); this.remove(RemovalReason.KILLED); } } @@ -65,16 +57,30 @@ public void tick() { if (this.level().isClientSide) { var isMovingOnGround = moveAnalysis.isMovingHorizontally() && onGround(); String animName; - if (isMovingOnGround && !this.isAggressive() && this.isAlive()) { + if (isMovingOnGround && !this.isAggressive() && this.tickCount >= 300 && this.isAlive()) { animName = "walk"; - } else if (isMovingOnGround && this.isAggressive() && this.isAlive()) { + } else if (isMovingOnGround && this.isAggressive() && this.tickCount >= 300 && this.isAlive()) { animName = "run"; + } else if (this.tickCount < 300 && this.isAlive()) { + animName = "spawn"; + } else if (!this.isAlive()) { + animName = "death"; } else { animName = "idle"; } animationDispatcher.dispatchFromClient("base_controller", animName); } else { - // Doing other stuff server-side... + if (this.tickCount < 300 && this.isAlive()) { + if (this.getNavigation() instanceof AzureNavigation azureNavigation) { + azureNavigation.hardStop(); + azureNavigation.stop(); + } + this.setYBodyRot(0); + this.setYHeadRot(0); + this.getEyePosition(90); + this.setXRot(0); + this.setYRot(0); + } } } @@ -83,7 +89,7 @@ public void tick() { */ @Override protected void registerGoals() { - this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.15F)); + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.2F)); this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 0.6F, true)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true)); } From 74de135562534315bf2d71e06b8f4d538ce1d2c4 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Mon, 16 Dec 2024 15:42:27 -0500 Subject: [PATCH 107/224] Committing progress. Signed-off-by: = --- .../ItemStackMixin_AzItemAnimatorCache.java | 26 ++++++ .../core2/animation/impl/AzItemAnimator.java | 5 +- .../core2/render/item/AzItemRenderer.java | 86 +++++++++---------- .../pipeline/impl/AzItemRendererPipeline.java | 25 +++--- .../impl/AzItemRendererPipelineContext.java | 7 +- .../core2/example/items/AzPistolRender.java | 7 +- 6 files changed, 90 insertions(+), 66 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java new file mode 100644 index 000000000..92dc7f6e1 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java @@ -0,0 +1,26 @@ +package mod.azure.azurelib.common.internal.mixins; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(ItemStack.class) +public abstract class ItemStackMixin_AzItemAnimatorCache implements AzAnimatorAccessor { + + @Unique + @Nullable + private AzAnimator animator; + + @Override + public void setAnimator(@Nullable AzAnimator animator) { + this.animator = animator; + } + + @Override + public @Nullable AzAnimator getAnimatorOrNull() { + return animator; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java index 59352efe9..3e6c9d945 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java @@ -1,11 +1,10 @@ package mod.azure.azurelib.core2.animation.impl; -import net.minecraft.world.item.Item; - import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.AzAnimatorConfig; +import net.minecraft.world.item.ItemStack; -public abstract class AzItemAnimator extends AzAnimator { +public abstract class AzItemAnimator extends AzAnimator { protected AzItemAnimator(AzAnimatorConfig config) { super(config); diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java index 82335de5f..8f1cbb111 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -5,6 +5,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import net.minecraft.client.Minecraft; import net.minecraft.client.model.geom.EntityModelSet; import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; @@ -13,7 +14,6 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; @@ -28,11 +28,11 @@ import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import mod.azure.azurelib.core2.render.pipeline.impl.AzItemRendererPipeline; -public abstract class AzItemRenderer extends BlockEntityWithoutLevelRenderer { +public abstract class AzItemRenderer extends BlockEntityWithoutLevelRenderer { - private final AzItemRendererPipeline rendererPipeline; + private final AzItemRendererPipeline rendererPipeline; - private final List> renderLayers; + private final List> renderLayers; protected float scaleWidth = 1; @@ -41,7 +41,7 @@ public abstract class AzItemRenderer extends BlockEntityWithoutL protected boolean useEntityGuiLighting = false; @Nullable - private AzItemAnimator reusedAzItemAnimator; + private AzItemAnimator reusedAzItemAnimator; protected AzItemRenderer() { this(Minecraft.getInstance().getBlockEntityRenderDispatcher(), Minecraft.getInstance().getEntityModels()); @@ -49,13 +49,13 @@ protected AzItemRenderer() { protected AzItemRenderer(BlockEntityRenderDispatcher dispatcher, EntityModelSet modelSet) { super(dispatcher, modelSet); - this.rendererPipeline = new AzItemRendererPipeline<>(this); + this.rendererPipeline = new AzItemRendererPipeline(this); this.renderLayers = new ObjectArrayList<>(); } - protected abstract @NotNull ResourceLocation getModelLocation(T item); + protected abstract @NotNull ResourceLocation getModelLocation(ItemStack item); - public abstract @NotNull ResourceLocation getTextureLocation(T item); + public abstract @NotNull ResourceLocation getTextureLocation(ItemStack item); @Override public void renderByItem( @@ -67,12 +67,11 @@ public void renderByItem( int packedOverlay ) { @SuppressWarnings("unchecked") - var animatable = (T) stack.getItem(); - var currentItemStack = stack; + var animatable = stack; // TODO: What was this used for? var renderPerspective = transformType; - var cachedEntityAnimator = provideAnimator(animatable); + var cachedEntityAnimator = provideAnimator(stack, animatable); var azBakedModel = provideBakedModel(animatable); if (cachedEntityAnimator != null && azBakedModel != null) { @@ -86,7 +85,7 @@ public void renderByItem( renderInGui( animatable, azBakedModel, - currentItemStack, + stack, transformType, poseStack, bufferSource, @@ -106,7 +105,7 @@ public void renderByItem( renderType, false, // TODO: Why the null check here? - currentItemStack != null && currentItemStack.hasFoil() + stack != null && stack.hasFoil() ); rendererPipeline.render( @@ -129,7 +128,7 @@ public void renderByItem( * Just includes some additional required transformations and settings. */ protected void renderInGui( - T animatable, + ItemStack animatable, AzBakedModel azBakedModel, ItemStack currentItemStack, ItemDisplayContext transformType, @@ -179,38 +178,35 @@ protected void renderInGui( poseStack.popPose(); } - protected @Nullable AzItemAnimator createAnimator() { + protected @Nullable AzItemAnimator createAnimator() { return null; } - protected @Nullable AzBakedModel provideBakedModel(@NotNull T item) { + protected @Nullable AzBakedModel provideBakedModel(@NotNull ItemStack item) { var modelResourceLocation = getModelLocation(item); return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); } - protected @Nullable AzItemAnimator provideAnimator(T item) { - // // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for - // the - // // item. - // var accessor = AzAnimatorAccessor.cast(item); - // // TODO: This won't work for items. Need to use an itemStack + id, instead. - // var cachedItemAnimator = (AzItemAnimator) accessor.getAnimatorOrNull(); - // - // if (cachedItemAnimator == null) { - // // If the cached animator is null, create a new one. We use a separate reference here just for some - // cachedItemAnimator = createAnimator(); - // - // if (cachedItemAnimator != null) { - // // If the new animator we created is not null, then register its controllers. - // cachedItemAnimator.registerControllers(cachedItemAnimator.getAnimationControllerContainer()); - // // Also cache the animator so that the next time we fetch the animator, it's ready for us. - // accessor.setAnimator(cachedItemAnimator); - // } - // } - // - // return cachedItemAnimator; - // FIXME: - return null; + protected @Nullable AzItemAnimator provideAnimator(ItemStack itemStack, ItemStack item) { + // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for + // the item. + var accessor = AzAnimatorAccessor.cast(itemStack); + // TODO: This won't work for items. Need to use an itemStack + id, instead. + var cachedItemAnimator = (AzItemAnimator) accessor.getAnimatorOrNull(); + + if (cachedItemAnimator == null) { + // If the cached animator is null, create a new one. We use a separate reference here just for some + cachedItemAnimator = createAnimator(); + + if (cachedItemAnimator != null) { + // If the new animator we created is not null, then register its controllers. + cachedItemAnimator.registerControllers(cachedItemAnimator.getAnimationControllerContainer()); + // Also cache the animator so that the next time we fetch the animator, it's ready for us. + accessor.setAnimator(cachedItemAnimator); + } + } + + return cachedItemAnimator; } /** @@ -218,7 +214,7 @@ protected void renderInGui( *

      * This can help with improperly lit 3d models */ - public AzItemRenderer useAlternateGuiLighting() { + public AzItemRenderer useAlternateGuiLighting() { this.useEntityGuiLighting = true; return this; } @@ -226,14 +222,14 @@ public AzItemRenderer useAlternateGuiLighting() { /** * Sets a scale override for this renderer, telling AzureLib to pre-scale the model */ - public AzItemRenderer withScale(float scale) { + public AzItemRenderer withScale(float scale) { return withScale(scale, scale); } /** * Sets a scale override for this renderer, telling AzureLib to pre-scale the model */ - public AzItemRenderer withScale(float scaleWidth, float scaleHeight) { + public AzItemRenderer withScale(float scaleWidth, float scaleHeight) { this.scaleWidth = scaleWidth; this.scaleHeight = scaleHeight; return this; @@ -242,19 +238,19 @@ public AzItemRenderer withScale(float scaleWidth, float scaleHeight) { /** * Returns the list of registered {@link GeoRenderLayer GeoRenderLayers} for this renderer */ - public List> getRenderLayers() { + public List> getRenderLayers() { return renderLayers; } /** * Adds a {@link GeoRenderLayer} to this renderer, to be called after the main model is rendered each frame */ - public AzItemRenderer addRenderLayer(AzRenderLayer renderLayer) { + public AzItemRenderer addRenderLayer(AzRenderLayer renderLayer) { this.renderLayers.add(renderLayer); return this; } - public @Nullable AzItemAnimator getAnimator() { + public @Nullable AzItemAnimator getAnimator() { return reusedAzItemAnimator; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java index bc0d89ac9..d3e5ca75b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java @@ -3,6 +3,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; @@ -15,25 +16,25 @@ import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; -public class AzItemRendererPipeline extends AzRendererPipeline { +public class AzItemRendererPipeline extends AzRendererPipeline { - private final AzItemRenderer itemRenderer; + private final AzItemRenderer itemRenderer; protected Matrix4f itemRenderTranslations = new Matrix4f(); protected Matrix4f modelRenderTranslations = new Matrix4f(); - public AzItemRendererPipeline(AzItemRenderer itemRenderer) { + public AzItemRendererPipeline(AzItemRenderer itemRenderer) { this.itemRenderer = itemRenderer; } @Override - protected AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { - return new AzItemRendererPipelineContext<>(this); + protected AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { + return new AzItemRendererPipelineContext(rendererPipeline); } @Override - protected @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { + protected @NotNull ResourceLocation getTextureLocation(@NotNull ItemStack animatable) { return itemRenderer.getTextureLocation(animatable); } @@ -43,7 +44,7 @@ protected AzRendererPipelineContext createContext(AzRendererPipeline rende * {@link PoseStack} translations made here are kept until the end of the render process */ @Override - public void preRender(AzRendererPipelineContext context, boolean isReRender) { + public void preRender(AzRendererPipelineContext context, boolean isReRender) { var poseStack = context.poseStack(); this.itemRenderTranslations = new Matrix4f(poseStack.last().pose()); @@ -60,7 +61,7 @@ public void preRender(AzRendererPipelineContext context, boolean isReRender) * called directly after */ @Override - public void actuallyRender(AzRendererPipelineContext context, boolean isReRender) { + public void actuallyRender(AzRendererPipelineContext context, boolean isReRender) { if (!isReRender) { var animatable = context.animatable(); var animator = itemRenderer.getAnimator(); @@ -81,7 +82,7 @@ public void actuallyRender(AzRendererPipelineContext context, boolean isReRen * Renders the provided {@link AzBone} and its associated child bones */ @Override - public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { if (bone.isTrackingMatrices()) { var animatable = context.animatable(); var poseStack = context.poseStack(); @@ -105,14 +106,14 @@ public void renderRecursively(AzRendererPipelineContext context, AzBone bone, * @see AnimatableTexture#setAndUpdate(ResourceLocation, int) */ @Override - public void updateAnimatedTextureFrame(T animatable) { + public void updateAnimatedTextureFrame(ItemStack animatable) { AnimatableTexture.setAndUpdate( getTextureLocation(animatable), - Item.getId(animatable) + (int) RenderUtils.getCurrentTick() + Item.getId(animatable.getItem()) + (int) RenderUtils.getCurrentTick() ); } - public Vec3 getRenderOffset(Item entity, float f) { + public Vec3 getRenderOffset(ItemStack itemStack, float f) { return Vec3.ZERO; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java index 9c090ff54..f402e38a2 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java @@ -4,22 +4,23 @@ import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; -public class AzItemRendererPipelineContext extends AzRendererPipelineContext { +public class AzItemRendererPipelineContext extends AzRendererPipelineContext { - public AzItemRendererPipelineContext(AzRendererPipeline rendererPipeline) { + public AzItemRendererPipelineContext(AzRendererPipeline rendererPipeline) { super(rendererPipeline); } // TODO: This is what Geckolib does, but it feels wrong to have this render type getter for an ITEM... @Override public @NotNull RenderType getDefaultRenderType( - T animatable, + ItemStack animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRender.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRender.java index ab259d6ee..194153425 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRender.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRender.java @@ -1,12 +1,13 @@ package mod.azure.azurelib.fabric.core2.example.items; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.core2.render.item.AzItemRenderer; -public class AzPistolRender extends AzItemRenderer { +public class AzPistolRender extends AzItemRenderer { private static final ResourceLocation MODEL = AzureLib.modResource("geo/item/pistol.geo.json"); @@ -17,12 +18,12 @@ public AzPistolRender() { } @Override - protected @NotNull ResourceLocation getModelLocation(AzPistol item) { + protected @NotNull ResourceLocation getModelLocation(ItemStack item) { return MODEL; } @Override - public @NotNull ResourceLocation getTextureLocation(AzPistol item) { + public @NotNull ResourceLocation getTextureLocation(ItemStack item) { return TEXTURE; } } From 7a16f305605eac890297bfef7dc38f542ad82782 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:47:52 -0500 Subject: [PATCH 108/224] Much cleaner --- .../example/entities/marauder/MarauderEntity.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java index f42ce2008..7f7d8efdc 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java @@ -57,14 +57,12 @@ public void tick() { if (this.level().isClientSide) { var isMovingOnGround = moveAnalysis.isMovingHorizontally() && onGround(); String animName; - if (isMovingOnGround && !this.isAggressive() && this.tickCount >= 300 && this.isAlive()) { - animName = "walk"; - } else if (isMovingOnGround && this.isAggressive() && this.tickCount >= 300 && this.isAlive()) { - animName = "run"; - } else if (this.tickCount < 300 && this.isAlive()) { - animName = "spawn"; - } else if (!this.isAlive()) { + if (!this.isAlive()) { animName = "death"; + } else if (this.tickCount < 300) { + animName = "spawn"; + } else if (isMovingOnGround) { + animName = this.isAggressive() ? "run" : "walk"; } else { animName = "idle"; } From 443e1dc30b117c137206845ed3d2cea5ab627336 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Mon, 16 Dec 2024 19:16:48 -0500 Subject: [PATCH 109/224] Fixed animation issues while pausing/unpausing game. Signed-off-by: = --- .../core2/animation/AzAnimationTimer.java | 62 +++++++++---------- .../azurelib/core2/animation/AzAnimator.java | 7 +-- .../impl/AzAnimationTransitionState.java | 2 +- .../AzAnimationControllerStateMachine.java | 15 ----- 4 files changed, 31 insertions(+), 55 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java index aa54d8259..673adf315 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java @@ -8,56 +8,52 @@ public class AzAnimationTimer { private final AzAnimatorConfig config; - // Remnants from AnimatableManager. - private double lastUpdateTime; - - private boolean isFirstTick = true; - - private double firstTickTime = -1; - // Remnants from GeoModel. private double animTime; private double lastGameTickTime; + private boolean wasPausedLastFrame; + public AzAnimationTimer(AzAnimatorConfig config) { this.config = config; } public void tick() { var minecraft = Minecraft.getInstance(); - // TODO: If encountering rendering smoothness issues, break glass (this used to be a DataTickets.TICK fetch). - var currentTick = RenderUtils.getCurrentTick(); - - if (firstTickTime == -1) { - firstTickTime = currentTick + minecraft.getTimer().getGameTimeDeltaTicks(); + var currentRenderTick = RenderUtils.getCurrentTick(); + + if (minecraft.isPaused()) { + if (!wasPausedLastFrame) { + // If this is the first frame of the game pause time, we need to set a flag. + this.wasPausedLastFrame = true; + } + + if (!config.shouldPlayAnimationsWhileGamePaused()) { + // If we cannot play animations while the game is paused, then return early. + return; + } } - double currentFrameTime = currentTick - firstTickTime; - boolean isReRender = !isFirstTick && currentFrameTime == lastUpdateTime; - - // TODO: Figure out why this was here to begin with. - // if (isReRender && instanceId == this.lastRenderedInstance) { - // return; - // } - - if (!isReRender && (!minecraft.isPaused() || config.shouldPlayAnimationsWhileGamePaused())) { - this.lastUpdateTime = currentFrameTime; - - this.animTime += lastUpdateTime - this.lastGameTickTime; - this.lastGameTickTime = lastUpdateTime; + // Compute the delta render tick for this frame. This calculation by default does not account for the game + // pause state, which means that the difference here could be massive by the time the player unpauses. + var deltaRenderTick = currentRenderTick - lastGameTickTime; + + if (wasPausedLastFrame && !minecraft.isPaused()) { + // If this is the first frame of the game play time, we need to set a flag and adjust the deltaRenderTick. + this.wasPausedLastFrame = false; + // To account for the deltaRenderTick being massive on exiting the game pause state, we simply set + // it to 0. This will result in no difference being added to animTime, allowing animations to + // continue right where it left off. + deltaRenderTick = 0; } + + // Add the deltaRenderTick to animTime. animTime is what controls the progress of animations. + this.animTime += deltaRenderTick; + this.lastGameTickTime = currentRenderTick; } public double getAnimTime() { return animTime; } - - public boolean isFirstTick() { - return this.isFirstTick; - } - - protected void finishFirstTick() { - this.isFirstTick = false; - } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index 164b128b2..91c3f4330 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -41,17 +41,13 @@ public void animate(T animatable) { reusableContext.animatable = animatable; var boneCache = reusableContext.boneCache(); - var config = reusableContext.config(); var timer = reusableContext.timer(); timer.tick(); preAnimationSetup(animatable, timer.getAnimTime()); - var minecraft = Minecraft.getInstance(); - var shouldRun = !minecraft.isPaused() || config.shouldPlayAnimationsWhileGamePaused(); - - if (shouldRun && !boneCache.isEmpty()) { + if (!boneCache.isEmpty()) { for (var controller : animationControllerContainer.getAll()) { controller.update(reusableContext); @@ -60,7 +56,6 @@ public void animate(T animatable) { this.reloadAnimations = false; boneCache.update(reusableContext); - timer.finishFirstTick(); } setCustomAnimations(animatable); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java index ae685b6c1..5596b7aeb 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java @@ -25,7 +25,7 @@ public void onUpdate(AzAnimationControllerStateMachine.Context context) { var stateMachine = context.getStateMachine(); var boneCache = animContext.boneCache(); - if (controllerTimer.getAdjustedTick() == 0 || stateMachine.isJustStarting()) { + if (controllerTimer.getAdjustedTick() == 0) { controller.setCurrentAnimation(controller.getAnimationQueue().next()); controller.getKeyFrameManager().keyFrameCallbackHandler().reset(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java index 7beb4594a..d0dfc492f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java @@ -14,8 +14,6 @@ public class AzAnimationControllerStateMachine extends StateMachine stateHolder; - private boolean isJustStarting; - public AzAnimationControllerStateMachine( StateHolder stateHolder, AzAnimationController animationController, @@ -35,11 +33,6 @@ public Context createContext() { public void update() { super.update(getContext()); - - var animContext = getContext().animationContext; - var timer = animContext.timer(); - - setJustStarting(timer.isFirstTick()); } public void pause() { @@ -74,14 +67,6 @@ public boolean isTransitioning() { return getState() == stateHolder.transitionState; } - public boolean isJustStarting() { - return isJustStarting; - } - - public void setJustStarting(boolean justStarting) { - isJustStarting = justStarting; - } - public record StateHolder( AzAnimationPlayState playState, AzAnimationPauseState pauseState, From 66030c565223abe10db92d56cc51667f8e043ace Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Tue, 17 Dec 2024 04:25:05 -0500 Subject: [PATCH 110/224] Clean up --- .../fabric/core2/example/entities/marauder/MarauderEntity.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java index 7f7d8efdc..bd5512573 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java @@ -22,8 +22,6 @@ public class MarauderEntity extends Monster { private final MoveAnalysis moveAnalysis; - private boolean hasPlayedDeath = false; - public MarauderEntity(EntityType entityType, Level level) { super(entityType, level); this.animationDispatcher = new AzAnimationDispatcher(this); From 2e7b555b4c064ac7760f5a3971cb42fd647550d5 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Wed, 18 Dec 2024 21:15:02 -0500 Subject: [PATCH 111/224] Started implementing animation dispatching (work in progress). Signed-off-by: = --- .../packet/AzEntityDispatchCommandPacket.java | 54 ++++++++++++ .../platform/services/AzureLibNetwork.java | 2 + .../dispatch/AzDispatchExecutor.java | 84 +++++++++++++++++++ .../animation/dispatch/AzDispatchSide.java | 39 +++++++++ .../animation/dispatch/AzDispatcher.java | 29 +++++++ .../AzDispatchAnimationCommandBuilder.java | 9 ++ .../dispatch/command/AzDispatchCommand.java | 32 +++++++ .../command/AzDispatchCommandBuilder.java | 39 +++++++++ .../AzDispatchControllerCommandBuilder.java | 16 ++++ .../command/AzDispatchRootCommandBuilder.java | 46 ++++++++++ .../command/action/AzDispatchAction.java | 14 ++++ .../action/codec/AzDispatchActionCodec.java | 41 +++++++++ .../action/codec/AzDispatchCommandCodec.java | 32 +++++++ .../action/impl/root/AzRootCancelAction.java | 35 ++++++++ .../impl/root/AzRootCancelAllAction.java | 30 +++++++ .../impl/root/AzRootPlayAnimationAction.java | 38 +++++++++ .../AzRootSetTransitionInSpeedAction.java | 24 ++++++ .../registry/AzDispatchActionRegistry.java | 59 +++++++++++++ .../azure/azurelib/fabric/ClientListener.java | 4 + .../azurelib/fabric/FabricAzureLibMod.java | 2 + .../drone/DroneAnimationDispatcher.java | 44 ++++++++-- .../neoforge/NeoForgeAzureLibMod.java | 5 ++ 22 files changed, 669 insertions(+), 9 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityDispatchCommandPacket.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchSide.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatcher.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchAnimationCommandBuilder.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommand.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommandBuilder.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchControllerCommandBuilder.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchRootCommandBuilder.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/AzDispatchAction.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchActionCodec.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchCommandCodec.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAction.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAllAction.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootPlayAnimationAction.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetTransitionInSpeedAction.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/registry/AzDispatchActionRegistry.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityDispatchCommandPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityDispatchCommandPacket.java new file mode 100644 index 000000000..dbbf39213 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityDispatchCommandPacket.java @@ -0,0 +1,54 @@ +package mod.azure.azurelib.common.internal.common.network.packet; + +import com.mojang.serialization.Codec; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import org.jetbrains.annotations.NotNull; + +public record AzEntityDispatchCommandPacket( + int entityId, + AzDispatchCommand dispatchCommand, + AzDispatchSide origin +) implements AbstractPacket { + + public static final Type TYPE = new Type<>( + AzureLibNetwork.AZ_ENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID + ); + + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, + AzEntityDispatchCommandPacket::entityId, + AzDispatchCommand.CODEC, + AzEntityDispatchCommandPacket::dispatchCommand, + AzDispatchSide.CODEC, + AzEntityDispatchCommandPacket::origin, + AzEntityDispatchCommandPacket::new + ); + + public void handle() { + var entity = ClientUtils.getLevel().getEntity(this.entityId); + + if (entity == null) { + return; + } + + var animator = AzAnimatorAccessor.getOrNull(entity); + + if (animator != null) { + dispatchCommand.getActions().forEach(action -> action.handle(animator)); + } + } + + @Override + public @NotNull Type type() { + return TYPE; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java index 35cabb8d3..696463f3d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java @@ -26,6 +26,8 @@ public interface AzureLibNetwork { ResourceLocation AZ_ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("az_entity_anim_trigger_sync"); + ResourceLocation AZ_ENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID = AzureLib.modResource("az_entity_dispatch_command_sync"); + ResourceLocation ENTITY_ANIM_DATA_SYNC_PACKET_ID = AzureLib.modResource("entity_anim_data_sync"); ResourceLocation ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("entity_anim_trigger_sync"); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java new file mode 100644 index 000000000..20c769846 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java @@ -0,0 +1,84 @@ +package mod.azure.azurelib.core2.animation.dispatch; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.network.packet.AzEntityDispatchCommandPacket; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; +import net.minecraft.world.entity.Entity; + +import java.util.List; + +public record AzDispatchExecutor( + List commands, + AzDispatchSide origin +) { + + public void sendForEntity(Entity entity) { + switch (origin) { + case CLIENT -> dispatchFromClient(entity); + case SERVER -> dispatchFromServer(entity); + } + } + + private void dispatchFromClient(T animatable) { + if (origin != AzDispatchSide.CLIENT) { + AzureLib.LOGGER.warn("Dispatch origin mismatch - expected CLIENT, got {}.", origin); + return; + } + + var isClientSide = isClientSide(animatable); + + if (!isClientSide) { + AzureLib.LOGGER.warn("Attempted client-side animation dispatch from server side."); + return; + } + + var animator = AzAnimatorAccessor.getOrNull(animatable); + + if (animator != null) { + commands.forEach(command -> { + command.getActions().forEach(action -> action.handle(animator)); + }); + } + } + + private void dispatchFromServer(T animatable) { + if (origin != AzDispatchSide.SERVER) { + AzureLib.LOGGER.warn("Dispatch origin mismatch - expected SERVER, got {}.", origin); + return; + } + + var isClientSide = isClientSide(animatable); + + if (isClientSide) { + AzureLib.LOGGER.warn("Attempted server-side animation dispatch from client side."); + return; + } + + if (animatable instanceof Entity entity) { + handleServerDispatchForEntity(entity); + } + // TODO: Armors + // TODO: Blocks + // TODO: Items + } + + private void handleServerDispatchForEntity(Entity entity) { + var entityId = entity.getId(); + + commands.forEach(command -> { + // TODO: Buffer commands together. + var packet = new AzEntityDispatchCommandPacket(entityId, command, origin); + Services.NETWORK.sendToTrackingEntityAndSelf(packet, entity); + }); + } + + private boolean isClientSide(T animatable) { + if (animatable instanceof Entity entity) { + return entity.level().isClientSide(); + } + + throw new IllegalArgumentException("Unhandled animatable type: " + animatable); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchSide.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchSide.java new file mode 100644 index 000000000..57ac253a6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchSide.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.core2.animation.dispatch; + +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.util.StringRepresentable; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public enum AzDispatchSide implements StringRepresentable { + CLIENT(0), + SERVER(1); + + private static final Map ID_TO_ENUM_MAP = new Int2ObjectArrayMap<>(); + + static { + // Populate the map for quick lookup + for (AzDispatchSide side : values()) { + ID_TO_ENUM_MAP.put(side.id, side); + } + } + + private final int id; + + AzDispatchSide(int id) { + this.id = id; + } + + public static final StreamCodec CODEC = StreamCodec.of( + (buf, val) -> buf.writeByte(val.id), + buf -> ID_TO_ENUM_MAP.get((int) buf.readByte()) + ); + + @Override + public @NotNull String getSerializedName() { + return name(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatcher.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatcher.java new file mode 100644 index 000000000..edbceb471 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatcher.java @@ -0,0 +1,29 @@ +package mod.azure.azurelib.core2.animation.dispatch; + +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class AzDispatcher { + + private AzDispatcher() {} + + public static AzDispatchExecutor fromClient(AzDispatchCommand command, AzDispatchCommand... additionalCommands) { + var commands = unifyCommands(command, additionalCommands); + return new AzDispatchExecutor(commands, AzDispatchSide.CLIENT); + } + + public static AzDispatchExecutor fromServer(AzDispatchCommand command, AzDispatchCommand... additionalCommands) { + var commands = unifyCommands(command, additionalCommands); + return new AzDispatchExecutor(commands, AzDispatchSide.SERVER); + } + + private static @NotNull ArrayList unifyCommands(AzDispatchCommand command, AzDispatchCommand[] additionalCommands) { + var commands = new ArrayList(); + commands.add(command); + commands.addAll(List.of(additionalCommands)); + return commands; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchAnimationCommandBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchAnimationCommandBuilder.java new file mode 100644 index 000000000..ea6665eb0 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchAnimationCommandBuilder.java @@ -0,0 +1,9 @@ +package mod.azure.azurelib.core2.animation.dispatch.command; + +public class AzDispatchAnimationCommandBuilder extends AzDispatchCommandBuilder { + + public AzDispatchAnimationCommandBuilder setPriority(int priority) { + // TODO: + return self(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommand.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommand.java new file mode 100644 index 000000000..bd0b2f383 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommand.java @@ -0,0 +1,32 @@ +package mod.azure.azurelib.core2.animation.dispatch.command; + +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.codec.AzDispatchCommandCodec; + +import java.util.Collection; +import java.util.List; + +public class AzDispatchCommand { + + public static final AzDispatchCommandCodec CODEC = new AzDispatchCommandCodec(); + + private final List actions; + + public AzDispatchCommand(List actions) { + this.actions = actions; + } + + public static AzDispatchRootCommandBuilder builder() { + return new AzDispatchRootCommandBuilder(); + } + + public static AzDispatchCommand playAnimation(String controllerName, String animationName) { + return builder() + .playAnimation(controllerName, animationName) + .build(); + } + + public Collection getActions() { + return actions; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommandBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommandBuilder.java new file mode 100644 index 000000000..4d524aba6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommandBuilder.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.core2.animation.dispatch.command; + +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; + +import java.util.ArrayList; +import java.util.List; + +public class AzDispatchCommandBuilder> { + + protected final List actions; + + AzDispatchCommandBuilder() { + this.actions = new ArrayList<>(); + } + + @SuppressWarnings("unchecked") + protected T self() { + return (T) this; + } + + public T setSpeed(float speed) { + // TODO: + return self(); + } + + public T setTransitionInSpeed(float transitionSpeed) { + // TODO: + return self(); + } + + public T setTransitionOutSpeed(float transitionSpeed) { + // TODO: + return self(); + } + + public AzDispatchCommand build() { + return new AzDispatchCommand(actions); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchControllerCommandBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchControllerCommandBuilder.java new file mode 100644 index 000000000..3d0c26a66 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchControllerCommandBuilder.java @@ -0,0 +1,16 @@ +package mod.azure.azurelib.core2.animation.dispatch.command; + +import java.util.function.UnaryOperator; + +public class AzDispatchControllerCommandBuilder extends AzDispatchCommandBuilder { + + public AzDispatchControllerCommandBuilder playAnimation(String animationName) { + // TODO: + return this; + } + + public AzDispatchControllerCommandBuilder playAnimation(String animationName, UnaryOperator builderUnaryOperator) { + // TODO: + return this; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchRootCommandBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchRootCommandBuilder.java new file mode 100644 index 000000000..939c3bc20 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchRootCommandBuilder.java @@ -0,0 +1,46 @@ +package mod.azure.azurelib.core2.animation.dispatch.command; + +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAllAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootPlayAnimationAction; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.UnaryOperator; + +public class AzDispatchRootCommandBuilder extends AzDispatchCommandBuilder { + + private final List actions; + + AzDispatchRootCommandBuilder() { + this.actions = new ArrayList<>(); + } + + public AzDispatchRootCommandBuilder cancelAll() { + actions.add(new AzRootCancelAllAction()); + return self(); + } + + public AzDispatchRootCommandBuilder cancel(String controllerName) { + actions.add(new AzRootCancelAction(controllerName)); + return self(); + } + + public AzDispatchRootCommandBuilder forController(String controllerName, UnaryOperator builderUnaryOperator) { + var builder = new AzDispatchControllerCommandBuilder(); + builderUnaryOperator.apply(builder); + var command = builder.build(); + actions.addAll(command.getActions()); + return self(); + } + + public AzDispatchRootCommandBuilder playAnimation(String controllerName, String animationName) { + actions.add(new AzRootPlayAnimationAction(controllerName, animationName)); + return self(); + } + + public AzDispatchCommand build() { + return new AzDispatchCommand(actions); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/AzDispatchAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/AzDispatchAction.java new file mode 100644 index 000000000..9746d48fe --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/AzDispatchAction.java @@ -0,0 +1,14 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.command.action.codec.AzDispatchActionCodec; +import net.minecraft.resources.ResourceLocation; + +public interface AzDispatchAction { + + AzDispatchActionCodec CODEC = new AzDispatchActionCodec(); + + void handle(AzAnimator animator); + + ResourceLocation getResourceLocation(); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchActionCodec.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchActionCodec.java new file mode 100644 index 000000000..48058dc0b --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchActionCodec.java @@ -0,0 +1,41 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.codec; + +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.registry.AzDispatchActionRegistry; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import org.jetbrains.annotations.NotNull; + +public class AzDispatchActionCodec implements StreamCodec { + + @Override + public @NotNull AzDispatchAction decode(@NotNull FriendlyByteBuf byteBuf) { + var id = byteBuf.readShort(); + var codec = AzDispatchActionRegistry.>getCodecOrNull(id); + + if (codec == null) { + throw new NullPointerException("Could not find action codec for a given action id while decoding data. ID: " + id); + } + + return codec.decode(byteBuf); + } + + @Override + public void encode(@NotNull FriendlyByteBuf byteBuf, @NotNull AzDispatchAction action) { + var resourceLocation = action.getResourceLocation(); + var id = AzDispatchActionRegistry.getIdOrNull(resourceLocation); + var codec = AzDispatchActionRegistry.>getCodecOrNull(resourceLocation); + + if (id == null) { + throw new NullPointerException("Could not find action id for a given resource location while encoding data. Resource Location: " + resourceLocation); + } + + byteBuf.writeShort(id); + + if (codec == null) { + throw new NullPointerException("Could not find action codec for a given resource location while encoding data. Resource Location: " + resourceLocation + ", ID: " + id); + } + + codec.encode(byteBuf, action); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchCommandCodec.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchCommandCodec.java new file mode 100644 index 000000000..d82473fbc --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchCommandCodec.java @@ -0,0 +1,32 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.codec; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import org.jetbrains.annotations.NotNull; + +public class AzDispatchCommandCodec implements StreamCodec { + + @Override + public @NotNull AzDispatchCommand decode(@NotNull FriendlyByteBuf byteBuf) { + var actionCount = byteBuf.readByte(); + var actions = new ObjectArrayList(actionCount); + + for (int i = 0; i < actionCount; i++) { + var action = AzDispatchAction.CODEC.decode(byteBuf); + actions.add(action); + } + + return new AzDispatchCommand(actions); + } + + @Override + public void encode(@NotNull FriendlyByteBuf byteBuf, @NotNull AzDispatchCommand command) { + var actions = command.getActions(); + var actionCount = actions.size(); + byteBuf.writeByte(actionCount); + actions.forEach(action -> AzDispatchAction.CODEC.encode(byteBuf, action)); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAction.java new file mode 100644 index 000000000..4ecf0aa88 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAction.java @@ -0,0 +1,35 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; + +public record AzRootCancelAction( + String controllerName +) implements AzDispatchAction { + + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, + AzRootCancelAction::controllerName, + AzRootCancelAction::new + ); + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/cancel"); + + @Override + public void handle(AzAnimator animator) { + var controller = animator.getAnimationControllerContainer().getOrNull(controllerName); + + if (controller != null) { + controller.setCurrentAnimation(null); + } + } + + @Override + public ResourceLocation getResourceLocation() { + return RESOURCE_LOCATION; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAllAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAllAction.java new file mode 100644 index 000000000..4ad32964a --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAllAction.java @@ -0,0 +1,30 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; + +public class AzRootCancelAllAction implements AzDispatchAction { + + public static final StreamCodec CODEC = StreamCodec.unit(new AzRootCancelAllAction()); + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/cancel_all"); + + @Override + public void handle(AzAnimator animator) { + var controllerContainer = animator.getAnimationControllerContainer(); + var controllers = controllerContainer.getAll(); + + + controllers.forEach(controller -> { + controller.setCurrentAnimation(null); + }); + } + + @Override + public ResourceLocation getResourceLocation() { + return RESOURCE_LOCATION; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootPlayAnimationAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootPlayAnimationAction.java new file mode 100644 index 000000000..587575ff6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootPlayAnimationAction.java @@ -0,0 +1,38 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; + +public record AzRootPlayAnimationAction( + String controllerName, + String animationName +) implements AzDispatchAction { + + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, + AzRootPlayAnimationAction::controllerName, + ByteBufCodecs.STRING_UTF8, + AzRootPlayAnimationAction::animationName, + AzRootPlayAnimationAction::new + ); + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/play_animation"); + + @Override + public void handle(AzAnimator animator) { + var controller = animator.getAnimationControllerContainer().getOrNull(controllerName); + + if (controller != null) { + controller.tryTriggerAnimation(animationName); + } + } + + @Override + public ResourceLocation getResourceLocation() { + return RESOURCE_LOCATION; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetTransitionInSpeedAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetTransitionInSpeedAction.java new file mode 100644 index 000000000..4de70eddf --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetTransitionInSpeedAction.java @@ -0,0 +1,24 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; + +public class AzRootSetTransitionInSpeedAction implements AzDispatchAction { + + public static final StreamCodec CODEC = StreamCodec.unit(new AzRootSetTransitionInSpeedAction()); + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/set_transition_in_speed"); + + @Override + public void handle(AzAnimator animator) { + // TODO: Modify animator transition length. + } + + @Override + public ResourceLocation getResourceLocation() { + return RESOURCE_LOCATION; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/registry/AzDispatchActionRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/registry/AzDispatchActionRegistry.java new file mode 100644 index 000000000..96bf73af6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/registry/AzDispatchActionRegistry.java @@ -0,0 +1,59 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.registry; + +import it.unimi.dsi.fastutil.objects.Object2ShortArrayMap; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAllAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootPlayAnimationAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootSetTransitionInSpeedAction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public class AzDispatchActionRegistry { + + private static final Map RESOURCE_LOCATION_TO_ID = new Object2ShortArrayMap<>(); + private static final Map> CODEC_BY_ID = new HashMap<>(); + + private static short NEXT_FREE_ID = 0; + + static { + // Root actions + register(AzRootCancelAction.RESOURCE_LOCATION, AzRootCancelAction.CODEC); + register(AzRootCancelAllAction.RESOURCE_LOCATION, AzRootCancelAllAction.CODEC); + register(AzRootSetTransitionInSpeedAction.RESOURCE_LOCATION, AzRootSetTransitionInSpeedAction.CODEC); + register(AzRootPlayAnimationAction.RESOURCE_LOCATION, AzRootPlayAnimationAction.CODEC); + + // Controller actions + // TODO: + + // Animation actions + // TODO: + } + + public static @Nullable > T getCodecOrNull(ResourceLocation resourceLocation) { + var id = RESOURCE_LOCATION_TO_ID.get(resourceLocation); + @SuppressWarnings("unchecked") + var codec = (T) CODEC_BY_ID.get(id); + return codec; + } + + public static @Nullable > T getCodecOrNull(short id) { + @SuppressWarnings("unchecked") + var codec = (T) CODEC_BY_ID.get(id); + return codec; + } + + public static @Nullable Short getIdOrNull(ResourceLocation resourceLocation) { + return RESOURCE_LOCATION_TO_ID.get(resourceLocation); + } + + private static void register(ResourceLocation resourceLocation, StreamCodec codec) { + var id = RESOURCE_LOCATION_TO_ID.computeIfAbsent(resourceLocation, ($) -> NEXT_FREE_ID++); + CODEC_BY_ID.put(id, codec); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index c7423daae..82da36f84 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -61,6 +61,10 @@ public void onInitializeClient() { AzEntityAnimTriggerPacket.TYPE, (packet, context) -> packet.handle() ); + ClientPlayNetworking.registerGlobalReceiver( + AzEntityDispatchCommandPacket.TYPE, + (packet, context) -> packet.handle() + ); ClientPlayNetworking.registerGlobalReceiver( EntityAnimDataSyncPacket.TYPE, (packet, context) -> packet.handle() diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 82ea79e91..bf7b1293f 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -1,5 +1,6 @@ package mod.azure.azurelib.fabric; +import mod.azure.azurelib.common.internal.common.network.packet.AzEntityDispatchCommandPacket; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; @@ -50,6 +51,7 @@ public void onInitialize() { PayloadTypeRegistry.playS2C().register(BlockEntityAnimDataSyncPacket.TYPE, BlockEntityAnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(EntityAnimTriggerPacket.TYPE, EntityAnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(AzEntityAnimTriggerPacket.TYPE, AzEntityAnimTriggerPacket.CODEC); + PayloadTypeRegistry.playS2C().register(AzEntityDispatchCommandPacket.TYPE, AzEntityDispatchCommandPacket.CODEC); PayloadTypeRegistry.playS2C().register(EntityAnimDataSyncPacket.TYPE, EntityAnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(AnimTriggerPacket.TYPE, AnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(AnimDataSyncPacket.TYPE, AnimDataSyncPacket.CODEC); diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationDispatcher.java index 71a9fc393..8aa821c6f 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationDispatcher.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimationDispatcher.java @@ -1,27 +1,53 @@ package mod.azure.azurelib.fabric.core2.example.entities.drone; import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatcher; +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; public class DroneAnimationDispatcher extends AzAnimationDispatcher { - public DroneAnimationDispatcher(Drone entity) { - super(entity); + private static final AzDispatchCommand ATTACK_CLAW_COMMAND = AzDispatchCommand + .playAnimation(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.ATTACK_CLAW_ANIMATION_NAME); + + private static final AzDispatchCommand ATTACK_TAIL_COMMAND = AzDispatchCommand + .playAnimation(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.ATTACK_TAIL_ANIMATION_NAME); + + private static final AzDispatchCommand CRAWL_COMMAND = AzDispatchCommand + .playAnimation(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.CRAWL_ANIMATION_NAME); + + private static final AzDispatchCommand CRAWL_HOLD_COMMAND = AzDispatchCommand + .playAnimation(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.CRAWL_HOLD_ANIMATION_NAME); + + private static final AzDispatchCommand IDLE_COMMAND = AzDispatchCommand + .playAnimation(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.IDLE_ANIMATION_NAME); + + private static final AzDispatchCommand RUN_COMMAND = AzDispatchCommand + .playAnimation(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.RUN_ANIMATION_NAME); + + private static final AzDispatchCommand WALK_COMMAND = AzDispatchCommand + .playAnimation(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.WALK_ANIMATION_NAME); + + private final Drone drone; + + public DroneAnimationDispatcher(Drone drone) { + super(drone); + this.drone = drone; } public void clientCrawl() { - dispatchFromClient(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.CRAWL_ANIMATION_NAME); + AzDispatcher.fromClient(CRAWL_COMMAND).sendForEntity(drone); } public void clientCrawlHold() { - dispatchFromClient(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.CRAWL_HOLD_ANIMATION_NAME); + AzDispatcher.fromClient(CRAWL_HOLD_COMMAND).sendForEntity(drone); } public void clientIdle() { - dispatchFromClient(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.IDLE_ANIMATION_NAME); + AzDispatcher.fromClient(IDLE_COMMAND).sendForEntity(drone); } public void clientRun() { - dispatchFromClient(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.RUN_ANIMATION_NAME); + AzDispatcher.fromClient(RUN_COMMAND).sendForEntity(drone); } public void clientSwim() { @@ -29,14 +55,14 @@ public void clientSwim() { } public void clientWalk() { - dispatchFromClient(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.WALK_ANIMATION_NAME); + AzDispatcher.fromClient(WALK_COMMAND).sendForEntity(drone); } public void serverClawAttack() { - dispatchFromServer(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.ATTACK_CLAW_ANIMATION_NAME); + AzDispatcher.fromServer(ATTACK_CLAW_COMMAND).sendForEntity(drone); } public void serverTailAttack() { - dispatchFromServer(DroneAnimationRefs.FULL_BODY_CONTROLLER_NAME, DroneAnimationRefs.ATTACK_TAIL_ANIMATION_NAME); + AzDispatcher.fromServer(ATTACK_TAIL_COMMAND).sendForEntity(drone); } } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java index f7568ceb3..b7dcdee47 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java @@ -63,6 +63,11 @@ public void registerMessages(RegisterPayloadHandlersEvent event) { AzEntityAnimTriggerPacket.CODEC, (msg, ctx) -> msg.handle() ); + registrar.playBidirectional( + AzEntityDispatchCommandPacket.TYPE, + AzEntityDispatchCommandPacket.CODEC, + (msg, ctx) -> msg.handle() + ); registrar.playBidirectional( EntityAnimDataSyncPacket.TYPE, EntityAnimDataSyncPacket.CODEC, From 7f9ed189075142d1eba0b0dbe4fa1a34513d4e5c Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 10:38:21 -0500 Subject: [PATCH 112/224] bring in from main --- .../internal/common/cache/texture/GeoGlowingTextureMeta.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java index 87db2d28b..99c633be9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java @@ -122,9 +122,9 @@ public void createImageMask(NativeImage originalImage, NativeImage newImage) { if (pixel.alpha > 0) color = FastColor.ABGR32.color( pixel.alpha, - FastColor.ABGR32.red(color), + FastColor.ABGR32.blue(color), FastColor.ABGR32.green(color), - FastColor.ABGR32.blue(color) + FastColor.ABGR32.red(color) ); newImage.setPixelRGBA(pixel.x, pixel.y, color); From 2372efd8517b99ed893a325225ba00d1ed305587 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 10:38:27 -0500 Subject: [PATCH 113/224] Update MarauderEntity.java --- .../core2/example/entities/marauder/MarauderEntity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java index bd5512573..6c282b05d 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java @@ -3,7 +3,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; -import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; +import net.minecraft.world.entity.ai.goal.RandomStrollGoal; import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; import net.minecraft.world.entity.ai.navigation.PathNavigation; import net.minecraft.world.entity.monster.Monster; @@ -85,7 +85,7 @@ public void tick() { */ @Override protected void registerGoals() { - this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.2F)); + this.goalSelector.addGoal(7, new RandomStrollGoal(this, 0.3F)); this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 0.6F, true)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true)); } From f38e33c4be271df4e9eb8214949ae71564390064 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 19 Dec 2024 10:28:32 -0800 Subject: [PATCH 114/224] Lint. Signed-off-by: = --- .../packet/AzEntityDispatchCommandPacket.java | 12 ++--- .../platform/services/AzureLibNetwork.java | 4 +- .../dispatch/AzDispatchExecutor.java | 7 +-- .../animation/dispatch/AzDispatchSide.java | 1 + .../animation/dispatch/AzDispatcher.java | 8 +++- .../dispatch/command/AzDispatchCommand.java | 6 +-- .../command/AzDispatchCommandBuilder.java | 4 +- .../AzDispatchControllerCommandBuilder.java | 5 +- .../command/AzDispatchRootCommandBuilder.java | 13 +++-- .../command/action/AzDispatchAction.java | 3 +- .../action/codec/AzDispatchActionCodec.java | 25 +++++++--- .../action/codec/AzDispatchCommandCodec.java | 5 +- .../action/impl/root/AzRootCancelAction.java | 8 ++-- .../impl/root/AzRootCancelAllAction.java | 13 +++-- .../impl/root/AzRootPlayAnimationAction.java | 8 ++-- .../AzRootSetTransitionInSpeedAction.java | 12 +++-- .../registry/AzDispatchActionRegistry.java | 24 ++++++---- .../core2/animation/impl/AzItemAnimator.java | 3 +- .../impl/AzItemRendererPipelineContext.java | 1 - .../azurelib/fabric/FabricAzureLibMod.java | 2 +- .../entities/marauder/MarauderAnimator.java | 47 ++++++++++--------- .../entities/marauder/MarauderEntity.java | 2 +- 22 files changed, 130 insertions(+), 83 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityDispatchCommandPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityDispatchCommandPacket.java index dbbf39213..552357cbc 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityDispatchCommandPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityDispatchCommandPacket.java @@ -1,17 +1,17 @@ package mod.azure.azurelib.common.internal.common.network.packet; -import com.mojang.serialization.Codec; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import org.jetbrains.annotations.NotNull; + import mod.azure.azurelib.common.api.client.helper.ClientUtils; import mod.azure.azurelib.common.internal.common.network.AbstractPacket; import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.codec.ByteBufCodecs; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import org.jetbrains.annotations.NotNull; public record AzEntityDispatchCommandPacket( int entityId, diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java index 696463f3d..b464cb9b0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java @@ -26,7 +26,9 @@ public interface AzureLibNetwork { ResourceLocation AZ_ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("az_entity_anim_trigger_sync"); - ResourceLocation AZ_ENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID = AzureLib.modResource("az_entity_dispatch_command_sync"); + ResourceLocation AZ_ENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID = AzureLib.modResource( + "az_entity_dispatch_command_sync" + ); ResourceLocation ENTITY_ANIM_DATA_SYNC_PACKET_ID = AzureLib.modResource("entity_anim_data_sync"); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java index 20c769846..1a53e228c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java @@ -1,13 +1,14 @@ package mod.azure.azurelib.core2.animation.dispatch; +import net.minecraft.world.entity.Entity; + +import java.util.List; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.network.packet.AzEntityDispatchCommandPacket; import mod.azure.azurelib.common.platform.Services; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; -import net.minecraft.world.entity.Entity; - -import java.util.List; public record AzDispatchExecutor( List commands, diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchSide.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchSide.java index 57ac253a6..4f97ebf0e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchSide.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchSide.java @@ -9,6 +9,7 @@ import java.util.Map; public enum AzDispatchSide implements StringRepresentable { + CLIENT(0), SERVER(1); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatcher.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatcher.java index edbceb471..630e1903b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatcher.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatcher.java @@ -1,11 +1,12 @@ package mod.azure.azurelib.core2.animation.dispatch; -import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; + public class AzDispatcher { private AzDispatcher() {} @@ -20,7 +21,10 @@ public static AzDispatchExecutor fromServer(AzDispatchCommand command, AzDispatc return new AzDispatchExecutor(commands, AzDispatchSide.SERVER); } - private static @NotNull ArrayList unifyCommands(AzDispatchCommand command, AzDispatchCommand[] additionalCommands) { + private static @NotNull ArrayList unifyCommands( + AzDispatchCommand command, + AzDispatchCommand[] additionalCommands + ) { var commands = new ArrayList(); commands.add(command); commands.addAll(List.of(additionalCommands)); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommand.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommand.java index bd0b2f383..4965a2e27 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommand.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommand.java @@ -1,11 +1,11 @@ package mod.azure.azurelib.core2.animation.dispatch.command; -import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; -import mod.azure.azurelib.core2.animation.dispatch.command.action.codec.AzDispatchCommandCodec; - import java.util.Collection; import java.util.List; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.codec.AzDispatchCommandCodec; + public class AzDispatchCommand { public static final AzDispatchCommandCodec CODEC = new AzDispatchCommandCodec(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommandBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommandBuilder.java index 4d524aba6..df8545141 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommandBuilder.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchCommandBuilder.java @@ -1,10 +1,10 @@ package mod.azure.azurelib.core2.animation.dispatch.command; -import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; - import java.util.ArrayList; import java.util.List; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; + public class AzDispatchCommandBuilder> { protected final List actions; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchControllerCommandBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchControllerCommandBuilder.java index 3d0c26a66..74bfcfe08 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchControllerCommandBuilder.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchControllerCommandBuilder.java @@ -9,7 +9,10 @@ public AzDispatchControllerCommandBuilder playAnimation(String animationName) { return this; } - public AzDispatchControllerCommandBuilder playAnimation(String animationName, UnaryOperator builderUnaryOperator) { + public AzDispatchControllerCommandBuilder playAnimation( + String animationName, + UnaryOperator builderUnaryOperator + ) { // TODO: return this; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchRootCommandBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchRootCommandBuilder.java index 939c3bc20..95d73aef8 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchRootCommandBuilder.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzDispatchRootCommandBuilder.java @@ -1,14 +1,14 @@ package mod.azure.azurelib.core2.animation.dispatch.command; +import java.util.ArrayList; +import java.util.List; +import java.util.function.UnaryOperator; + import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAction; import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAllAction; import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootPlayAnimationAction; -import java.util.ArrayList; -import java.util.List; -import java.util.function.UnaryOperator; - public class AzDispatchRootCommandBuilder extends AzDispatchCommandBuilder { private final List actions; @@ -27,7 +27,10 @@ public AzDispatchRootCommandBuilder cancel(String controllerName) { return self(); } - public AzDispatchRootCommandBuilder forController(String controllerName, UnaryOperator builderUnaryOperator) { + public AzDispatchRootCommandBuilder forController( + String controllerName, + UnaryOperator builderUnaryOperator + ) { var builder = new AzDispatchControllerCommandBuilder(); builderUnaryOperator.apply(builder); var command = builder.build(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/AzDispatchAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/AzDispatchAction.java index 9746d48fe..c0af06dce 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/AzDispatchAction.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/AzDispatchAction.java @@ -1,8 +1,9 @@ package mod.azure.azurelib.core2.animation.dispatch.command.action; +import net.minecraft.resources.ResourceLocation; + import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.dispatch.command.action.codec.AzDispatchActionCodec; -import net.minecraft.resources.ResourceLocation; public interface AzDispatchAction { diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchActionCodec.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchActionCodec.java index 48058dc0b..125218f1d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchActionCodec.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchActionCodec.java @@ -1,20 +1,24 @@ package mod.azure.azurelib.core2.animation.dispatch.command.action.codec; -import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; -import mod.azure.azurelib.core2.animation.dispatch.command.action.registry.AzDispatchActionRegistry; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.registry.AzDispatchActionRegistry; + public class AzDispatchActionCodec implements StreamCodec { @Override public @NotNull AzDispatchAction decode(@NotNull FriendlyByteBuf byteBuf) { var id = byteBuf.readShort(); - var codec = AzDispatchActionRegistry.>getCodecOrNull(id); + var codec = AzDispatchActionRegistry + .>getCodecOrNull(id); if (codec == null) { - throw new NullPointerException("Could not find action codec for a given action id while decoding data. ID: " + id); + throw new NullPointerException( + "Could not find action codec for a given action id while decoding data. ID: " + id + ); } return codec.decode(byteBuf); @@ -24,16 +28,23 @@ public class AzDispatchActionCodec implements StreamCodec>getCodecOrNull(resourceLocation); + var codec = AzDispatchActionRegistry + .>getCodecOrNull(resourceLocation); if (id == null) { - throw new NullPointerException("Could not find action id for a given resource location while encoding data. Resource Location: " + resourceLocation); + throw new NullPointerException( + "Could not find action id for a given resource location while encoding data. Resource Location: " + + resourceLocation + ); } byteBuf.writeShort(id); if (codec == null) { - throw new NullPointerException("Could not find action codec for a given resource location while encoding data. Resource Location: " + resourceLocation + ", ID: " + id); + throw new NullPointerException( + "Could not find action codec for a given resource location while encoding data. Resource Location: " + + resourceLocation + ", ID: " + id + ); } codec.encode(byteBuf, action); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchCommandCodec.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchCommandCodec.java index d82473fbc..068ac3e07 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchCommandCodec.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzDispatchCommandCodec.java @@ -1,12 +1,13 @@ package mod.azure.azurelib.core2.animation.dispatch.command.action.codec; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; -import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; + public class AzDispatchCommandCodec implements StreamCodec { @Override diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAction.java index 4ecf0aa88..dd1cf1340 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAction.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAction.java @@ -1,13 +1,14 @@ package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; + public record AzRootCancelAction( String controllerName ) implements AzDispatchAction { @@ -17,6 +18,7 @@ public record AzRootCancelAction( AzRootCancelAction::controllerName, AzRootCancelAction::new ); + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/cancel"); @Override diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAllAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAllAction.java index 4ad32964a..d40ec2026 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAllAction.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAllAction.java @@ -1,15 +1,19 @@ package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; + public class AzRootCancelAllAction implements AzDispatchAction { - public static final StreamCodec CODEC = StreamCodec.unit(new AzRootCancelAllAction()); + public static final StreamCodec CODEC = StreamCodec.unit( + new AzRootCancelAllAction() + ); + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/cancel_all"); @Override @@ -17,7 +21,6 @@ public void handle(AzAnimator animator) { var controllerContainer = animator.getAnimationControllerContainer(); var controllers = controllerContainer.getAll(); - controllers.forEach(controller -> { controller.setCurrentAnimation(null); }); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootPlayAnimationAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootPlayAnimationAction.java index 587575ff6..a72f3ea2d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootPlayAnimationAction.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootPlayAnimationAction.java @@ -1,13 +1,14 @@ package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; + public record AzRootPlayAnimationAction( String controllerName, String animationName @@ -20,6 +21,7 @@ public record AzRootPlayAnimationAction( AzRootPlayAnimationAction::animationName, AzRootPlayAnimationAction::new ); + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/play_animation"); @Override diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetTransitionInSpeedAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetTransitionInSpeedAction.java index 4de70eddf..a41f3bf54 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetTransitionInSpeedAction.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetTransitionInSpeedAction.java @@ -1,15 +1,19 @@ package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; + public class AzRootSetTransitionInSpeedAction implements AzDispatchAction { - public static final StreamCodec CODEC = StreamCodec.unit(new AzRootSetTransitionInSpeedAction()); + public static final StreamCodec CODEC = StreamCodec.unit( + new AzRootSetTransitionInSpeedAction() + ); + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/set_transition_in_speed"); @Override diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/registry/AzDispatchActionRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/registry/AzDispatchActionRegistry.java index 96bf73af6..4daf5e111 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/registry/AzDispatchActionRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/registry/AzDispatchActionRegistry.java @@ -1,11 +1,6 @@ package mod.azure.azurelib.core2.animation.dispatch.command.action.registry; import it.unimi.dsi.fastutil.objects.Object2ShortArrayMap; -import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; -import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAction; -import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAllAction; -import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootPlayAnimationAction; -import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootSetTransitionInSpeedAction; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; @@ -14,10 +9,18 @@ import java.util.HashMap; import java.util.Map; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzDispatchAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAllAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootPlayAnimationAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootSetTransitionInSpeedAction; + public class AzDispatchActionRegistry { private static final Map RESOURCE_LOCATION_TO_ID = new Object2ShortArrayMap<>(); - private static final Map> CODEC_BY_ID = new HashMap<>(); + + private static final Map> CODEC_BY_ID = + new HashMap<>(); private static short NEXT_FREE_ID = 0; @@ -35,7 +38,9 @@ public class AzDispatchActionRegistry { // TODO: } - public static @Nullable > T getCodecOrNull(ResourceLocation resourceLocation) { + public static @Nullable > T getCodecOrNull( + ResourceLocation resourceLocation + ) { var id = RESOURCE_LOCATION_TO_ID.get(resourceLocation); @SuppressWarnings("unchecked") var codec = (T) CODEC_BY_ID.get(id); @@ -52,7 +57,10 @@ public class AzDispatchActionRegistry { return RESOURCE_LOCATION_TO_ID.get(resourceLocation); } - private static void register(ResourceLocation resourceLocation, StreamCodec codec) { + private static void register( + ResourceLocation resourceLocation, + StreamCodec codec + ) { var id = RESOURCE_LOCATION_TO_ID.computeIfAbsent(resourceLocation, ($) -> NEXT_FREE_ID++); CODEC_BY_ID.put(id, codec); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java index 3e6c9d945..9765833b0 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java @@ -1,8 +1,9 @@ package mod.azure.azurelib.core2.animation.impl; +import net.minecraft.world.item.ItemStack; + import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.AzAnimatorConfig; -import net.minecraft.world.item.ItemStack; public abstract class AzItemAnimator extends AzAnimator { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java index f402e38a2..a3e85fee5 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java @@ -3,7 +3,6 @@ import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index bf7b1293f..8d0614676 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -1,6 +1,5 @@ package mod.azure.azurelib.fabric; -import mod.azure.azurelib.common.internal.common.network.packet.AzEntityDispatchCommandPacket; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; @@ -21,6 +20,7 @@ import mod.azure.azurelib.common.internal.common.network.packet.AnimDataSyncPacket; import mod.azure.azurelib.common.internal.common.network.packet.AnimTriggerPacket; import mod.azure.azurelib.common.internal.common.network.packet.AzEntityAnimTriggerPacket; +import mod.azure.azurelib.common.internal.common.network.packet.AzEntityDispatchCommandPacket; import mod.azure.azurelib.common.internal.common.network.packet.BlockEntityAnimDataSyncPacket; import mod.azure.azurelib.common.internal.common.network.packet.BlockEntityAnimTriggerPacket; import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimDataSyncPacket; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java index 570c195fd..c9c577b4f 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java @@ -36,7 +36,8 @@ public class MarauderAnimator extends AzEntityAnimator { private static final AzRawAnimation WALK_ANIMATION = AzRawAnimation.begin().thenLoop(WALK_ANIMATION_NAME); - private static final AzRawAnimation SPAWN_ANIMATION = AzRawAnimation.begin().then(SPAWN_ANIMATION_NAME, AzLoopType.PLAY_ONCE); + private static final AzRawAnimation SPAWN_ANIMATION = AzRawAnimation.begin() + .then(SPAWN_ANIMATION_NAME, AzLoopType.PLAY_ONCE); private static final AzRawAnimation DEATH_ANIMATION = AzRawAnimation.begin() .then(DEATH_ANIMATION_NAME, AzLoopType.HOLD_ON_LAST_FRAME); @@ -89,31 +90,31 @@ public void registerControllers(AzAnimationControllerContainer a } if (event.getKeyframeData().getSound().equals("portal")) { event.getAnimatable() - .level() - .playLocalSound( - event.getAnimatable().getX(), - event.getAnimatable().getY(), - event.getAnimatable().getZ(), - SoundEvents.PORTAL_AMBIENT, - SoundSource.HOSTILE, - 0.20F, - 1.0F, - true - ); + .level() + .playLocalSound( + event.getAnimatable().getX(), + event.getAnimatable().getY(), + event.getAnimatable().getZ(), + SoundEvents.PORTAL_AMBIENT, + SoundSource.HOSTILE, + 0.20F, + 1.0F, + true + ); } if (event.getKeyframeData().getSound().equals("axe")) { event.getAnimatable() - .level() - .playLocalSound( - event.getAnimatable().getX(), - event.getAnimatable().getY(), - event.getAnimatable().getZ(), - SoundEvents.ENDER_EYE_LAUNCH, - SoundSource.HOSTILE, - 1.00F, - 1.0F, - true - ); + .level() + .playLocalSound( + event.getAnimatable().getX(), + event.getAnimatable().getY(), + event.getAnimatable().getZ(), + SoundEvents.ENDER_EYE_LAUNCH, + SoundSource.HOSTILE, + 1.00F, + 1.0F, + true + ); } } ) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java index 7f7d8efdc..b62ab03e8 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java @@ -44,7 +44,7 @@ public float maxUpStep() { protected void tickDeath() { ++this.deathTime; if (this.deathTime >= 80 && !this.level().isClientSide() && !this.isRemoved()) { - this.level().broadcastEntityEvent(this, (byte)60); + this.level().broadcastEntityEvent(this, (byte) 60); this.remove(RemovalReason.KILLED); } } From 5226bcf2a39f044512b9fa8ad53c202d75e73a1d Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 19 Dec 2024 14:19:15 -0500 Subject: [PATCH 115/224] Implemented item stack animator caching logic (mostly). Signed-off-by: = --- .../common/internal/common/AzureLib.java | 13 +++++++ .../ItemStackMixin_AzItemAnimatorCache.java | 5 +++ .../AzIdentifiableItemStackAnimatorCache.java | 38 +++++++++++++++++++ .../core2/render/item/AzItemRenderer.java | 29 +++++++------- .../resources/azurelib.fabric.mixins.json | 1 + .../main/resources/azurelib.neo.mixins.json | 1 + 6 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentifiableItemStackAnimatorCache.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java index b869debf2..2f19aabd2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java @@ -1,6 +1,7 @@ package mod.azure.azurelib.common.internal.common; import com.mojang.serialization.Codec; +import net.minecraft.core.UUIDUtil; import net.minecraft.core.component.DataComponentType; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.resources.ResourceLocation; @@ -9,6 +10,7 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; +import java.util.UUID; import java.util.function.Supplier; import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; @@ -29,6 +31,10 @@ public final class AzureLib { public static final Marker MAIN_MARKER = MarkerManager.getMarker("main"); + /** + * @deprecated + */ + @Deprecated(forRemoval = true) public static final Supplier> STACK_ANIMATABLE_ID_COMPONENT = Services.PLATFORM .registerDataComponent( "stack_animatable_id", @@ -38,6 +44,13 @@ public final class AzureLib { ) ); + public static final Supplier> AZ_ID = Services.PLATFORM + .registerDataComponent( + "az_id", + builder -> builder.persistent(UUIDUtil.CODEC) + .networkSynchronized(UUIDUtil.STREAM_CODEC) + ); + public static boolean hasInitialized; public static boolean hasKeyBindsInitialized; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java index 92dc7f6e1..49a684e95 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java @@ -2,6 +2,7 @@ import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.cache.AzIdentifiableItemStackAnimatorCache; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; @@ -21,6 +22,10 @@ public void setAnimator(@Nullable AzAnimator animator) { @Override public @Nullable AzAnimator getAnimatorOrNull() { + // TODO: Use a utility function to perform this type of cast. + @SuppressWarnings("all") + var self = (ItemStack) ((Object) this); + AzIdentifiableItemStackAnimatorCache.getInstance().add(self); return animator; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentifiableItemStackAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentifiableItemStackAnimatorCache.java new file mode 100644 index 000000000..a8b618b5e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentifiableItemStackAnimatorCache.java @@ -0,0 +1,38 @@ +package mod.azure.azurelib.core2.animation.cache; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class AzIdentifiableItemStackAnimatorCache { + + private static final AzIdentifiableItemStackAnimatorCache INSTANCE = new AzIdentifiableItemStackAnimatorCache(); + + // TODO: Purge null empty weak reference mappings periodically. + private static final Map> ITEM_STACKS_BY_UUID = new HashMap<>(); + + public static AzIdentifiableItemStackAnimatorCache getInstance() { + return INSTANCE; + } + + public void add(ItemStack itemStack) { + var uuid = itemStack.get(AzureLib.AZ_ID.get()); + + if (uuid != null) { + ITEM_STACKS_BY_UUID.computeIfAbsent(uuid, ($) -> new WeakReference<>(itemStack)); + } + } + + public @Nullable AzItemAnimator getOrNull(UUID uuid) { + var itemStackReference = ITEM_STACKS_BY_UUID.get(uuid); + var itemStack = itemStackReference.get(); + return itemStack == null ? null : (AzItemAnimator) AzAnimatorAccessor.getOrNull(itemStack); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java index 8f1cbb111..73f1c4e4d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -5,7 +5,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import net.minecraft.client.Minecraft; import net.minecraft.client.model.geom.EntityModelSet; import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; @@ -22,6 +21,7 @@ import java.util.List; import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; @@ -190,23 +190,22 @@ protected void renderInGui( protected @Nullable AzItemAnimator provideAnimator(ItemStack itemStack, ItemStack item) { // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for // the item. - var accessor = AzAnimatorAccessor.cast(itemStack); - // TODO: This won't work for items. Need to use an itemStack + id, instead. - var cachedItemAnimator = (AzItemAnimator) accessor.getAnimatorOrNull(); + var accessor = AzAnimatorAccessor.cast(itemStack); + var cachedItemAnimator = (AzItemAnimator) accessor.getAnimatorOrNull(); - if (cachedItemAnimator == null) { + if (cachedItemAnimator == null) { // If the cached animator is null, create a new one. We use a separate reference here just for some - cachedItemAnimator = createAnimator(); - - if (cachedItemAnimator != null) { - // If the new animator we created is not null, then register its controllers. - cachedItemAnimator.registerControllers(cachedItemAnimator.getAnimationControllerContainer()); - // Also cache the animator so that the next time we fetch the animator, it's ready for us. - accessor.setAnimator(cachedItemAnimator); - } - } + cachedItemAnimator = createAnimator(); + + if (cachedItemAnimator != null) { + // If the new animator we created is not null, then register its controllers. + cachedItemAnimator.registerControllers(cachedItemAnimator.getAnimationControllerContainer()); + // Also cache the animator so that the next time we fetch the animator, it's ready for us. + accessor.setAnimator(cachedItemAnimator); + } + } - return cachedItemAnimator; + return cachedItemAnimator; } /** diff --git a/fabric/src/main/resources/azurelib.fabric.mixins.json b/fabric/src/main/resources/azurelib.fabric.mixins.json index 2cb6f7576..08d156654 100644 --- a/fabric/src/main/resources/azurelib.fabric.mixins.json +++ b/fabric/src/main/resources/azurelib.fabric.mixins.json @@ -11,6 +11,7 @@ "client": [ "EntityMixin_AzEntityAnimatorCache", "ItemRendererAccessor", + "ItemStackMixin_AzItemAnimatorCache", "LivingEntityMixin_EDARefManagement", "MinecraftMixin", "MixinHumanoidArmorLayer", diff --git a/neo/src/main/resources/azurelib.neo.mixins.json b/neo/src/main/resources/azurelib.neo.mixins.json index 05846b1d3..4a8ea8f50 100644 --- a/neo/src/main/resources/azurelib.neo.mixins.json +++ b/neo/src/main/resources/azurelib.neo.mixins.json @@ -11,6 +11,7 @@ "client": [ "EntityMixin_AzEntityAnimatorCache", "ItemRendererAccessor", + "ItemStackMixin_AzItemAnimatorCache", "LivingEntityMixin_EDARefManagement", "MinecraftMixin", "MixinItemRenderer", From 99776508f02b3aa1114616eaa1e0498dd76c1f23 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 19 Dec 2024 16:29:23 -0500 Subject: [PATCH 116/224] Implemented WeakSelfReference.java. Signed-off-by: = --- .../core2/util/WeakSelfReference.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/util/WeakSelfReference.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/WeakSelfReference.java b/common/src/main/java/mod/azure/azurelib/core2/util/WeakSelfReference.java new file mode 100644 index 000000000..2b95f6845 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/WeakSelfReference.java @@ -0,0 +1,24 @@ +package mod.azure.azurelib.core2.util; + +import java.lang.ref.WeakReference; + +/** + * Gets a cached {@link WeakReference} from an object. Types implementing this interface should store a {@code final} + * field of a WeakReference type containing a reference to {@code this}. + * + * @param The type of the instance to hold a {@link WeakReference} to. + */ +public interface WeakSelfReference { + + WeakReference getOrCreateRef(); + + static WeakReference getOrCreateRef(T target) { + if (target instanceof WeakSelfReference weakSelfReference) { + @SuppressWarnings("unchecked") + var ref = (WeakReference) weakSelfReference.getOrCreateRef(); + return ref; + } + + return new WeakReference<>(target); + } +} From 64369a74abb72fdc2db62ad360e05b3fd2a204a1 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 19 Dec 2024 16:30:38 -0500 Subject: [PATCH 117/224] Fixed an animation bug with AzLoopType.PLAY_ONCE not working properly. Signed-off-by: = --- .../state/impl/AzAnimationPlayState.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java index 5a6a44e28..629784d3d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java @@ -36,8 +36,16 @@ public void onUpdate(AzAnimationControllerStateMachine.Context context) { var hasAnimationFinished = controllerTimer.getAdjustedTick() >= currentAnimation.animation().length(); if (hasAnimationFinished) { - tryPlayAgain(context, currentAnimation); - // Regardless of if we should play again, the animation has finished, so return. + var shouldPlayAgain = shouldPlayAgain(context, currentAnimation); + + if (shouldPlayAgain) { + // If it should play again, then we simply play the animation again. + playAgain(context); + } else { + // Nothing more to do at this point since we can't play the animation again, so stop. + context.getStateMachine().stop(); + return; + } } // The animation is still running at this point, proceed with updating the bones according to keyframes. @@ -73,7 +81,7 @@ private void tryPlayNextOrStop(AzAnimationControllerStateMachine.Context cont controller.setCurrentAnimation(nextAnimation); } - private void tryPlayAgain( + private boolean shouldPlayAgain( AzAnimationControllerStateMachine.Context context, AzQueuedAnimation currentAnimation ) { @@ -81,13 +89,8 @@ private void tryPlayAgain( var controller = context.getAnimationController(); // If it has, we then need to see if the animation should play again. - var shouldPlayAgain = currentAnimation.loopType() + return currentAnimation.loopType() .shouldPlayAgain(animatable, controller, currentAnimation.animation()); - - if (shouldPlayAgain) { - // If it should play again, then we simply play the animation again. - playAgain(context); - } } protected void playAgain(AzAnimationControllerStateMachine.Context context) { From 77e71f018242b054788c6751e367a9a1f47f2748 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 19 Dec 2024 16:39:19 -0500 Subject: [PATCH 118/224] Finished implementing item animations. Signed-off-by: = --- .../AzItemStackDispatchCommandPacket.java | 51 ++++++++++++++ .../ItemStackMixin_AzItemAnimatorCache.java | 21 ++++-- .../internal/mixins/MixinItemRenderer.java | 15 ++-- .../platform/services/AzureLibNetwork.java | 4 ++ .../AzIdentifiableItemStackAnimatorCache.java | 17 +++-- .../dispatch/AzDispatchExecutor.java | 69 +++++++++++-------- .../render/item/AzItemRendererRegistry.java | 20 ++++++ .../azure/azurelib/fabric/ClientListener.java | 7 ++ .../azurelib/fabric/FabricAzureLibMod.java | 7 +- .../fabric/core2/example/items/AzPistol.java | 62 ++--------------- .../items/AzPistolAnimationDispatcher.java | 20 ++++++ .../core2/example/items/AzPistolAnimator.java | 42 +++++++++++ ...istolRender.java => AzPistolRenderer.java} | 9 ++- .../neoforge/NeoForgeAzureLibMod.java | 5 ++ 14 files changed, 246 insertions(+), 103 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzItemStackDispatchCommandPacket.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererRegistry.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimationDispatcher.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimator.java rename fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/{AzPistolRender.java => AzPistolRenderer.java} (73%) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzItemStackDispatchCommandPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzItemStackDispatchCommandPacket.java new file mode 100644 index 000000000..da7b4ac71 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzItemStackDispatchCommandPacket.java @@ -0,0 +1,51 @@ +package mod.azure.azurelib.common.internal.common.network.packet; + +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.core2.animation.cache.AzIdentifiableItemStackAnimatorCache; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; + +public record AzItemStackDispatchCommandPacket( + UUID itemStackId, + AzDispatchCommand dispatchCommand, + AzDispatchSide origin +) implements AbstractPacket { + + public static final Type TYPE = new Type<>( + AzureLibNetwork.AZ_ITEM_STACK_DISPATCH_COMMAND_SYNC_PACKET_ID + ); + + public static final StreamCodec CODEC = StreamCodec.composite( + UUIDUtil.STREAM_CODEC, + AzItemStackDispatchCommandPacket::itemStackId, + AzDispatchCommand.CODEC, + AzItemStackDispatchCommandPacket::dispatchCommand, + AzDispatchSide.CODEC, + AzItemStackDispatchCommandPacket::origin, + AzItemStackDispatchCommandPacket::new + ); + + public void handle() { + var animator = AzIdentifiableItemStackAnimatorCache.getInstance().getOrNull(itemStackId); + + if (animator != null) { + dispatchCommand.getActions().forEach(action -> action.handle(animator)); + } else { + // TODO: queue command. + } + } + + @Override + public @NotNull Type type() { + return TYPE; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java index 49a684e95..87586eaf9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java @@ -1,20 +1,28 @@ package mod.azure.azurelib.common.internal.mixins; -import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; -import mod.azure.azurelib.core2.animation.cache.AzIdentifiableItemStackAnimatorCache; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; +import java.lang.ref.WeakReference; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.cache.AzIdentifiableItemStackAnimatorCache; +import mod.azure.azurelib.core2.util.WeakSelfReference; + @Mixin(ItemStack.class) -public abstract class ItemStackMixin_AzItemAnimatorCache implements AzAnimatorAccessor { +public abstract class ItemStackMixin_AzItemAnimatorCache implements AzAnimatorAccessor, WeakSelfReference { @Unique @Nullable private AzAnimator animator; + @Unique + @SuppressWarnings("all") + private final WeakReference ref = new WeakReference<>(((ItemStack) ((Object) this))); + @Override public void setAnimator(@Nullable AzAnimator animator) { this.animator = animator; @@ -28,4 +36,9 @@ public void setAnimator(@Nullable AzAnimator animator) { AzIdentifiableItemStackAnimatorCache.getInstance().add(self); return animator; } + + @Override + public WeakReference getOrCreateRef() { + return ref; + } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java index c3b64ba3a..457fcd457 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java @@ -18,14 +18,12 @@ import mod.azure.azurelib.common.api.common.animatable.GeoItem; import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.core2.render.item.AzItemRendererRegistry; /** * Render hook to inject AzureLib's ISTER rendering callback - * - * @deprecated */ @Mixin(ItemRenderer.class) -@Deprecated(forRemoval = true) public class MixinItemRenderer { @Inject( @@ -45,9 +43,18 @@ public void itemModelHook( BakedModel bakedModel, CallbackInfo ci ) { - if (itemStack.getItem() instanceof GeoItem) + // TODO: Remove this along with Geo-code. + if (itemStack.getItem() instanceof GeoItem) { RenderProvider.of(itemStack) .getCustomRenderer() .renderByItem(itemStack, transformType, poseStack, multiBufferSource, i, j); + } + + var item = itemStack.getItem(); + var renderer = AzItemRendererRegistry.getOrNull(item); + + if (renderer != null) { + renderer.renderByItem(itemStack, transformType, poseStack, multiBufferSource, i, j); + } } } diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java index b464cb9b0..9b65ab8fb 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java @@ -30,6 +30,10 @@ public interface AzureLibNetwork { "az_entity_dispatch_command_sync" ); + ResourceLocation AZ_ITEM_STACK_DISPATCH_COMMAND_SYNC_PACKET_ID = AzureLib.modResource( + "az_item_stack_dispatch_command_sync" + ); + ResourceLocation ENTITY_ANIM_DATA_SYNC_PACKET_ID = AzureLib.modResource("entity_anim_data_sync"); ResourceLocation ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("entity_anim_trigger_sync"); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentifiableItemStackAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentifiableItemStackAnimatorCache.java index a8b618b5e..1e78a60a6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentifiableItemStackAnimatorCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentifiableItemStackAnimatorCache.java @@ -1,8 +1,5 @@ package mod.azure.azurelib.core2.animation.cache; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; -import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; @@ -11,6 +8,11 @@ import java.util.Map; import java.util.UUID; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; +import mod.azure.azurelib.core2.util.WeakSelfReference; + public class AzIdentifiableItemStackAnimatorCache { private static final AzIdentifiableItemStackAnimatorCache INSTANCE = new AzIdentifiableItemStackAnimatorCache(); @@ -26,13 +28,20 @@ public void add(ItemStack itemStack) { var uuid = itemStack.get(AzureLib.AZ_ID.get()); if (uuid != null) { - ITEM_STACKS_BY_UUID.computeIfAbsent(uuid, ($) -> new WeakReference<>(itemStack)); + // Always update the reference in the cache. WeakSelfReference is memory-efficient if stable so don't worry. + ITEM_STACKS_BY_UUID.put(uuid, WeakSelfReference.getOrCreateRef(itemStack)); } } public @Nullable AzItemAnimator getOrNull(UUID uuid) { var itemStackReference = ITEM_STACKS_BY_UUID.get(uuid); + + if (itemStackReference == null) { + return null; + } + var itemStack = itemStackReference.get(); + return itemStack == null ? null : (AzItemAnimator) AzAnimatorAccessor.getOrNull(itemStack); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java index 1a53e228c..75da05d8f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java @@ -1,11 +1,15 @@ package mod.azure.azurelib.core2.animation.dispatch; +import net.minecraft.core.component.PatchedDataComponentMap; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; import java.util.List; +import java.util.UUID; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.network.packet.AzEntityDispatchCommandPacket; +import mod.azure.azurelib.common.internal.common.network.packet.AzItemStackDispatchCommandPacket; import mod.azure.azurelib.common.platform.Services; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; @@ -16,25 +20,44 @@ public record AzDispatchExecutor( ) { public void sendForEntity(Entity entity) { + if (!canNotProceed(entity)) { + // TODO: Log here. + return; + } + switch (origin) { case CLIENT -> dispatchFromClient(entity); - case SERVER -> dispatchFromServer(entity); + case SERVER -> handleServerDispatchForEntity(entity); } } - private void dispatchFromClient(T animatable) { - if (origin != AzDispatchSide.CLIENT) { - AzureLib.LOGGER.warn("Dispatch origin mismatch - expected CLIENT, got {}.", origin); + public void sendForItem(Entity entity, ItemStack itemStack) { + if (!canNotProceed(entity)) { + // TODO: Log here. return; } - var isClientSide = isClientSide(animatable); + // TODO: What if this isn't a PatchedDataComponentMap? + if ( + itemStack.getComponents() instanceof PatchedDataComponentMap components && !components.has( + AzureLib.AZ_ID.get() + ) + ) { + components.set(AzureLib.AZ_ID.get(), UUID.randomUUID()); + } - if (!isClientSide) { - AzureLib.LOGGER.warn("Attempted client-side animation dispatch from server side."); - return; + switch (origin) { + case CLIENT -> dispatchFromClient(itemStack); + case SERVER -> handleServerDispatchForItem(entity, itemStack); } + } + + private boolean canNotProceed(T animatable) { + var isLogicalClientSide = isClientSide(animatable); + return (origin == AzDispatchSide.CLIENT) == isLogicalClientSide; + } + private void dispatchFromClient(T animatable) { var animator = AzAnimatorAccessor.getOrNull(animatable); if (animator != null) { @@ -44,27 +67,6 @@ private void dispatchFromClient(T animatable) { } } - private void dispatchFromServer(T animatable) { - if (origin != AzDispatchSide.SERVER) { - AzureLib.LOGGER.warn("Dispatch origin mismatch - expected SERVER, got {}.", origin); - return; - } - - var isClientSide = isClientSide(animatable); - - if (isClientSide) { - AzureLib.LOGGER.warn("Attempted server-side animation dispatch from client side."); - return; - } - - if (animatable instanceof Entity entity) { - handleServerDispatchForEntity(entity); - } - // TODO: Armors - // TODO: Blocks - // TODO: Items - } - private void handleServerDispatchForEntity(Entity entity) { var entityId = entity.getId(); @@ -75,6 +77,15 @@ private void handleServerDispatchForEntity(Entity entity) { }); } + private void handleServerDispatchForItem(Entity entity, ItemStack itemStack) { + var uuid = itemStack.get(AzureLib.AZ_ID.get()); + commands.forEach(command -> { + // TODO: Buffer commands together. + var packet = new AzItemStackDispatchCommandPacket(uuid, command, origin); + Services.NETWORK.sendToTrackingEntityAndSelf(packet, entity); + }); + } + private boolean isClientSide(T animatable) { if (animatable instanceof Entity entity) { return entity.level().isClientSide(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererRegistry.java new file mode 100644 index 000000000..ac2fee7ec --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererRegistry.java @@ -0,0 +1,20 @@ +package mod.azure.azurelib.core2.render.item; + +import net.minecraft.world.item.Item; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public class AzItemRendererRegistry { + + private static final Map ITEM_TO_RENDERER = new HashMap<>(); + + public static void register(Item item, AzItemRenderer itemRenderer) { + ITEM_TO_RENDERER.put(item, itemRenderer); + } + + public static @Nullable AzItemRenderer getOrNull(Item item) { + return ITEM_TO_RENDERER.get(item); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index 82da36f84..dae0227fc 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -15,11 +15,13 @@ import mod.azure.azurelib.common.api.client.helper.ClientUtils; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.network.packet.*; +import mod.azure.azurelib.core2.render.item.AzItemRendererRegistry; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; import mod.azure.azurelib.fabric.core2.example.blocks.StargateRender; import mod.azure.azurelib.fabric.core2.example.entities.doomhunter.DoomHunterRenderer; import mod.azure.azurelib.fabric.core2.example.entities.drone.DroneRenderer; import mod.azure.azurelib.fabric.core2.example.entities.marauder.MarauderRenderer; +import mod.azure.azurelib.fabric.core2.example.items.AzPistolRenderer; public final class ClientListener implements ClientModInitializer { @@ -65,6 +67,10 @@ public void onInitializeClient() { AzEntityDispatchCommandPacket.TYPE, (packet, context) -> packet.handle() ); + ClientPlayNetworking.registerGlobalReceiver( + AzItemStackDispatchCommandPacket.TYPE, + (packet, context) -> packet.handle() + ); ClientPlayNetworking.registerGlobalReceiver( EntityAnimDataSyncPacket.TYPE, (packet, context) -> packet.handle() @@ -73,6 +79,7 @@ public void onInitializeClient() { ClientPlayNetworking.registerGlobalReceiver(AnimDataSyncPacket.TYPE, (packet, context) -> packet.handle()); ClientPlayNetworking.registerGlobalReceiver(SendConfigDataPacket.TYPE, (packet, context) -> packet.handle()); + AzItemRendererRegistry.register(FabricAzureLibMod.AZ_PISTOL, new AzPistolRenderer()); EntityRendererRegistry.register(ExampleEntityTypes.DRONE, DroneRenderer::new); EntityRendererRegistry.register(ExampleEntityTypes.DOOMHUNTER, DoomHunterRenderer::new); EntityRendererRegistry.register(ExampleEntityTypes.MARAUDER, MarauderRenderer::new); diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 8d0614676..43c434819 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -21,6 +21,7 @@ import mod.azure.azurelib.common.internal.common.network.packet.AnimTriggerPacket; import mod.azure.azurelib.common.internal.common.network.packet.AzEntityAnimTriggerPacket; import mod.azure.azurelib.common.internal.common.network.packet.AzEntityDispatchCommandPacket; +import mod.azure.azurelib.common.internal.common.network.packet.AzItemStackDispatchCommandPacket; import mod.azure.azurelib.common.internal.common.network.packet.BlockEntityAnimDataSyncPacket; import mod.azure.azurelib.common.internal.common.network.packet.BlockEntityAnimTriggerPacket; import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimDataSyncPacket; @@ -39,6 +40,8 @@ public final class FabricAzureLibMod implements ModInitializer { BlockBehaviour.Properties.of().sound(SoundType.DRIPSTONE_BLOCK).strength(5.0f, 8.0f).noOcclusion() ); + public static final Item AZ_PISTOL = new AzPistol(); + @Override public void onInitialize() { ConfigIO.FILE_WATCH_MANAGER.startService(); @@ -52,6 +55,8 @@ public void onInitialize() { PayloadTypeRegistry.playS2C().register(EntityAnimTriggerPacket.TYPE, EntityAnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(AzEntityAnimTriggerPacket.TYPE, AzEntityAnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(AzEntityDispatchCommandPacket.TYPE, AzEntityDispatchCommandPacket.CODEC); + PayloadTypeRegistry.playS2C() + .register(AzItemStackDispatchCommandPacket.TYPE, AzItemStackDispatchCommandPacket.CODEC); PayloadTypeRegistry.playS2C().register(EntityAnimDataSyncPacket.TYPE, EntityAnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(AnimTriggerPacket.TYPE, AnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(AnimDataSyncPacket.TYPE, AnimDataSyncPacket.CODEC); @@ -70,7 +75,7 @@ public void onInitialize() { Registry.register( BuiltInRegistries.ITEM, AzureLib.modResource("az_pistol"), - new AzPistol() + AZ_PISTOL ); Registry.register( BuiltInRegistries.ITEM, diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java index 5b0b36cdb..57511efc7 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java @@ -1,7 +1,5 @@ package mod.azure.azurelib.fabric.core2.example.items; -import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.LivingEntity; @@ -11,43 +9,20 @@ import net.minecraft.world.level.Level; import org.jetbrains.annotations.NotNull; -import java.util.function.Consumer; +public class AzPistol extends Item { -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; -import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; -import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; -import mod.azure.azurelib.core.animation.AnimatableManager; -import mod.azure.azurelib.core.animation.Animation; -import mod.azure.azurelib.core.animation.AnimationController; -import mod.azure.azurelib.core.animation.RawAnimation; -import mod.azure.azurelib.core.object.PlayState; - -public class AzPistol extends Item implements GeoItem { - - private final AnimatableInstanceCache cache = AzureLibUtil.createInstanceCache(this); - - private static final String FIRING_ANIMATION_NAME = "firing"; - - private static final RawAnimation FIRING_ANIMATION = RawAnimation.begin() - .then(FIRING_ANIMATION_NAME, Animation.LoopType.PLAY_ONCE); + private final AzPistolAnimationDispatcher dispatcher; public AzPistol() { super(new Properties()); - SingletonGeoAnimatable.registerSyncedAnimatable(this); // Needed to make triggerable animations work + this.dispatcher = new AzPistolAnimationDispatcher(); } @Override public void onUseTick(Level level, LivingEntity livingEntity, ItemStack stack, int remainingUseDuration) { super.onUseTick(level, livingEntity, stack, remainingUseDuration); if (livingEntity instanceof Player player && !level.isClientSide()) { - triggerAnim( - player, - GeoItem.getOrAssignId(stack, (ServerLevel) level), - "base_controller", - FIRING_ANIMATION_NAME - ); + dispatcher.serverFire(player, stack); } } @@ -61,33 +36,4 @@ public void onUseTick(Level level, LivingEntity livingEntity, ItemStack stack, i user.startUsingItem(hand); return InteractionResultHolder.consume(itemStack); } - - @Override - public void createRenderer(Consumer consumer) { - consumer.accept(new RenderProvider() { - - private AzPistolRender renderer = null; - - @Override - public BlockEntityWithoutLevelRenderer getCustomRenderer() { - this.renderer = new AzPistolRender(); - return this.renderer; - } - }); - } - - @Override - public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { - controllers.add( - new AnimationController<>(this, "base_controller", event -> PlayState.CONTINUE).triggerableAnim( - FIRING_ANIMATION_NAME, - FIRING_ANIMATION - ) - ); - } - - @Override - public AnimatableInstanceCache getAnimatableInstanceCache() { - return cache; - } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimationDispatcher.java new file mode 100644 index 000000000..338652902 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimationDispatcher.java @@ -0,0 +1,20 @@ +package mod.azure.azurelib.fabric.core2.example.items; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; + +import mod.azure.azurelib.core2.animation.dispatch.AzDispatcher; +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; + +public class AzPistolAnimationDispatcher { + + private static final String FIRING_ANIMATION_NAME = "firing"; + + private static final AzDispatchCommand FIRING_COMMAND = AzDispatchCommand.builder() + .playAnimation("base_controller", FIRING_ANIMATION_NAME) + .build(); + + public void serverFire(Entity entity, ItemStack itemStack) { + AzDispatcher.fromServer(FIRING_COMMAND).sendForItem(entity, itemStack); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimator.java new file mode 100644 index 000000000..da8c4e75b --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimator.java @@ -0,0 +1,42 @@ +package mod.azure.azurelib.fabric.core2.example.items; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; +import mod.azure.azurelib.core2.animation.primitive.AzLoopType; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; + +public class AzPistolAnimator extends AzItemAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource("animations/item/pistol.animation.json"); + + private static final String FIRING_ANIMATION_NAME = "firing"; + + private static final AzRawAnimation FIRING_ANIMATION = AzRawAnimation.begin() + .then(FIRING_ANIMATION_NAME, AzLoopType.PLAY_ONCE); + + public AzPistolAnimator() { + super(AzAnimatorConfig.defaultConfig()); + } + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + AzAnimationController.builder(this, "base_controller") + .triggerableAnim(FIRING_ANIMATION_NAME, FIRING_ANIMATION) + .build() + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(ItemStack animatable) { + return ANIMATIONS; + } + +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRender.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java similarity index 73% rename from fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRender.java rename to fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java index 194153425..dac7a95cc 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRender.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java @@ -3,18 +3,21 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; import mod.azure.azurelib.core2.render.item.AzItemRenderer; -public class AzPistolRender extends AzItemRenderer { +public class AzPistolRenderer extends AzItemRenderer { private static final ResourceLocation MODEL = AzureLib.modResource("geo/item/pistol.geo.json"); private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/item/pistol.png"); - public AzPistolRender() { - super(); + @Override + protected @Nullable AzItemAnimator createAnimator() { + return new AzPistolAnimator(); } @Override diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java index b7dcdee47..378b9cc42 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java @@ -68,6 +68,11 @@ public void registerMessages(RegisterPayloadHandlersEvent event) { AzEntityDispatchCommandPacket.CODEC, (msg, ctx) -> msg.handle() ); + registrar.playBidirectional( + AzItemStackDispatchCommandPacket.TYPE, + AzItemStackDispatchCommandPacket.CODEC, + (msg, ctx) -> msg.handle() + ); registrar.playBidirectional( EntityAnimDataSyncPacket.TYPE, EntityAnimDataSyncPacket.CODEC, From 6097e78c22ec790b5bc819a2b6e7db596280df40 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 20:20:45 -0500 Subject: [PATCH 119/224] Remove old pistol example --- .../azurelib/fabric/FabricAzureLibMod.java | 6 -- .../fabric/core2/example/items/Pistol.java | 93 ------------------- .../core2/example/items/PistolRender.java | 12 --- 3 files changed, 111 deletions(-) delete mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/Pistol.java delete mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/PistolRender.java diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 43c434819..abbcfabf7 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -31,7 +31,6 @@ import mod.azure.azurelib.fabric.core2.example.armors.DoomArmor; import mod.azure.azurelib.fabric.core2.example.blocks.Stargate; import mod.azure.azurelib.fabric.core2.example.items.AzPistol; -import mod.azure.azurelib.fabric.core2.example.items.Pistol; import mod.azure.azurelib.fabric.platform.FabricAzureLibNetwork; public final class FabricAzureLibMod implements ModInitializer { @@ -67,11 +66,6 @@ public void onInitialize() { AzureLib.modResource("stargate"), new BlockItem(STARGATE, new Item.Properties()) ); - Registry.register( - BuiltInRegistries.ITEM, - AzureLib.modResource("pistol"), - new Pistol() - ); Registry.register( BuiltInRegistries.ITEM, AzureLib.modResource("az_pistol"), diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/Pistol.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/Pistol.java deleted file mode 100644 index b3278c673..000000000 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/Pistol.java +++ /dev/null @@ -1,93 +0,0 @@ -package mod.azure.azurelib.fabric.core2.example.items; - -import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResultHolder; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Consumer; - -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; -import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; -import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; -import mod.azure.azurelib.core.animation.AnimatableManager; -import mod.azure.azurelib.core.animation.Animation; -import mod.azure.azurelib.core.animation.AnimationController; -import mod.azure.azurelib.core.animation.RawAnimation; -import mod.azure.azurelib.core.object.PlayState; - -public class Pistol extends Item implements GeoItem { - - private final AnimatableInstanceCache cache = AzureLibUtil.createInstanceCache(this); - - private static final String FIRING_ANIMATION_NAME = "firing"; - - private static final RawAnimation FIRING_ANIMATION = RawAnimation.begin() - .then(FIRING_ANIMATION_NAME, Animation.LoopType.PLAY_ONCE); - - public Pistol() { - super(new Properties()); - SingletonGeoAnimatable.registerSyncedAnimatable(this); // Needed to make triggerable animations work - } - - @Override - public void onUseTick(Level level, LivingEntity livingEntity, ItemStack stack, int remainingUseDuration) { - super.onUseTick(level, livingEntity, stack, remainingUseDuration); - if (livingEntity instanceof Player player && !level.isClientSide()) { - triggerAnim( - player, - GeoItem.getOrAssignId(stack, (ServerLevel) level), - "base_controller", - FIRING_ANIMATION_NAME - ); - } - } - - @Override - public @NotNull InteractionResultHolder use( - @NotNull Level world, - Player user, - @NotNull InteractionHand hand - ) { - final var itemStack = user.getItemInHand(hand); - user.startUsingItem(hand); - return InteractionResultHolder.consume(itemStack); - } - - @Override - public void createRenderer(Consumer consumer) { - consumer.accept(new RenderProvider() { - - private PistolRender renderer = null; - - @Override - public BlockEntityWithoutLevelRenderer getCustomRenderer() { - this.renderer = new PistolRender(); - return this.renderer; - } - }); - } - - @Override - public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { - controllers.add( - new AnimationController<>(this, "base_controller", event -> PlayState.CONTINUE).triggerableAnim( - FIRING_ANIMATION_NAME, - FIRING_ANIMATION - ) - ); - } - - @Override - public AnimatableInstanceCache getAnimatableInstanceCache() { - return cache; - } -} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/PistolRender.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/PistolRender.java deleted file mode 100644 index 157428209..000000000 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/PistolRender.java +++ /dev/null @@ -1,12 +0,0 @@ -package mod.azure.azurelib.fabric.core2.example.items; - -import mod.azure.azurelib.common.api.client.model.DefaultedItemGeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoItemRenderer; -import mod.azure.azurelib.common.internal.common.AzureLib; - -public class PistolRender extends GeoItemRenderer { - - public PistolRender() { - super(new DefaultedItemGeoModel<>(AzureLib.modResource("pistol"))); - } -} From 42afb9de162e51bcdaaf69873e0e60469be2b3f8 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 20:25:26 -0500 Subject: [PATCH 120/224] Create rendererPipeline getter --- .../core2/render/pipeline/AzRendererPipelineContext.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java index d60eb7c53..f64649b94 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java @@ -104,6 +104,10 @@ protected int getPackedOverlay(T animatable, float u, float partialTick) { return OverlayTexture.NO_OVERLAY; } + public AzRendererPipeline rendererPipeline() { + return rendererPipeline; + } + public T animatable() { return animatable; } From 4ff1b2ef6a4011a056c1d2e7c5beaa685d383598 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 20:25:34 -0500 Subject: [PATCH 121/224] create needed setters --- .../core2/render/pipeline/AzRendererPipelineContext.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java index f64649b94..6dd41352c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java @@ -124,6 +124,10 @@ public int packedLight() { return packedLight; } + public void setPackedLight(int packedLight) { + this.packedLight = packedLight; + } + public int packedOverlay() { return packedOverlay; } @@ -144,6 +148,10 @@ public int renderColor() { return renderType; } + public void setRenderType(@Nullable RenderType renderType) { + this.renderType = renderType; + } + public VertexConsumer vertexConsumer() { return vertexConsumer; } From a45556fbeb701b97a548b3709f0aa690fce3b2a2 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 20:26:09 -0500 Subject: [PATCH 122/224] make getTextureLocation public to be able to get from context pipeline getter --- .../azurelib/core2/render/pipeline/AzRendererPipeline.java | 2 +- .../core2/render/pipeline/impl/AzEntityRendererPipeline.java | 2 +- .../core2/render/pipeline/impl/AzItemRendererPipeline.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index 3189a1cf5..98ecd0e0f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -33,7 +33,7 @@ protected AzRendererPipeline() { protected abstract AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline); - protected abstract @NotNull ResourceLocation getTextureLocation(@NotNull T animatable); + public abstract @NotNull ResourceLocation getTextureLocation(@NotNull T animatable); /** * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java index df897081e..c6e13ebe6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -42,7 +42,7 @@ protected AzRendererPipelineContext createContext(AzRendererPipeline rende } @Override - protected @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { + public @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { return entityRenderer.getTextureLocation(animatable); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java index d3e5ca75b..ae17ed77d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java @@ -34,7 +34,7 @@ protected AzRendererPipelineContext createContext(AzRendererPipeline< } @Override - protected @NotNull ResourceLocation getTextureLocation(@NotNull ItemStack animatable) { + public @NotNull ResourceLocation getTextureLocation(@NotNull ItemStack animatable) { return itemRenderer.getTextureLocation(animatable); } From e82da3100f2e7b3e74e07f25f6550217bacb0138 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 20:26:20 -0500 Subject: [PATCH 123/224] make public so getter can access --- .../azurelib/core2/render/pipeline/AzRendererPipeline.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index 98ecd0e0f..d72696f1b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -86,7 +86,7 @@ public void render( * Usually you'd use this for rendering alternate {@link RenderType} layers or for sub-model rendering whilst inside * a {@link AzRenderLayer} or similar */ - protected void reRender(AzRendererPipelineContext context) { + public void reRender(AzRendererPipelineContext context) { var poseStack = context.poseStack(); poseStack.pushPose(); preRender(context, true); From d99b9fa186f299616aca992334b3f919ee60c37b Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 20:26:35 -0500 Subject: [PATCH 124/224] WIP port of AutoGlowLayer --- .../render/layer/AzAutoGlowingLayer.java | 24 +++++++++++++++++++ .../entities/marauder/MarauderRenderer.java | 2 ++ 2 files changed, 26 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java new file mode 100644 index 000000000..eec4b2631 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java @@ -0,0 +1,24 @@ +package mod.azure.azurelib.core2.render.layer; + +import mod.azure.azurelib.common.internal.common.cache.texture.AutoGlowingTexture; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; + +public class AzAutoGlowingLayer extends AzRenderLayer { + + @Override + public void preRender(AzRendererPipelineContext context) {} + + @Override + public void render(AzRendererPipelineContext context) { + var renderPipeline = context.rendererPipeline(); + context.setRenderType(AutoGlowingTexture.getRenderType(renderPipeline.getTextureLocation(context.animatable()))); + context.setPackedLight(15728640); + if (context.renderType() != null) { + context.rendererPipeline().reRender(context); + } + } + + @Override + public void renderForBone(AzRendererPipelineContext context, AzBone bone) {} +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java index 4aac37ae6..b9c976ad0 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java @@ -1,5 +1,6 @@ package mod.azure.azurelib.fabric.core2.example.entities.marauder; +import mod.azure.azurelib.core2.render.layer.AzAutoGlowingLayer; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; @@ -17,6 +18,7 @@ public class MarauderRenderer extends AzEntityRenderer { public MarauderRenderer(EntityRendererProvider.Context context) { super(context); + addRenderLayer(new AzAutoGlowingLayer()); /** * TODO: Port this to new system, as it currently requries this be a GeoEntity and use the GeoLayers as well */ From 53ee8e43178600edf476116ad3545e749f619584 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 19 Dec 2024 21:18:34 -0500 Subject: [PATCH 125/224] Fixed glow layer not glowing. Signed-off-by: = --- .../render/layer/AzAutoGlowingLayer.java | 30 ++++++++++++++----- .../render/pipeline/AzRendererPipeline.java | 18 ++++++----- .../impl/AzEntityRendererPipeline.java | 8 +++++ .../pipeline/impl/AzItemRendererPipeline.java | 8 +++++ .../entities/marauder/MarauderRenderer.java | 4 +-- 5 files changed, 52 insertions(+), 16 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java index eec4b2631..75ceeb221 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java @@ -4,21 +4,37 @@ import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; -public class AzAutoGlowingLayer extends AzRenderLayer { +public class AzAutoGlowingLayer extends AzRenderLayer { @Override - public void preRender(AzRendererPipelineContext context) {} + public void preRender(AzRendererPipelineContext context) {} @Override - public void render(AzRendererPipelineContext context) { + public void render(AzRendererPipelineContext context) { + var animatable = context.animatable(); var renderPipeline = context.rendererPipeline(); - context.setRenderType(AutoGlowingTexture.getRenderType(renderPipeline.getTextureLocation(context.animatable()))); - context.setPackedLight(15728640); + var textureLocation = renderPipeline.getTextureLocation(animatable); + var renderType = AutoGlowingTexture.getRenderType(textureLocation); + if (context.renderType() != null) { - context.rendererPipeline().reRender(context); + var prevRenderType = context.renderType(); + var prevPackedLight = context.packedLight(); + var prevVertexConsumer = context.vertexConsumer(); + + context.setRenderType(renderType); + context.setPackedLight(0xF00000); + context.setVertexConsumer(context.multiBufferSource().getBuffer(renderType)); + + renderPipeline.reRender(context); + + // Restore context for sanity + // TODO: Should probably cache the context as a whole somewhere and then restore it (a "previous" context). + context.setRenderType(prevRenderType); + context.setPackedLight(prevPackedLight); + context.setVertexConsumer(prevVertexConsumer); } } @Override - public void renderForBone(AzRendererPipelineContext context, AzBone bone) {} + public void renderForBone(AzRendererPipelineContext context, AzBone bone) {} } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index d72696f1b..2dcf7a8b2 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -35,6 +35,11 @@ protected AzRendererPipeline() { public abstract @NotNull ResourceLocation getTextureLocation(@NotNull T animatable); + /** + * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer + */ + protected abstract List> getRenderLayers(); + /** * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this * GeoRenderer.
      @@ -61,6 +66,7 @@ public void render( int packedLight ) { context.populate(animatable, model, bufferSource, packedLight, partialTick, poseStack, renderType, buffer); + poseStack.pushPose(); preRender(context, false); @@ -88,10 +94,13 @@ public void render( */ public void reRender(AzRendererPipelineContext context) { var poseStack = context.poseStack(); + poseStack.pushPose(); + preRender(context, true); actuallyRender(context, true); postRender(context, true); + poseStack.popPose(); } @@ -139,7 +148,9 @@ protected void renderCubesOfBone(AzRendererPipelineContext context, AzBone bo for (var cube : bone.getCubes()) { poseStack.pushPose(); + renderCube(context, cube); + poseStack.popPose(); } } @@ -298,11 +309,4 @@ protected void scaleModelForRender( public AzRendererPipelineContext getContext() { return context; } - - /** - * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer - */ - protected List> getRenderLayers() { - return List.of(); - } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java index c6e13ebe6..8eff8efb5 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -15,12 +15,15 @@ import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; +import java.util.List; + import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.render.entity.AzEntityLeashRenderUtil; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; @@ -46,6 +49,11 @@ protected AzRendererPipelineContext createContext(AzRendererPipeline rende return entityRenderer.getTextureLocation(animatable); } + @Override + protected List> getRenderLayers() { + return entityRenderer.getRenderLayers(); + } + /** * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this * GeoRenderer.
      diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java index ae17ed77d..d1a2af3ce 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java @@ -8,11 +8,14 @@ import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; +import java.util.List; + import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.render.item.AzItemRenderer; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; @@ -38,6 +41,11 @@ protected AzRendererPipelineContext createContext(AzRendererPipeline< return itemRenderer.getTextureLocation(animatable); } + @Override + protected List> getRenderLayers() { + return itemRenderer.getRenderLayers(); + } + /** * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling * and translating.
      diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java index b9c976ad0..170a1ac07 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java @@ -1,6 +1,5 @@ package mod.azure.azurelib.fabric.core2.example.entities.marauder; -import mod.azure.azurelib.core2.render.layer.AzAutoGlowingLayer; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; @@ -9,6 +8,7 @@ import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import mod.azure.azurelib.core2.render.layer.AzAutoGlowingLayer; public class MarauderRenderer extends AzEntityRenderer { @@ -18,7 +18,7 @@ public class MarauderRenderer extends AzEntityRenderer { public MarauderRenderer(EntityRendererProvider.Context context) { super(context); - addRenderLayer(new AzAutoGlowingLayer()); + addRenderLayer(new AzAutoGlowingLayer<>()); /** * TODO: Port this to new system, as it currently requries this be a GeoEntity and use the GeoLayers as well */ From a3c60e966d7844fdef55ea1d03468c48f329de9a Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:29:02 -0500 Subject: [PATCH 126/224] Fixes Marauders portal --- .../textures/entity/marauder_glowmask.png | Bin 7478 -> 8489 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/common/src/main/resources/assets/azurelib/textures/entity/marauder_glowmask.png b/common/src/main/resources/assets/azurelib/textures/entity/marauder_glowmask.png index 388049425fd91a1e71eb9b46010f11cf143ac5ea..268e054317da2f2066ef91ba21b2ce51072c4ee7 100644 GIT binary patch literal 8489 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 From 32016c87173f09c9e752afd46012910a99f163d0 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:29:13 -0500 Subject: [PATCH 127/224] Remove TODO --- .../core2/example/entities/marauder/MarauderRenderer.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java index 170a1ac07..df555215e 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java @@ -19,10 +19,6 @@ public class MarauderRenderer extends AzEntityRenderer { public MarauderRenderer(EntityRendererProvider.Context context) { super(context); addRenderLayer(new AzAutoGlowingLayer<>()); - /** - * TODO: Port this to new system, as it currently requries this be a GeoEntity and use the GeoLayers as well - */ - // addRenderLayer(new AutoGlowingGeoLayer<>(this)); } @Override From 9bbb1d2e51be3e54863552408a365947cc341e0d Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:29:24 -0500 Subject: [PATCH 128/224] Add Java docs to AzAutoGlowingLayer --- .../core2/render/layer/AzAutoGlowingLayer.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java index 75ceeb221..4985fe12a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java @@ -3,12 +3,28 @@ import mod.azure.azurelib.common.internal.common.cache.texture.AutoGlowingTexture; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import net.minecraft.client.renderer.RenderType; +/** + * A {@link AzRenderLayer} dedicated to rendering the auto-generated glow layer functionality provided by AzureLib. + * This utilizes texture files with the _glowing suffix to create glowing effects for models. + */ public class AzAutoGlowingLayer extends AzRenderLayer { @Override public void preRender(AzRendererPipelineContext context) {} + /** + * Handles the main rendering logic for the animatable object in the pipeline context. + * This includes switching to a custom {@link RenderType} for glowing textures and rendering + * the object using the pipeline's re-render mechanism. + *

      + * The rendering context's state is modified temporarily to apply a custom render type and packed light. + * After rendering, the context is restored to its original state for consistency. + *

      + * + * @param context the rendering pipeline context, containing the animatable object and rendering state + */ @Override public void render(AzRendererPipelineContext context) { var animatable = context.animatable(); From bac155380239b5298adeecd3abd2923f3f4b4d1f Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:29:38 -0500 Subject: [PATCH 129/224] Adds AzBlockAndItemLayer --- .../render/layer/AzBlockAndItemLayer.java | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java new file mode 100644 index 000000000..911ef8f12 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java @@ -0,0 +1,180 @@ +package mod.azure.azurelib.core2.render.layer; + +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.function.Function; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; + +/** + * A {@link AzRenderLayer} responsible for rendering {@link net.minecraft.world.level.block.state.BlockState BlockStates} + * or {@link net.minecraft.world.item.ItemStack ItemStacks} onto a specified {@link AzRendererPipeline}. + * This layer handles the rendering of physical elements, such as blocks and items, associated with animation bones. + */ +public class AzBlockAndItemLayer extends AzRenderLayer { + + protected final Function itemStackProvider; + + protected final Function blockStateProvider; + + public AzBlockAndItemLayer() { + this(bone -> null, bone -> null); + } + + public AzBlockAndItemLayer( + Function itemStackProvider, + Function blockStateProvider + ) { + super(); + + this.itemStackProvider = itemStackProvider; + this.blockStateProvider = blockStateProvider; + } + + @Override + public void preRender(AzRendererPipelineContext context) {} + + @Override + public void render(AzRendererPipelineContext context) {} + + /** + * Renders an {@link ItemStack} or {@link BlockState} associated with the specified bone in the rendering context. + * If both the {@link ItemStack} and {@link BlockState} are {@code null}, no rendering occurs. + *

      + * This method applies the bone's transformations to the current rendering matrix stack before rendering, + * ensuring the item or block appears correctly positioned and oriented relative to the bone. + *

      + * + * @param context the rendering pipeline context, containing rendering state and utilities + * @param bone the bone for which to render associated elements + */ + @Override + public void renderForBone(AzRendererPipelineContext context, AzBone bone) { + var stack = itemStackForBone(bone); + var blockState = blockStateForBone(bone); + + if (stack == null && blockState == null) + return; + + context.poseStack().pushPose(); + RenderUtils.translateAndRotateMatrixForBone(context.poseStack(), bone); + + if (stack != null) + renderItemForBone(context, bone, stack); + + if (blockState != null) + renderBlockForBone(context, bone, blockState); + + context.poseStack().popPose(); + } + + /** + * Retrieves the {@link ItemStack} associated with the given bone for rendering purposes. Returns {@code null} if + * there is no {@link ItemStack} to render for this bone. + * + * @param bone the bone for which to retrieve the {@link ItemStack} + * @return the {@link ItemStack} relevant to the specified bone, or {@code null} if none exists + */ + public ItemStack itemStackForBone(AzBone bone) { + return itemStackProvider.apply(bone); + } + + /** + * Retrieves the {@link BlockState} associated with the given bone for rendering purposes. Returns {@code null} if + * there is no {@link BlockState} to render for this bone. + * + * @param bone the bone for which to retrieve the {@link BlockState} + * @return the {@link BlockState} relevant to the specified bone, or {@code null} if none exists + */ + public BlockState blockStateForBone(AzBone bone) { + return blockStateProvider.apply(bone); + } + + /** + * Determines the specific {@link ItemDisplayContext} to use for rendering the given {@link ItemStack} on the + * specified bone. By default, this method returns {@link ItemDisplayContext#NONE}. + * + * @param bone the bone where the {@link ItemStack} will be rendered + * @param stack the {@link ItemStack} to render + * @return the {@link ItemDisplayContext} to use for rendering + */ + protected ItemDisplayContext getTransformTypeForStack(AzBone bone, ItemStack stack) { + return ItemDisplayContext.NONE; + } + + /** + * Renders the given {@link ItemStack} for the specified bone in the rendering context. + * The rendering adjusts based on whether the animatable object is a {@link LivingEntity}. + * + * @param context the rendering pipeline context + * @param bone the bone where the {@link ItemStack} will be rendered + * @param itemStack the {@link ItemStack} to render + */ + protected void renderItemForBone(AzRendererPipelineContext context, AzBone bone, ItemStack itemStack) { + if (context.animatable() instanceof LivingEntity livingEntity) { + Minecraft.getInstance() + .getItemRenderer() + .renderStatic( + livingEntity, + itemStack, + getTransformTypeForStack(bone, itemStack), + false, + context.poseStack(), + context.multiBufferSource(), + livingEntity.level(), + context.packedLight(), + context.packedOverlay(), + livingEntity.getId() + ); + } else { + Minecraft.getInstance() + .getItemRenderer() + .renderStatic( + itemStack, + getTransformTypeForStack(bone, itemStack), + context.packedLight(), + context.packedOverlay(), + context.poseStack(), + context.multiBufferSource(), + Minecraft.getInstance().level, + context.animatable().hashCode() + ); + } + } + + /** + * Renders the given {@link BlockState} for the specified bone in the rendering context. + * The block is rendered with adjusted position and scale to fit within the bone's space. + * + * @param context the rendering pipeline context + * @param bone the bone where the {@link BlockState} will be rendered + * @param blockState the {@link BlockState} to render + */ + protected void renderBlockForBone(AzRendererPipelineContext context, AzBone bone, BlockState blockState) { + context.poseStack().pushPose(); + + context.poseStack().translate(-0.25f, -0.25f, -0.25f); + context.poseStack().scale(0.5f, 0.5f, 0.5f); + + Minecraft.getInstance() + .getBlockRenderer() + .renderSingleBlock( + blockState, + context.poseStack(), + context.multiBufferSource(), + context.packedLight(), + OverlayTexture.NO_OVERLAY + ); + + context.poseStack().popPose(); + } + +} From 31294e4200c68f3d7cfc9a591415a68628d1a51f Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:53:12 -0500 Subject: [PATCH 130/224] Lint --- .../render/layer/AzAutoGlowingLayer.java | 16 ++-- .../render/layer/AzBlockAndItemLayer.java | 82 +++++++++---------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java index 4985fe12a..26bec5ef6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java @@ -1,13 +1,14 @@ package mod.azure.azurelib.core2.render.layer; +import net.minecraft.client.renderer.RenderType; + import mod.azure.azurelib.common.internal.common.cache.texture.AutoGlowingTexture; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; -import net.minecraft.client.renderer.RenderType; /** - * A {@link AzRenderLayer} dedicated to rendering the auto-generated glow layer functionality provided by AzureLib. - * This utilizes texture files with the _glowing suffix to create glowing effects for models. + * A {@link AzRenderLayer} dedicated to rendering the auto-generated glow layer functionality provided by AzureLib. This + * utilizes texture files with the _glowing suffix to create glowing effects for models. */ public class AzAutoGlowingLayer extends AzRenderLayer { @@ -15,12 +16,11 @@ public class AzAutoGlowingLayer extends AzRenderLayer { public void preRender(AzRendererPipelineContext context) {} /** - * Handles the main rendering logic for the animatable object in the pipeline context. - * This includes switching to a custom {@link RenderType} for glowing textures and rendering - * the object using the pipeline's re-render mechanism. + * Handles the main rendering logic for the animatable object in the pipeline context. This includes switching to a + * custom {@link RenderType} for glowing textures and rendering the object using the pipeline's re-render mechanism. *

      - * The rendering context's state is modified temporarily to apply a custom render type and packed light. - * After rendering, the context is restored to its original state for consistency. + * The rendering context's state is modified temporarily to apply a custom render type and packed light. After + * rendering, the context is restored to its original state for consistency. *

      * * @param context the rendering pipeline context, containing the animatable object and rendering state diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java index 911ef8f12..250da7eab 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java @@ -1,6 +1,5 @@ package mod.azure.azurelib.core2.render.layer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.world.entity.LivingEntity; @@ -12,11 +11,12 @@ import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; /** - * A {@link AzRenderLayer} responsible for rendering {@link net.minecraft.world.level.block.state.BlockState BlockStates} - * or {@link net.minecraft.world.item.ItemStack ItemStacks} onto a specified {@link AzRendererPipeline}. + * A {@link AzRenderLayer} responsible for rendering {@link net.minecraft.world.level.block.state.BlockState + * BlockStates} or {@link net.minecraft.world.item.ItemStack ItemStacks} onto a specified {@link AzRendererPipeline}. * This layer handles the rendering of physical elements, such as blocks and items, associated with animation bones. */ public class AzBlockAndItemLayer extends AzRenderLayer { @@ -49,8 +49,8 @@ public void render(AzRendererPipelineContext context) {} * Renders an {@link ItemStack} or {@link BlockState} associated with the specified bone in the rendering context. * If both the {@link ItemStack} and {@link BlockState} are {@code null}, no rendering occurs. *

      - * This method applies the bone's transformations to the current rendering matrix stack before rendering, - * ensuring the item or block appears correctly positioned and oriented relative to the bone. + * This method applies the bone's transformations to the current rendering matrix stack before rendering, ensuring + * the item or block appears correctly positioned and oriented relative to the bone. *

      * * @param context the rendering pipeline context, containing rendering state and utilities @@ -111,8 +111,8 @@ protected ItemDisplayContext getTransformTypeForStack(AzBone bone, ItemStack sta } /** - * Renders the given {@link ItemStack} for the specified bone in the rendering context. - * The rendering adjusts based on whether the animatable object is a {@link LivingEntity}. + * Renders the given {@link ItemStack} for the specified bone in the rendering context. The rendering adjusts based + * on whether the animatable object is a {@link LivingEntity}. * * @param context the rendering pipeline context * @param bone the bone where the {@link ItemStack} will be rendered @@ -121,38 +121,38 @@ protected ItemDisplayContext getTransformTypeForStack(AzBone bone, ItemStack sta protected void renderItemForBone(AzRendererPipelineContext context, AzBone bone, ItemStack itemStack) { if (context.animatable() instanceof LivingEntity livingEntity) { Minecraft.getInstance() - .getItemRenderer() - .renderStatic( - livingEntity, - itemStack, - getTransformTypeForStack(bone, itemStack), - false, - context.poseStack(), - context.multiBufferSource(), - livingEntity.level(), - context.packedLight(), - context.packedOverlay(), - livingEntity.getId() - ); + .getItemRenderer() + .renderStatic( + livingEntity, + itemStack, + getTransformTypeForStack(bone, itemStack), + false, + context.poseStack(), + context.multiBufferSource(), + livingEntity.level(), + context.packedLight(), + context.packedOverlay(), + livingEntity.getId() + ); } else { Minecraft.getInstance() - .getItemRenderer() - .renderStatic( - itemStack, - getTransformTypeForStack(bone, itemStack), - context.packedLight(), - context.packedOverlay(), - context.poseStack(), - context.multiBufferSource(), - Minecraft.getInstance().level, - context.animatable().hashCode() - ); + .getItemRenderer() + .renderStatic( + itemStack, + getTransformTypeForStack(bone, itemStack), + context.packedLight(), + context.packedOverlay(), + context.poseStack(), + context.multiBufferSource(), + Minecraft.getInstance().level, + context.animatable().hashCode() + ); } } /** - * Renders the given {@link BlockState} for the specified bone in the rendering context. - * The block is rendered with adjusted position and scale to fit within the bone's space. + * Renders the given {@link BlockState} for the specified bone in the rendering context. The block is rendered with + * adjusted position and scale to fit within the bone's space. * * @param context the rendering pipeline context * @param bone the bone where the {@link BlockState} will be rendered @@ -165,14 +165,14 @@ protected void renderBlockForBone(AzRendererPipelineContext context, AzBone bone context.poseStack().scale(0.5f, 0.5f, 0.5f); Minecraft.getInstance() - .getBlockRenderer() - .renderSingleBlock( - blockState, - context.poseStack(), - context.multiBufferSource(), - context.packedLight(), - OverlayTexture.NO_OVERLAY - ); + .getBlockRenderer() + .renderSingleBlock( + blockState, + context.poseStack(), + context.multiBufferSource(), + context.packedLight(), + OverlayTexture.NO_OVERLAY + ); context.poseStack().popPose(); } From 0c3ed7338e7c17d32b7224b954c9482991195ed4 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:53:17 -0500 Subject: [PATCH 131/224] Create AzArmorLayer.java --- .../core2/render/layer/AzArmorLayer.java | 324 ++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java new file mode 100644 index 000000000..07814da7e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java @@ -0,0 +1,324 @@ +package mod.azure.azurelib.core2.render.layer; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.geom.ModelLayers; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.blockentity.SkullBlockRenderer; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.component.DataComponents; +import net.minecraft.tags.ItemTags; +import net.minecraft.util.FastColor; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.*; +import net.minecraft.world.item.component.DyedItemColor; +import net.minecraft.world.level.block.AbstractSkullBlock; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; + +/** + * Builtin class for handling dynamic armor rendering on AzureLib entities.
      + * Supports both {@link GeoItem AzureLib} and {@link net.minecraft.world.item.ArmorItem Vanilla} armor models.
      + * Unlike a traditional armor renderer, this renderer renders per-bone, giving much more flexible armor rendering. + */ +public class AzArmorLayer extends AzRenderLayer { + + protected static final HumanoidModel INNER_ARMOR_MODEL = new HumanoidModel<>( + Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR) + ); + + protected static final HumanoidModel OUTER_ARMOR_MODEL = new HumanoidModel<>( + Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR) + ); + + @Nullable + protected ItemStack mainHandStack; + + @Nullable + protected ItemStack offhandStack; + + @Nullable + protected ItemStack helmetStack; + + @Nullable + protected ItemStack chestplateStack; + + @Nullable + protected ItemStack leggingsStack; + + @Nullable + protected ItemStack bootsStack; + + @Override + public void preRender(AzRendererPipelineContext context) { + if (!(context.animatable() instanceof LivingEntity livingEntity)) + return; + this.mainHandStack = livingEntity.getItemBySlot(EquipmentSlot.MAINHAND); + this.offhandStack = livingEntity.getItemBySlot(EquipmentSlot.OFFHAND); + this.helmetStack = livingEntity.getItemBySlot(EquipmentSlot.HEAD); + this.chestplateStack = livingEntity.getItemBySlot(EquipmentSlot.CHEST); + this.leggingsStack = livingEntity.getItemBySlot(EquipmentSlot.LEGS); + this.bootsStack = livingEntity.getItemBySlot(EquipmentSlot.FEET); + } + + @Override + public void render(AzRendererPipelineContext context) {} + + @Override + public void renderForBone(AzRendererPipelineContext context, AzBone bone) { + ItemStack armorStack = getArmorItemForBone(context, bone); + + if (armorStack == null) + return; + + if ( + armorStack.getItem() instanceof BlockItem blockItem && blockItem + .getBlock() instanceof AbstractSkullBlock skullBlock + ) { + renderSkullAsArmor(context, bone, armorStack, skullBlock); + } else { + EquipmentSlot slot = getEquipmentSlotForBone(context, bone, armorStack); + HumanoidModel model = getModelForItem(context, bone, slot, armorStack); + ModelPart modelPart = getModelPartForBone(context, model); + + if (!modelPart.cubes.isEmpty()) { + context.poseStack().pushPose(); + context.poseStack().scale(-1, -1, 1); + + if ( + model instanceof GeoArmorRenderer geoArmorRenderer && context + .animatable() instanceof Entity entity + ) { + prepModelPartForRender(context, bone, modelPart); + geoArmorRenderer.prepForRender(entity, armorStack, slot, model); + geoArmorRenderer.applyBoneVisibilityByPart(slot, modelPart, model); + geoArmorRenderer.renderToBuffer( + context.poseStack(), + null, + context.packedLight(), + context.packedOverlay(), + armorStack.is( + ItemTags.DYEABLE + ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(armorStack, -6265536)) : -1 + ); + } else if (armorStack.getItem() instanceof ArmorItem) { + prepModelPartForRender(context, bone, modelPart); + renderVanillaArmorPiece( + context, + bone, + slot, + armorStack, + modelPart + ); + } + + context.poseStack().popPose(); + } + } + } + + /** + * Return an EquipmentSlot for a given {@link ItemStack} and animatable instance.
      + * This is what determines the base model to use for rendering a particular stack + */ + @NotNull + protected EquipmentSlot getEquipmentSlotForBone(AzRendererPipelineContext context, AzBone bone, ItemStack stack) { + for (EquipmentSlot slot : EquipmentSlot.values()) { + if ( + slot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR && context + .animatable() instanceof LivingEntity livingEntity + ) { + if (stack == livingEntity.getItemBySlot(slot)) + return slot; + } + } + + return EquipmentSlot.CHEST; + } + + /** + * Return a ModelPart for a given {@link AzBone}.
      + * This is then transformed into position for the final render + */ + @NotNull + protected ModelPart getModelPartForBone(AzRendererPipelineContext context, HumanoidModel baseModel) { + return baseModel.body; + } + + /** + * Get the {@link ItemStack} relevant to the bone being rendered.
      + * Return null if this bone should be ignored + */ + @Nullable + protected ItemStack getArmorItemForBone(AzRendererPipelineContext context, AzBone bone) { + return null; + } + + /** + * Renders an individual armor piece base on the given {@link AzBone} and {@link ItemStack} + */ + protected void renderVanillaArmorPiece( + AzRendererPipelineContext context, + AzBone bone, + EquipmentSlot slot, + ItemStack armorStack, + ModelPart modelPart + ) { + var material = ((ArmorItem) armorStack.getItem()).getMaterial(); + + for (ArmorMaterial.Layer layer : material.value().layers()) { + var buffer = getVanillaArmorBuffer( + context, + armorStack, + slot, + bone, + layer, + false + ); + + modelPart.render(context.poseStack(), buffer, context.packedLight(), context.packedOverlay()); + } + + var trim = armorStack.get(DataComponents.TRIM); + + if (trim != null) { + TextureAtlasSprite sprite = Minecraft.getInstance() + .getModelManager() + .getAtlas( + Sheets.ARMOR_TRIMS_SHEET + ) + .getSprite( + slot == EquipmentSlot.LEGS ? trim.innerTexture(material) : trim.outerTexture(material) + ); + VertexConsumer buffer = sprite.wrap( + context.multiBufferSource().getBuffer(Sheets.armorTrimsSheet(trim.pattern().value().decal())) + ); + modelPart.render(context.poseStack(), buffer, context.packedLight(), context.packedOverlay()); + } + + if (armorStack.hasFoil()) + modelPart.render( + context.poseStack(), + getVanillaArmorBuffer( + context, + armorStack, + slot, + bone, + null, + true + ), + context.packedLight(), + context.packedOverlay(), + 1 + ); + } + + protected VertexConsumer getVanillaArmorBuffer( + AzRendererPipelineContext context, + ItemStack stack, + EquipmentSlot slot, + AzBone bone, + @Nullable ArmorMaterial.Layer layer, + boolean forGlint + ) { + if (forGlint) + return context.multiBufferSource().getBuffer(RenderType.armorEntityGlint()); + + return context.multiBufferSource() + .getBuffer(RenderType.armorCutoutNoCull(layer.texture(slot == EquipmentSlot.LEGS))); + } + + /** + * Returns a cached instance of a base HumanoidModel that is used for rendering/modelling the provided + * {@link ItemStack} + */ + @NotNull + protected HumanoidModel getModelForItem( + AzRendererPipelineContext context, + AzBone bone, + EquipmentSlot slot, + ItemStack stack + ) { + var defaultModel = slot == EquipmentSlot.LEGS ? INNER_ARMOR_MODEL : OUTER_ARMOR_MODEL; + var livingEntity = (LivingEntity) context.animatable(); + + return RenderProvider.of(stack).getHumanoidArmorModel(livingEntity, stack, slot, defaultModel); + } + + /** + * Render a given {@link AbstractSkullBlock} as a worn armor piece in relation to a given {@link AzBone} + */ + protected void renderSkullAsArmor( + AzRendererPipelineContext context, + AzBone bone, + ItemStack stack, + AbstractSkullBlock skullBlock + ) { + var type = skullBlock.getType(); + var model = SkullBlockRenderer.createSkullRenderers(Minecraft.getInstance().getEntityModels()) + .get(type); + var renderType = SkullBlockRenderer.getRenderType(type, stack.get(DataComponents.PROFILE)); + + context.poseStack().pushPose(); + RenderUtils.translateAndRotateMatrixForBone(context.poseStack(), bone); + context.poseStack().scale(1.1875f, 1.1875f, 1.1875f); + context.poseStack().translate(-0.5f, 0, -0.5f); + SkullBlockRenderer.renderSkull( + null, + 0, + 0, + context.poseStack(), + context.multiBufferSource(), + context.packedLight(), + model, + renderType + ); + context.poseStack().popPose(); + } + + /** + * Prepares the given {@link ModelPart} for render by setting its translation, position, and rotation values based + * on the provided {@link AzBone} + * + * @param context + * @param bone The AzBone to base the translations on + * @param sourcePart The ModelPart to translate + */ + protected void prepModelPartForRender(AzRendererPipelineContext context, AzBone bone, ModelPart sourcePart) { + final var firstCube = bone.getCubes().get(0); + final var armorCube = sourcePart.cubes.get(0); + final var armorBoneSizeX = firstCube.size().x(); + final var armorBoneSizeY = firstCube.size().y(); + final var armorBoneSizeZ = firstCube.size().z(); + final var actualArmorSizeX = Math.abs(armorCube.maxX - armorCube.minX); + final var actualArmorSizeY = Math.abs(armorCube.maxY - armorCube.minY); + final var actualArmorSizeZ = Math.abs(armorCube.maxZ - armorCube.minZ); + var scaleX = (float) (armorBoneSizeX / actualArmorSizeX); + var scaleY = (float) (armorBoneSizeY / actualArmorSizeY); + var scaleZ = (float) (armorBoneSizeZ / actualArmorSizeZ); + + sourcePart.setPos( + -(bone.getPivotX() - ((bone.getPivotX() * scaleX) - bone.getPivotX()) / scaleX), + -(bone.getPivotY() - ((bone.getPivotY() * scaleY) - bone.getPivotY()) / scaleY), + (bone.getPivotZ() - ((bone.getPivotZ() * scaleZ) - bone.getPivotZ()) / scaleZ) + ); + + sourcePart.xRot = -bone.getRotX(); + sourcePart.yRot = -bone.getRotY(); + sourcePart.zRot = bone.getRotZ(); + + context.poseStack().scale(scaleX, scaleY, scaleZ); + } +} From 1b1bbcd86c54e7bc176c8c59028c2e9d22cce63e Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:05:37 -0500 Subject: [PATCH 132/224] Clean up --- .../CommonArmorMaterialRegistryInterface.java | 66 ----------------- .../CommonCreativeTabRegistryInterface.java | 35 ---------- .../CommonEntityRegistryInterface.java | 70 ------------------- .../CommonFluidRegistryInterface.java | 49 ------------- .../registry/CommonItemRegistryInterface.java | 59 ---------------- .../CommonMenuTypesRegistryInterface.java | 49 ------------- .../CommonParticleRegistryInterface.java | 54 -------------- .../CommonSoundRegistryInterface.java | 51 -------------- .../CommonStatusEffectRegistryInterface.java | 64 ----------------- .../CommonStructureRegistryInterface.java | 51 -------------- 10 files changed, 548 deletions(-) delete mode 100644 common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonArmorMaterialRegistryInterface.java delete mode 100644 common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonCreativeTabRegistryInterface.java delete mode 100644 common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonEntityRegistryInterface.java delete mode 100644 common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonFluidRegistryInterface.java delete mode 100644 common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonItemRegistryInterface.java delete mode 100644 common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonMenuTypesRegistryInterface.java delete mode 100644 common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonParticleRegistryInterface.java delete mode 100644 common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonSoundRegistryInterface.java delete mode 100644 common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStatusEffectRegistryInterface.java delete mode 100644 common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStructureRegistryInterface.java diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonArmorMaterialRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonArmorMaterialRegistryInterface.java deleted file mode 100644 index 5814b8728..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonArmorMaterialRegistryInterface.java +++ /dev/null @@ -1,66 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import net.minecraft.core.Holder; -import net.minecraft.world.item.ArmorMaterial; - -import java.util.function.Supplier; - -import mod.azure.azurelib.common.platform.Services; - -/** - * Example of using this Interface to create a new Item: - *

      - * The following code demonstrates how to register a new armor material in the game: - *

      - * - *
      {@code
      - *
      - * public static final Holder TEST_ARMOR_MATERIAL = CommonArmorMaterialRegistryInterface
      - *     .registerArmorMaterial("modid", "materialname", YOURCLASS::dummyArmorMaterial);
      - *
      - * private static ArmorMaterial dummyArmorMaterial() {
      - *     ArmorMaterial diamond = ArmorMaterials.DIAMOND.value();
      - *     return new ArmorMaterial(
      - *         diamond.defense(),
      - *         diamond.enchantmentValue(),
      - *         diamond.equipSound(),
      - *         diamond.repairIngredient(),
      - *         List.of(), // If your Material has other layers like Player Armors inner/outer
      - *         diamond.toughness(),
      - *         diamond.knockbackResistance()
      - *     );
      - * }
      - * }
      - *

      - * In this example: - *

      - *
        - *
      • registerArmorMaterial is a method to register a new armor material with the specified mod ID and - * material name.
      • - *
      • dummyArmorMaterial creates a new instance of ArmorMaterial using the properties of the - * existing ArmorMaterials.DIAMOND.
      • - *
      - *

      - * The {@link net.minecraft.world.item.ArmorMaterial ArmorMaterial} class represents the material properties for an - * armor item. - *

      - */ -public interface CommonArmorMaterialRegistryInterface { - - /** - * Registers a new Armor Material. - * - * @param modID The mod ID. - * @param matName The name of the material. - * @param armorMaterial A supplier for the armor material. - * @param The type of the armor material. - * @return A holder for the registered armor material. - */ - static Holder registerArmorMaterial( - String modID, - String matName, - Supplier armorMaterial - ) { - return Services.COMMON_REGISTRY.registerArmorMaterial(modID, matName, armorMaterial); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonCreativeTabRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonCreativeTabRegistryInterface.java deleted file mode 100644 index 3bf0044be..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonCreativeTabRegistryInterface.java +++ /dev/null @@ -1,35 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -/** - * Example of using this Interface to create a new Creative Tab: - *

      - * The following code demonstrates how to register a new creative mode tab in the game: - *

      - * - *
      {@code
      - *
      - * public static final Supplier EXAMPLEMOD_TAB = Services.COMMON_REGISTRY.registerCreativeModeTab(
      - *     AzureLib.MOD_ID,
      - *     "examplemod_items",
      - *     () -> Services.COMMON_REGISTRY.newCreativeTabBuilder()
      - *         .title(Component.translatable("itemGroup." + AzureLib.MOD_ID + ".examplemod_items"))
      - *         .icon(() -> new ItemStack(Items.ITEM_FRAME))
      - *         .displayItems((enabledFeatures, entries) -> entries.accept(Items.ITEM_FRAME))
      - *         .build()
      - * );
      - * }
      - *

      - * In this example: - *

      - *
        - *
      • registerCreativeModeTab is a method to register a new creative mode tab with the specified mod ID - * and tab name.
      • - *
      • The newCreativeTabBuilder method is used to build the creative tab with a title, icon, and displayed - * items.
      • - *
      - *

      - * The {@link net.minecraft.world.item.CreativeModeTab CreativeModeTab} class represents a tab in the creative inventory - * menu. - *

      - */ -public interface CommonCreativeTabRegistryInterface {} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonEntityRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonEntityRegistryInterface.java deleted file mode 100644 index 6a4469773..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonEntityRegistryInterface.java +++ /dev/null @@ -1,70 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.MobCategory; - -import java.util.function.Supplier; - -import mod.azure.azurelib.common.platform.Services; - -/** - * Example of using this Interface to create a new Entity: - *

      - * The following code demonstrates how to register a new entity type in the game: - *

      - * - *
      {@code
      - *
      - * public static final Supplier> TEST = CommonEntityRegistryInterface.registerEntity(
      - *     "modid",
      - *     "entityname",
      - *     TestEntity::new,
      - *     MobCategory.CREATURE,
      - *     0.7f,
      - *     1.3f
      - * );
      - * }
      - *

      - * In this example: - *

      - *
        - *
      • registerEntity is a method to register a new entity with the specified mod ID, entity name, factory - * method, dimensions, and spawn egg colors.
      • - *
      • TestEntity::new is a reference to the constructor of the TestEntity class.
      • - *
      • 0.7f and 1.3f represent the width and height of the entity, respectively.
      • - *
      • 0x1F1F1F and 0x0D0D0D represent the primary and secondary colors of the entity's spawn - * egg.
      • - *
      - *

      - * The {@link net.minecraft.world.entity.EntityType EntityType} class represents an entity type in the game. - *

      - */ -public interface CommonEntityRegistryInterface { - - /** - * Registers a new entity type. - * - * @param modID The mod ID. - * @param entityName The name of the entity. - * @param entity The factory method for creating instances of the entity. - * @param width The width of the entity. - * @param height The height of the entity. - * @param The type of the entity. - * @return A supplier for the registered entity type. - */ - static Supplier> registerEntity( - String modID, - String entityName, - EntityType.EntityFactory entity, - MobCategory mobCategory, - float width, - float height - ) { - return Services.COMMON_REGISTRY.registerEntity( - modID, - entityName, - () -> EntityType.Builder.of(entity, mobCategory).sized(width, height).build(entityName) - ); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonFluidRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonFluidRegistryInterface.java deleted file mode 100644 index 1f8bd8704..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonFluidRegistryInterface.java +++ /dev/null @@ -1,49 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import net.minecraft.world.level.material.Fluid; - -import java.util.function.Supplier; - -import mod.azure.azurelib.common.platform.Services; - -/** - * Example of using this Interface to create a new Fluid: - *

      - * The following code demonstrates how to register a new Fluid in the game: - *

      - * - *
      {@code
      - *
      - * public static final Supplier TEST_FLUID = CommonFluidRegistryInterface.registerFluid(
      - *     "modid",
      - *     "fluidName",
      - *     () -> new CustomFluid()
      - * );
      - * }
      - *

      - * In this example: - *

      - *
        - *
      • registerFluid is a method to register a new fluid with the specified mod ID and fluid name.
      • - *
      • Fluid is the base class for all fluids in the game.
      • - *
      • CustomFluid is a user-defined class extending Fluid.
      • - *
      - *

      - * The {@link net.minecraft.world.level.material.Fluid Fluid} class represents a fluid in the game. - *

      - */ -public interface CommonFluidRegistryInterface { - - /** - * Registers a new fluid. - * - * @param modID The mod ID. - * @param itemName The name of the fluid. - * @param fluid A supplier that provides an instance of the fluid. - * @param The type of the fluid extending from {@link Fluid}. - * @return A supplier that provides the registered fluid. - */ - static Supplier registerFluid(String modID, String itemName, Supplier fluid) { - return Services.COMMON_REGISTRY.registerFluid(modID, itemName, fluid); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonItemRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonItemRegistryInterface.java deleted file mode 100644 index 29f08710f..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonItemRegistryInterface.java +++ /dev/null @@ -1,59 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import net.minecraft.world.item.Item; - -import java.util.function.Supplier; - -import mod.azure.azurelib.common.platform.Services; - -/** - * Example of using this Interface to create a new Item: - *

      - * The following code demonstrates how to register a new item and a spawn egg in the game: - *

      - * - *
      {@code
      - *
      - * public static final Supplier TEST_ITEM = CommonItemRegistryInterface.registerItem(
      - *     "modid",
      - *     "itemname",
      - *     () -> new Item(new Item.Properties())
      - * );
      - *
      - * public static final Supplier TEST_SPAWN_EGG = CommonItemRegistryInterface.registerItem(
      - *     "modid",
      - *     "entityname_spawn_egg",
      - *     Services.COMMON_REGISTRY.makeSpawnEggFor(TESTENTITY, 0x1F1F1F, 0x0D0D0D, new Item.Properties())
      - * );
      - * }
      - *

      - * In this example: - *

      - *
        - *
      • registerItem is a method to register a new item with the specified mod ID and item name.
      • - *
      • Item is used to create a new item instance with default properties.
      • - *
      • makeSpawnEggFor is a method to create a spawn egg for the specified entity with primary and - * secondary colors.
      • - *
      - *

      - * The {@link net.minecraft.world.item.Item Item} class represents an item in the game. - *

      - *

      - * The {@link net.minecraft.world.item.SpawnEggItem SpawnEggItem} class represents a spawn egg in the game. - *

      - */ -public interface CommonItemRegistryInterface { - - /** - * Registers a new Item. - * - * @param modID The mod ID. - * @param itemName The name of the item. - * @param item A supplier for the item. - * @param The type of the item. - * @return A supplier for the registered item. - */ - static Supplier registerItem(String modID, String itemName, Supplier item) { - return Services.COMMON_REGISTRY.registerItem(modID, itemName, item); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonMenuTypesRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonMenuTypesRegistryInterface.java deleted file mode 100644 index a70980b49..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonMenuTypesRegistryInterface.java +++ /dev/null @@ -1,49 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import net.minecraft.world.inventory.MenuType; - -import java.util.function.Supplier; - -import mod.azure.azurelib.common.platform.Services; - -/** - * Example of using this Interface to create a new MenuType: - *

      - * The following code demonstrates how to register a new screen type in the game: - *

      - * - *
      {@code
      - *
      - * public static final Supplier> TEST = CommonMenuTypesRegistryInterface.registerScreen(
      - *     "modid",
      - *     "screenname",
      - *     () -> new MenuType<>(CustomScreenHandler::new, FeatureFlags.VANILLA_SET)
      - * );
      - * }
      - *

      - * In this example: - *

      - *
        - *
      • registerScreen is a method to register a new screen type with the specified mod ID and screen - * name.
      • - *
      • MenuType is used to create a new screen type instance.
      • - *
      - *

      - * The {@link net.minecraft.world.inventory.MenuType MenuType} class represents a type of screen in the game. - *

      - */ -public interface CommonMenuTypesRegistryInterface { - - /** - * Registers a new screen type. - * - * @param modID The mod ID. - * @param screenName The name of the screen. - * @param item A supplier for the screen type. - * @param The type of the screen type. - * @return A supplier for the registered screen type. - */ - static > Supplier registerScreen(String modID, String screenName, Supplier item) { - return Services.COMMON_REGISTRY.registerScreen(modID, screenName, item); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonParticleRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonParticleRegistryInterface.java deleted file mode 100644 index 92e5b0b8d..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonParticleRegistryInterface.java +++ /dev/null @@ -1,54 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import net.minecraft.core.particles.ParticleType; - -import java.util.function.Supplier; - -import mod.azure.azurelib.common.platform.Services; - -/** - * Example of using this Interface to create a new Particle: - *

      - * The following code demonstrates how to register a new particle type in the game: - *

      - * - *
      {@code
      - *
      - * public static final Supplier TEST = CommonParticleRegistryInterface.registerParticle(
      - *     "modid",
      - *     "particlename",
      - *     () -> new SimpleParticleType(true)
      - * );
      - * }
      - *

      - * In this example: - *

      - *
        - *
      • registerParticle is a method to register a new particle with the specified mod ID and particle - * name.
      • - *
      • SimpleParticleType is used to create a new particle type instance.
      • - *
      - *

      - * The {@link net.minecraft.core.particles.SimpleParticleType SimpleParticleType} class represents a basic particle type - * in the game. - *

      - */ -public interface CommonParticleRegistryInterface { - - /** - * Registers a new Particle. - * - * @param modID The mod ID. - * @param particleName The ID of the particle. - * @param particle A supplier for the particle type. - * @param The type of the particle type. - * @return A supplier for the registered particle type. - */ - static > Supplier registerParticle( - String modID, - String particleName, - Supplier particle - ) { - return Services.COMMON_REGISTRY.registerParticle(modID, particleName, particle); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonSoundRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonSoundRegistryInterface.java deleted file mode 100644 index 28121fa6e..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonSoundRegistryInterface.java +++ /dev/null @@ -1,51 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import net.minecraft.sounds.SoundEvent; - -import java.util.function.Supplier; - -import mod.azure.azurelib.common.platform.Services; - -/** - * Example of using this Interface to create a new SoundEvent: - *

      - * The following code demonstrates how to register a new sound event in the game: - *

      - * - *
      {@code
      - *
      - * public static Supplier TEST_SOUND = CommonSoundRegistryInterface.registerSound(
      - *     "modid",
      - *     "test_sound",
      - *     () -> SoundEvent.createVariableRangeEvent(
      - *         ResourceLocation.fromNamespaceAndPath("modid", "test_sound")
      - *     )
      - * );
      - * }
      - *

      - * In this example: - *

      - *
        - *
      • registerSound is a method to register a new sound event with the specified mod ID and sound - * name.
      • - *
      • SoundEvent is used to create a new sound event instance.
      • - *
      - *

      - * The {@link net.minecraft.sounds.SoundEvent SoundEvent} class represents a sound event in the game. - *

      - */ -public interface CommonSoundRegistryInterface { - - /** - * Registers a new sound event. - * - * @param modID The mod ID. - * @param soundName The name of the sound event. - * @param sound A supplier for the sound event. - * @param The type of the sound event. - * @return A supplier for the registered sound event. - */ - static Supplier registerSound(String modID, String soundName, Supplier sound) { - return Services.COMMON_REGISTRY.registerSound(modID, soundName, sound); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStatusEffectRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStatusEffectRegistryInterface.java deleted file mode 100644 index b2b77eb74..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStatusEffectRegistryInterface.java +++ /dev/null @@ -1,64 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import net.minecraft.core.Holder; -import net.minecraft.world.effect.MobEffect; - -import java.util.function.Supplier; - -import mod.azure.azurelib.common.platform.Services; - -/** - * Example of using this Interface to create a new Status Effect: - *

      - * The following code demonstrates how to register a new Status Effect in the game: - *

      - * - *
      {@code
      - *
      - * public static final Holder TEST_EFFECT = CommonStatusEffectRegistryInterface.registerStatusEffect(
      - *     "modid",
      - *     "effectName",
      - *     () -> new CustomMobEffect(
      - *         MobEffectCategory.HARMFUL,
      - *         Color.BLACK.getColor()
      - *     )
      - * );
      - * }
      - *

      - * In this example: - *

      - *
        - *
      • registerStatusEffect is a method to register a new status effect with the specified mod ID and - * effect name.
      • - *
      • MobEffect is the base class for all status effects in the game.
      • - *
      • CustomMobEffect is a user-defined class extending MobEffect.
      • - *
      • MobEffectCategory.HARMFUL specifies the category of the status effect.
      • - *
      • Color.BLACK.getColor() specifies the color of the status effect.
      • - *
      - *

      - * The {@link net.minecraft.world.effect.MobEffect MobEffect} class represents a status effect in the game. - *

      - *

      - * The {@link net.minecraft.world.effect.MobEffectCategory MobEffectCategory} class represents the category of a status - * effect in the game. - *

      - */ -public interface CommonStatusEffectRegistryInterface { - - /** - * Registers a new Status Effect. - * - * @param modID The mod ID. - * @param effectName The name of the Status Effect. - * @param statusEffect A supplier that provides an instance of the Status Effect. - * @param The type of the status effect extending from {@link net.minecraft.world.effect.MobEffect}. - * @return A holder that provides the registered status effect. - */ - static Holder registerStatusEffect( - String modID, - String effectName, - Supplier statusEffect - ) { - return Services.COMMON_REGISTRY.registerStatusEffect(modID, effectName, statusEffect); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStructureRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStructureRegistryInterface.java deleted file mode 100644 index fedfa4b57..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStructureRegistryInterface.java +++ /dev/null @@ -1,51 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import com.mojang.serialization.MapCodec; -import net.minecraft.world.level.levelgen.structure.Structure; -import net.minecraft.world.level.levelgen.structure.StructureType; - -import java.util.function.Supplier; - -import mod.azure.azurelib.common.platform.Services; - -/** - * Example of using this Interface to create a new Structure: - *

      - * The following code demonstrates how to register a new structure in the game: - *

      - * - *
      {@code
      - *
      - * public static final Supplier> TEST = CommonStructureRegistryInterface
      - *     .registerStructure("modid", "structurename", CustomStructure.CODEC);
      - * }
      - *

      - * In this example: - *

      - *
        - *
      • registerStructure is a method to register a new structure type with the specified mod ID and - * structure name.
      • - *
      • "modid" is the identifier for your mod.
      • - *
      • "structurename" is the name you want to give to your new structure.
      • - *
      • CustomStructure.CODEC is the codec for your custom structure type.
      • - *
      - */ -public interface CommonStructureRegistryInterface { - - /** - * Registers a new structure. - * - * @param modID The mod ID. - * @param structureName The name of the structure. - * @param structure A codec for the structure type. - * @param The type of the structure. - * @return A supplier for the registered structure type. - */ - static Supplier> registerStructure( - String modID, - String structureName, - MapCodec structure - ) { - return Services.COMMON_REGISTRY.registerStructure(modID, structureName, structure); - } -} From c8abb2546c0d9a4ab2e82a5349f4be3dde32b6fd Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:09:53 -0500 Subject: [PATCH 133/224] Mark as deprecated --- .../common/api/client/model/DefaultedBlockGeoModel.java | 1 + .../common/api/client/model/DefaultedEntityGeoModel.java | 1 + .../azurelib/common/api/client/model/DefaultedGeoModel.java | 1 + .../azurelib/common/api/client/model/DefaultedItemGeoModel.java | 1 + .../mod/azure/azurelib/common/api/client/model/GeoModel.java | 1 + .../azurelib/common/api/client/renderer/GeoArmorRenderer.java | 1 + .../common/api/client/renderer/GeoArmorRendererConstants.java | 1 + .../azurelib/common/api/client/renderer/GeoBlockRenderer.java | 1 + .../azurelib/common/api/client/renderer/GeoEntityRenderer.java | 1 + .../azurelib/common/api/client/renderer/GeoItemRenderer.java | 1 + .../azurelib/common/api/client/renderer/GeoObjectRenderer.java | 1 + .../common/api/client/renderer/layer/AutoGlowingGeoLayer.java | 1 + .../common/api/client/renderer/layer/BlockAndItemGeoLayer.java | 1 + .../common/api/client/renderer/layer/BoneFilterGeoLayer.java | 1 + .../api/client/renderer/layer/FastBoneFilterGeoLayer.java | 1 + .../common/api/client/renderer/layer/GeoRenderLayer.java | 1 + .../api/client/renderer/layer/GeoRenderLayersContainer.java | 1 + .../common/api/client/renderer/layer/ItemArmorGeoLayer.java | 1 + .../internal/common/animatable/SingletonGeoAnimatable.java | 2 ++ 19 files changed, 20 insertions(+) diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java index 6b1270d29..52cc7b8a5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java @@ -13,6 +13,7 @@ * {@link DefaultedGeoModel} specific to {@link net.minecraft.world.level.block.Block Blocks}. Using this class * pre-sorts provided asset paths into the "block" subdirectory */ +@Deprecated(forRemoval = true) public class DefaultedBlockGeoModel extends DefaultedGeoModel { /** diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java index 0f22e6506..b34ec1424 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java @@ -19,6 +19,7 @@ * provided asset paths into the "entity" subdirectory Additionally it can automatically handle head-turning if the * entity has a "head" bone */ +@Deprecated(forRemoval = true) public class DefaultedEntityGeoModel extends DefaultedGeoModel { private final boolean turnsHead; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java index b8acf56c4..14891b926 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java @@ -14,6 +14,7 @@ * This class allows for minimal boilerplate when implementing basic models, and saves on new classes.
      * Additionally, it encourages consistency and sorting of asset paths. */ +@Deprecated(forRemoval = true) public abstract class DefaultedGeoModel extends GeoModel { private ResourceLocation modelPath; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java index c7993b5a6..c85f75de1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java @@ -13,6 +13,7 @@ * {@link DefaultedGeoModel} specific to {@link net.minecraft.world.item.Item Items}. Using this class pre-sorts * provided asset paths into the "item" subdirectory */ +@Deprecated(forRemoval = true) public class DefaultedItemGeoModel extends DefaultedGeoModel { /** diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java index e4b060b55..67d13afe4 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java @@ -38,6 +38,7 @@ * Base class for all code-based model objects.
      * All models to registered to a {@link GeoRenderer} should be an instance of this or one of its subclasses. */ +@Deprecated(forRemoval = true) public abstract class GeoModel implements CoreGeoModel { private final AnimationProcessor processor = new AnimationProcessor<>(this); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java index 42fd8e223..d72974d89 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java @@ -49,6 +49,7 @@ * @param * @see GeoItem */ +@Deprecated(forRemoval = true) public class GeoArmorRenderer extends HumanoidModel implements GeoRenderer { protected final GeoRenderLayersContainer renderLayers = new GeoRenderLayersContainer<>(this); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRendererConstants.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRendererConstants.java index e5c912312..6907787ed 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRendererConstants.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRendererConstants.java @@ -6,6 +6,7 @@ /** * @author Boston Vanseghi */ +@Deprecated(forRemoval = true) public class GeoArmorRendererConstants { public static final String BONE_ARMOR_BODY_NAME = "armorBody"; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java index a3381503a..7ff2435e0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java @@ -41,6 +41,7 @@ * Base {@link GeoRenderer} class for rendering {@link BlockEntity Blocks} specifically.
      * All blocks added to be rendered by AzureLib should use an instance of this class. */ +@Deprecated(forRemoval = true) public class GeoBlockRenderer implements GeoRenderer, BlockEntityRenderer { protected final GeoModel model; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java index 37af7a506..9558e5ef3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java @@ -51,6 +51,7 @@ * All entities added to be rendered by AzureLib should use an instance of this class.
      * This also includes {@link net.minecraft.world.entity.projectile.Projectile Projectiles} */ +@Deprecated(forRemoval = true) public class GeoEntityRenderer extends EntityRenderer implements GeoRenderer { protected final List> renderLayers = new ObjectArrayList<>(); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java index c12a23051..e8c47d0b8 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java @@ -44,6 +44,7 @@ * Base {@link GeoRenderer} class for rendering {@link Item Items} specifically.
      * All items added to be rendered by AzureLib should use an instance of this class. */ +@Deprecated(forRemoval = true) public class GeoItemRenderer extends BlockEntityWithoutLevelRenderer implements GeoRenderer { protected final GeoRenderLayersContainer renderLayers = new GeoRenderLayersContainer<>(this); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java index f380d52df..d0934ad7b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java @@ -38,6 +38,7 @@ *
      * It is strongly recommended you override {@link GeoRenderer#getInstanceId} if using this renderer */ +@Deprecated(forRemoval = true) public class GeoObjectRenderer implements GeoRenderer { protected final GeoRenderLayersContainer renderLayers = new GeoRenderLayersContainer<>(this); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java index 8442a81f3..aeab5141b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java @@ -20,6 +20,7 @@ * {@link GeoRenderLayer} for rendering the auto-generated glowlayer functionality implemented by AzureLib using the * _glowing appendixed texture files. */ +@Deprecated(forRemoval = true) public class AutoGlowingGeoLayer extends GeoRenderLayer { public AutoGlowingGeoLayer(GeoRenderer renderer) { diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java index 6fcbe29c9..21340862c 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java @@ -28,6 +28,7 @@ * {@link GeoRenderLayer} for rendering {@link net.minecraft.world.level.block.state.BlockState BlockStates} or * {@link net.minecraft.world.item.ItemStack ItemStacks} on a given {@link GeoAnimatable} */ +@Deprecated(forRemoval = true) public class BlockAndItemGeoLayer extends GeoRenderLayer { protected final BiFunction stackForBone; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java index 0edebc056..957c9a74c 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java @@ -22,6 +22,7 @@ *
      * NOTE: Despite this layer existing, it is much more efficient to use {@link FastBoneFilterGeoLayer} instead */ +@Deprecated(forRemoval = true) public class BoneFilterGeoLayer extends GeoRenderLayer { protected final TriConsumer checkAndApply; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java index 630844623..e126cab01 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java @@ -24,6 +24,7 @@ * This version requires you provide the list of bones to filter up-front, so that the bone hierarchy doesn't need to be * traversed. */ +@Deprecated(forRemoval = true) public class FastBoneFilterGeoLayer extends BoneFilterGeoLayer { protected final Supplier> boneSupplier; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java index 91ebda9bb..b0b496b60 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java @@ -21,6 +21,7 @@ * Render layer base class for rendering additional layers of effects or textures over an existing model at runtime.
      * Contains the base boilerplate and helper code for various render layer features */ +@Deprecated(forRemoval = true) public abstract class GeoRenderLayer { protected final GeoRenderer renderer; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java index a456596ff..0f0902f0b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java @@ -16,6 +16,7 @@ * Base interface for a container for {@link GeoRenderLayer GeoRenderLayers}
      * Each renderer should contain an instance of this, for holding its layers and handling events. */ +@Deprecated(forRemoval = true) public class GeoRenderLayersContainer { private final GeoRenderer renderer; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java index e5992f53a..6089eebef 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java @@ -47,6 +47,7 @@ * Supports both {@link GeoItem AzureLib} and {@link net.minecraft.world.item.ArmorItem Vanilla} armor models.
      * Unlike a traditional armor renderer, this renderer renders per-bone, giving much more flexible armor rendering. */ +@Deprecated(forRemoval = true) public class ItemArmorGeoLayer extends GeoRenderLayer { protected static final HumanoidModel INNER_ARMOR_MODEL = new HumanoidModel<>( diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java index 4a57252b1..24596d53e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java @@ -25,6 +25,8 @@ /** * The {@link GeoAnimatable} interface specific to singleton objects. This primarily applies to armor and items + * + * @deprecated */ public interface SingletonGeoAnimatable extends GeoAnimatable { From 6e931df4e35ab6ff3cdd2ac2d83b717e8533c88d Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:10:14 -0500 Subject: [PATCH 134/224] Undeprecated --- .../common/internal/common/cache/texture/AnimatableTexture.java | 1 - .../common/internal/common/cache/texture/AutoGlowingTexture.java | 1 - .../internal/common/cache/texture/GeoGlowingTextureMeta.java | 1 - 3 files changed, 3 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java index cac61bd80..03185d603 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java @@ -32,7 +32,6 @@ /** * Wrapper for {@link SimpleTexture SimpleTexture} implementation allowing for casual use of animated non-atlas textures * - * @deprecated */ public class AnimatableTexture extends SimpleTexture { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java index 2ce2b551d..46fd9ea8a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java @@ -35,7 +35,6 @@ /** * Texture object type responsible for AzureLib's emissive render textures * - * @deprecated */ public class AutoGlowingTexture extends GeoAbstractTexture { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java index 99c633be9..608dbded1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java @@ -24,7 +24,6 @@ * Metadata class that stores the data for AzureLib's {@link AutoGlowingGeoLayer emissive texture feature} for a given * texture * - * @deprecated */ public class GeoGlowingTextureMeta { From 04dbb245502e26ecec5d358157285a68bcdd8cea Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:11:13 -0500 Subject: [PATCH 135/224] bump as i built a version to maven for testing locally in another source --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 653466653..76e8bf56e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -51,5 +51,5 @@ mod_logo = azurelib.png mod_name = AzureLib mod_sources = https://github.com/AzureDoom/AzureLib mod_url = https://modrinth.com/mod/azurelib -version = 3.0.0-alpha13 +version = 3.0.0-alpha14 modrinth_id = 7zlUOZvb From ba9a2a576c47bbe4d011d9cc72628951da1f0d62 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 19 Dec 2024 22:39:03 -0500 Subject: [PATCH 136/224] Try and optimize memory efficiency of base renderer pipeline. Signed-off-by: = --- .../render/pipeline/AzRendererPipeline.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index 2dcf7a8b2..4b079febf 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -7,7 +7,6 @@ import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.joml.Matrix3f; import org.joml.Matrix4f; import org.joml.Vector3f; import org.joml.Vector4f; @@ -169,6 +168,9 @@ protected void renderChildBones(AzRendererPipelineContext context, AzBone bon } } + private final Matrix4f poseStateCache = new Matrix4f(); + private final Vector3f normalCache = new Vector3f(); + /** * Renders an individual {@link GeoCube}.
      * This tends to be called recursively from something like {@link AzRendererPipeline#renderCubesOfBone} @@ -180,22 +182,24 @@ protected void renderCube(AzRendererPipelineContext context, GeoCube cube) { RenderUtils.rotateMatrixAroundCube(poseStack, cube); RenderUtils.translateAwayFromPivotPoint(poseStack, cube); - Matrix3f normalisedPoseState = poseStack.last().normal(); - Matrix4f poseState = new Matrix4f(poseStack.last().pose()); + var normalisedPoseState = poseStack.last().normal(); + var poseState = poseStateCache.set(poseStack.last().pose()); for (var quad : cube.quads()) { if (quad == null) { continue; } - // TODO: Optimize - var normal = normalisedPoseState.transform(new Vector3f(quad.normal())); + normalCache.set(quad.normal()); + var normal = normalisedPoseState.transform(normalCache); RenderUtils.fixInvertedFlatCube(cube, normal); createVerticesOfQuad(context, quad, poseState, normal); } } + private final Vector4f poseStateTransformCache = new Vector4f(); + /** * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for * rendering @@ -213,8 +217,8 @@ protected void createVerticesOfQuad( for (var vertex : quad.vertices()) { var position = vertex.position(); - // TODO: Optimize - var vector4f = poseState.transform(new Vector4f(position.x(), position.y(), position.z(), 1.0f)); + poseStateTransformCache.set(position.x(), position.y(), position.z(), 1.0f); + var vector4f = poseState.transform(poseStateTransformCache); buffer.addVertex( vector4f.x(), From 2139c659ede1bd27b4b804a0cae435159811c958 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Thu, 19 Dec 2024 23:12:46 -0500 Subject: [PATCH 137/224] More optimizations. Signed-off-by: = --- .../internal/client/util/RenderUtils.java | 19 ++++++++++++++----- .../cache/texture/AnimatableTexture.java | 1 - .../cache/texture/AutoGlowingTexture.java | 1 - .../cache/texture/GeoGlowingTextureMeta.java | 1 - .../render/pipeline/AzRendererPipeline.java | 7 ++++--- .../impl/AzEntityRendererPipeline.java | 4 ++-- 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java index d9b24ffba..078ddea4e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java @@ -44,7 +44,15 @@ /** * Helper class for various methods and functions useful while rendering */ -public record RenderUtils() { +public class RenderUtils { + + private static final Matrix4f TRANSLATE_MATRIX_CACHE = new Matrix4f(); + + private static final Quaternionf X_QUATERNION_CACHE = new Quaternionf(); + + private static final Quaternionf Y_QUATERNION_CACHE = new Quaternionf(); + + private static final Quaternionf Z_QUATERNION_CACHE = new Quaternionf(); public static void translateMatrixToBone(PoseStack poseStack, CoreGeoBone bone) { poseStack.translate(-bone.getPosX() / 16f, bone.getPosY() / 16f, bone.getPosZ() / 16f); @@ -64,9 +72,9 @@ public static void rotateMatrixAroundBone(PoseStack poseStack, CoreGeoBone bone) public static void rotateMatrixAroundCube(PoseStack poseStack, GeoCube cube) { Vec3 rotation = cube.rotation(); - poseStack.mulPose(new Quaternionf().rotationXYZ(0, 0, (float) rotation.z())); - poseStack.mulPose(new Quaternionf().rotationXYZ(0, (float) rotation.y(), 0)); - poseStack.mulPose(new Quaternionf().rotationXYZ((float) rotation.x(), 0, 0)); + poseStack.mulPose(Z_QUATERNION_CACHE.rotationXYZ(0, 0, (float) rotation.z())); + poseStack.mulPose(Y_QUATERNION_CACHE.rotationXYZ(0, (float) rotation.y(), 0)); + poseStack.mulPose(X_QUATERNION_CACHE.rotationXYZ((float) rotation.x(), 0, 0)); } public static void scaleMatrixForBone(PoseStack poseStack, CoreGeoBone bone) { @@ -128,7 +136,8 @@ public static void faceRotation(PoseStack poseStack, Entity animatable, float pa * coordinate triplet to a render matrix */ public static Matrix4f translateMatrix(Matrix4f matrix, Vector3f vector) { - return matrix.add(new Matrix4f().m30(vector.x).m31(vector.y).m32(vector.z)); + TRANSLATE_MATRIX_CACHE.m30(vector.x).m31(vector.y).m32(vector.z); + return matrix.add(TRANSLATE_MATRIX_CACHE); } /** diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java index 03185d603..9c636f4a3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java @@ -31,7 +31,6 @@ /** * Wrapper for {@link SimpleTexture SimpleTexture} implementation allowing for casual use of animated non-atlas textures - * */ public class AnimatableTexture extends SimpleTexture { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java index 46fd9ea8a..6d213ad25 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java @@ -34,7 +34,6 @@ /** * Texture object type responsible for AzureLib's emissive render textures - * */ public class AutoGlowingTexture extends GeoAbstractTexture { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java index 608dbded1..103b0ac00 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java @@ -23,7 +23,6 @@ /** * Metadata class that stores the data for AzureLib's {@link AutoGlowingGeoLayer emissive texture feature} for a given * texture - * */ public class GeoGlowingTextureMeta { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index 4b079febf..e865b5ce1 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -26,6 +26,10 @@ public abstract class AzRendererPipeline { private final AzRendererPipelineContext context; + private final Matrix4f poseStateCache = new Matrix4f(); + + private final Vector3f normalCache = new Vector3f(); + protected AzRendererPipeline() { this.context = createContext(this); } @@ -168,9 +172,6 @@ protected void renderChildBones(AzRendererPipelineContext context, AzBone bon } } - private final Matrix4f poseStateCache = new Matrix4f(); - private final Vector3f normalCache = new Vector3f(); - /** * Renders an individual {@link GeoCube}.
      * This tends to be called recursively from something like {@link AzRendererPipeline#renderCubesOfBone} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java index 8eff8efb5..9c3f2c0fd 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java @@ -77,7 +77,7 @@ public void updateAnimatedTextureFrame(T entity) { @Override public void preRender(AzRendererPipelineContext context, boolean isReRender) { var poseStack = context.poseStack(); - this.entityRenderTranslations = new Matrix4f(poseStack.last().pose()); + this.entityRenderTranslations.set(poseStack.last().pose()); scaleModelForRender( context, @@ -199,7 +199,7 @@ public void actuallyRender(AzRendererPipelineContext context, boolean isReRen } } - this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); + this.modelRenderTranslations.set(poseStack.last().pose()); if (!animatable.isInvisibleTo(Minecraft.getInstance().player)) { super.actuallyRender(context, isReRender); From 4565c27c218da35f8efbe15b1f93dcbcffe33578 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Fri, 20 Dec 2024 01:11:35 -0500 Subject: [PATCH 138/224] Use a utility function for Object casting --- .../azurelib/common/internal/common/util/AzureLibUtil.java | 5 +++++ .../internal/mixins/ItemStackMixin_AzItemAnimatorCache.java | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java index 398544576..3854e831f 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java @@ -27,6 +27,11 @@ */ public record AzureLibUtil() { + + public static T self(Object object) { + return (T) object; + } + /** * Creates a new AnimatableInstanceCache for the given animatable object * diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java index 87586eaf9..e9ad7b808 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java @@ -1,5 +1,7 @@ package mod.azure.azurelib.common.internal.mixins; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; @@ -30,9 +32,7 @@ public void setAnimator(@Nullable AzAnimator animator) { @Override public @Nullable AzAnimator getAnimatorOrNull() { - // TODO: Use a utility function to perform this type of cast. - @SuppressWarnings("all") - var self = (ItemStack) ((Object) this); + var self = AzureLibUtil.self(this); AzIdentifiableItemStackAnimatorCache.getInstance().add(self); return animator; } From 73230c01ee4308349b93cc80c890c0e9be8e1d5d Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 01:22:07 -0500 Subject: [PATCH 139/224] Further split-up of the renderer pipeline code. Signed-off-by: = --- .../core2/render/entity/AzEntityRenderer.java | 2 +- .../core2/render/item/AzItemRenderer.java | 2 +- .../render/pipeline/AzLayerRenderer.java | 45 ++++ .../render/pipeline/AzModelRenderer.java | 157 +++++++++++++ .../render/pipeline/AzPhasedRenderer.java | 19 ++ .../render/pipeline/AzRendererPipeline.java | 209 ++---------------- .../entity/AzEntityLayerRenderer.java | 28 +++ .../AzEntityModelRenderer.java} | 174 +++------------ .../entity/AzEntityRendererPipeline.java | 134 +++++++++++ .../AzEntityRendererPipelineContext.java | 2 +- .../pipeline/item/AzItemModelRenderer.java | 68 ++++++ .../AzItemRendererPipeline.java | 80 ++----- .../AzItemRendererPipelineContext.java | 2 +- 13 files changed, 529 insertions(+), 393 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzLayerRenderer.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzModelRenderer.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzPhasedRenderer.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityLayerRenderer.java rename common/src/main/java/mod/azure/azurelib/core2/render/pipeline/{impl/AzEntityRendererPipeline.java => entity/AzEntityModelRenderer.java} (63%) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java rename common/src/main/java/mod/azure/azurelib/core2/render/pipeline/{impl => entity}/AzEntityRendererPipelineContext.java (96%) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemModelRenderer.java rename common/src/main/java/mod/azure/azurelib/core2/render/pipeline/{impl => item}/AzItemRendererPipeline.java (63%) rename common/src/main/java/mod/azure/azurelib/core2/render/pipeline/{impl => item}/AzItemRendererPipelineContext.java (94%) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index ec4d749f7..fdd878cae 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -18,7 +18,7 @@ import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; -import mod.azure.azurelib.core2.render.pipeline.impl.AzEntityRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.entity.AzEntityRendererPipeline; public abstract class AzEntityRenderer extends EntityRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java index 73f1c4e4d..5644b72a6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -26,7 +26,7 @@ import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; -import mod.azure.azurelib.core2.render.pipeline.impl.AzItemRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.item.AzItemRendererPipeline; public abstract class AzItemRenderer extends BlockEntityWithoutLevelRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzLayerRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzLayerRenderer.java new file mode 100644 index 000000000..374fcd728 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzLayerRenderer.java @@ -0,0 +1,45 @@ +package mod.azure.azurelib.core2.render.pipeline; + +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +import java.util.Collection; +import java.util.function.Supplier; + +public class AzLayerRenderer { + + private final Supplier>> renderLayerSupplier; + + public AzLayerRenderer(Supplier>> renderLayerSupplier) { + this.renderLayerSupplier = renderLayerSupplier; + } + + /** + * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their + * {@link AzRenderLayer#preRender pre-render} actions. + */ + protected void preApplyRenderLayers(AzRendererPipelineContext context) { + for (var renderLayer : renderLayerSupplier.get()) { + renderLayer.preRender(context); + } + } + + /** + * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their + * {@link AzRenderLayer#renderForBone per-bone} render actions. + */ + public void applyRenderLayersForBone(AzRendererPipelineContext context, AzBone bone) { + for (var renderLayer : renderLayerSupplier.get()) { + renderLayer.renderForBone(context, bone); + } + } + + /** + * Render the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer + */ + protected void applyRenderLayers(AzRendererPipelineContext context) { + for (var renderLayer : renderLayerSupplier.get()) { + renderLayer.render(context); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzModelRenderer.java new file mode 100644 index 000000000..91d07b9a1 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzModelRenderer.java @@ -0,0 +1,157 @@ +package mod.azure.azurelib.core2.render.pipeline; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; +import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; +import mod.azure.azurelib.core2.model.AzBone; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.joml.Vector4f; + +public class AzModelRenderer { + + private final Matrix4f poseStateCache = new Matrix4f(); + + private final Vector3f normalCache = new Vector3f(); + + private final AzRendererPipeline rendererPipeline; + + protected final AzLayerRenderer layerRenderer; + + public AzModelRenderer(AzRendererPipeline rendererPipeline, AzLayerRenderer layerRenderer) { + this.layerRenderer = layerRenderer; + this.rendererPipeline = rendererPipeline; + } + + /** + * The actual render method that sub-type renderers should override to handle their specific rendering tasks.
      + */ + protected void render(AzRendererPipelineContext context, boolean isReRender) { + var animatable = context.animatable(); + var model = context.bakedModel(); + + rendererPipeline.updateAnimatedTextureFrame(animatable); + + for (var bone : model.getTopLevelBones()) { + renderRecursively(context, bone, isReRender); + } + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + protected void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + var poseStack = context.poseStack(); + + poseStack.pushPose(); + RenderUtils.prepMatrixForBone(poseStack, bone); + renderCubesOfBone(context, bone); + + if (!isReRender) { + layerRenderer.applyRenderLayersForBone(context, bone); + } + + renderChildBones(context, bone, isReRender); + poseStack.popPose(); + } + + /** + * Renders the {@link GeoCube GeoCubes} associated with a given {@link AzBone} + */ + protected void renderCubesOfBone(AzRendererPipelineContext context, AzBone bone) { + if (bone.isHidden()) { + return; + } + + var poseStack = context.poseStack(); + + for (var cube : bone.getCubes()) { + poseStack.pushPose(); + + renderCube(context, cube); + + poseStack.popPose(); + } + } + + /** + * Render the child bones of a given {@link AzBone}.
      + * Note that this does not render the bone itself. That should be done through + * {@link AzModelRenderer#renderCubesOfBone} separately + */ + protected void renderChildBones(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + if (bone.isHidingChildren()) + return; + + for (var childBone : bone.getChildBones()) { + renderRecursively(context, childBone, isReRender); + } + } + + /** + * Renders an individual {@link GeoCube}.
      + * This tends to be called recursively from something like {@link AzModelRenderer#renderCubesOfBone} + */ + protected void renderCube(AzRendererPipelineContext context, GeoCube cube) { + var poseStack = context.poseStack(); + + RenderUtils.translateToPivotPoint(poseStack, cube); + RenderUtils.rotateMatrixAroundCube(poseStack, cube); + RenderUtils.translateAwayFromPivotPoint(poseStack, cube); + + var normalisedPoseState = poseStack.last().normal(); + var poseState = poseStateCache.set(poseStack.last().pose()); + + for (var quad : cube.quads()) { + if (quad == null) { + continue; + } + + normalCache.set(quad.normal()); + var normal = normalisedPoseState.transform(normalCache); + + RenderUtils.fixInvertedFlatCube(cube, normal); + createVerticesOfQuad(context, quad, poseState, normal); + } + } + + private final Vector4f poseStateTransformCache = new Vector4f(); + + /** + * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for + * rendering + */ + protected void createVerticesOfQuad( + AzRendererPipelineContext context, + GeoQuad quad, + Matrix4f poseState, + Vector3f normal + ) { + var buffer = context.vertexConsumer(); + var color = context.renderColor(); + var packedOverlay = context.packedOverlay(); + var packedLight = context.packedLight(); + + for (var vertex : quad.vertices()) { + var position = vertex.position(); + poseStateTransformCache.set(position.x(), position.y(), position.z(), 1.0f); + var vector4f = poseState.transform(poseStateTransformCache); + + buffer.addVertex( + vector4f.x(), + vector4f.y(), + vector4f.z(), + color, + vertex.texU(), + vertex.texV(), + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzPhasedRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzPhasedRenderer.java new file mode 100644 index 000000000..48ed55860 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzPhasedRenderer.java @@ -0,0 +1,19 @@ +package mod.azure.azurelib.core2.render.pipeline; + +import com.mojang.blaze3d.vertex.PoseStack; + +public interface AzPhasedRenderer { + + /** + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
      + * {@link PoseStack} translations made here are kept until the end of the render process + */ + void preRender(AzRendererPipelineContext context, boolean isReRender); + + /** + * Called after rendering the model to buffer. Post-render modifications should be performed here.
      + * {@link PoseStack} transformations will be unused and lost once this method ends + */ + void postRender(AzRendererPipelineContext context, boolean isReRender); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index e865b5ce1..be742848e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -2,40 +2,37 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.joml.Matrix4f; -import org.joml.Vector3f; -import org.joml.Vector4f; import java.util.List; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; -import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; -import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core2.model.AzBakedModel; -import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; - -public abstract class AzRendererPipeline { +public abstract class AzRendererPipeline implements AzPhasedRenderer { private final AzRendererPipelineContext context; - private final Matrix4f poseStateCache = new Matrix4f(); + private final AzLayerRenderer layerRenderer; - private final Vector3f normalCache = new Vector3f(); + private final AzModelRenderer modelRenderer; protected AzRendererPipeline() { this.context = createContext(this); + this.layerRenderer = createLayerRenderer(); + this.modelRenderer = createModelRenderer(layerRenderer); } protected abstract AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline); + protected abstract AzModelRenderer createModelRenderer(AzLayerRenderer layerRenderer); + + protected abstract AzLayerRenderer createLayerRenderer(); + public abstract @NotNull ResourceLocation getTextureLocation(@NotNull T animatable); /** @@ -76,9 +73,9 @@ public void render( // TODO: // if (firePreRenderEvent(poseStack, model, bufferSource, partialTick, packedLight)) { - preApplyRenderLayers(context); - actuallyRender(context, false); - applyRenderLayers(context); + layerRenderer.preApplyRenderLayers(context); + modelRenderer.render(context, false); + layerRenderer.applyRenderLayers(context); postRender(context, false); // TODO: // firePostRenderEvent(poseStack, model, bufferSource, partialTick, packedLight); @@ -101,184 +98,12 @@ public void reRender(AzRendererPipelineContext context) { poseStack.pushPose(); preRender(context, true); - actuallyRender(context, true); + modelRenderer.render(context, true); postRender(context, true); poseStack.popPose(); } - /** - * The actual render method that sub-type renderers should override to handle their specific rendering tasks.
      - */ - protected void actuallyRender(AzRendererPipelineContext context, boolean isReRender) { - var animatable = context.animatable(); - var model = context.bakedModel(); - - updateAnimatedTextureFrame(animatable); - - for (var bone : model.getTopLevelBones()) { - renderRecursively(context, bone, isReRender); - } - } - - /** - * Renders the provided {@link AzBone} and its associated child bones - */ - protected void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { - var poseStack = context.poseStack(); - - poseStack.pushPose(); - RenderUtils.prepMatrixForBone(poseStack, bone); - renderCubesOfBone(context, bone); - - if (!isReRender) { - applyRenderLayersForBone(context, bone); - } - - renderChildBones(context, bone, isReRender); - poseStack.popPose(); - } - - /** - * Renders the {@link GeoCube GeoCubes} associated with a given {@link AzBone} - */ - protected void renderCubesOfBone(AzRendererPipelineContext context, AzBone bone) { - if (bone.isHidden()) { - return; - } - - var poseStack = context.poseStack(); - - for (var cube : bone.getCubes()) { - poseStack.pushPose(); - - renderCube(context, cube); - - poseStack.popPose(); - } - } - - /** - * Render the child bones of a given {@link AzBone}.
      - * Note that this does not render the bone itself. That should be done through - * {@link AzRendererPipeline#renderCubesOfBone} separately - */ - protected void renderChildBones(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { - if (bone.isHidingChildren()) - return; - - for (var childBone : bone.getChildBones()) { - renderRecursively(context, childBone, isReRender); - } - } - - /** - * Renders an individual {@link GeoCube}.
      - * This tends to be called recursively from something like {@link AzRendererPipeline#renderCubesOfBone} - */ - protected void renderCube(AzRendererPipelineContext context, GeoCube cube) { - var poseStack = context.poseStack(); - - RenderUtils.translateToPivotPoint(poseStack, cube); - RenderUtils.rotateMatrixAroundCube(poseStack, cube); - RenderUtils.translateAwayFromPivotPoint(poseStack, cube); - - var normalisedPoseState = poseStack.last().normal(); - var poseState = poseStateCache.set(poseStack.last().pose()); - - for (var quad : cube.quads()) { - if (quad == null) { - continue; - } - - normalCache.set(quad.normal()); - var normal = normalisedPoseState.transform(normalCache); - - RenderUtils.fixInvertedFlatCube(cube, normal); - createVerticesOfQuad(context, quad, poseState, normal); - } - } - - private final Vector4f poseStateTransformCache = new Vector4f(); - - /** - * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for - * rendering - */ - protected void createVerticesOfQuad( - AzRendererPipelineContext context, - GeoQuad quad, - Matrix4f poseState, - Vector3f normal - ) { - var buffer = context.vertexConsumer(); - var color = context.renderColor(); - var packedOverlay = context.packedOverlay(); - var packedLight = context.packedLight(); - - for (var vertex : quad.vertices()) { - var position = vertex.position(); - poseStateTransformCache.set(position.x(), position.y(), position.z(), 1.0f); - var vector4f = poseState.transform(poseStateTransformCache); - - buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - color, - vertex.texU(), - vertex.texV(), - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() - ); - } - } - - /** - * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their - * {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#preRender pre-render} actions. - */ - protected void preApplyRenderLayers(AzRendererPipelineContext context) { - for (var renderLayer : getRenderLayers()) { - renderLayer.preRender(context); - } - } - - /** - * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their - * {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer#renderForBone per-bone} render actions. - */ - protected void applyRenderLayersForBone(AzRendererPipelineContext context, AzBone bone) { - for (var renderLayer : getRenderLayers()) { - renderLayer.renderForBone(context, bone); - } - } - - /** - * Render the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer - */ - protected void applyRenderLayers(AzRendererPipelineContext context) { - for (var renderLayer : getRenderLayers()) { - renderLayer.render(context); - } - } - - /** - * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling - * and translating.
      - * {@link PoseStack} translations made here are kept until the end of the render process - */ - protected void preRender(AzRendererPipelineContext context, boolean isReRender) {} - - /** - * Called after rendering the model to buffer. Post-render modifications should be performed here.
      - * {@link PoseStack} transformations will be unused and lost once this method ends - */ - protected void postRender(AzRendererPipelineContext context, boolean isReRender) {} - /** * Call after all other rendering work has taken place, including reverting the {@link PoseStack}'s state. This * method is not called in {@link AzRendererPipeline#reRender re-render} @@ -295,7 +120,7 @@ protected void doPostRenderCleanup() {} /** * Scales the {@link PoseStack} in preparation for rendering the model, excluding when re-rendering the model as - * part of a {@link mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer} or external render call.
      + * part of a {@link AzRenderLayer} or external render call.
      * Override and call super with modified scale values as needed to further modify the scale of the model (E.G. child * entities) */ diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityLayerRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityLayerRenderer.java new file mode 100644 index 000000000..dbfde6a56 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityLayerRenderer.java @@ -0,0 +1,28 @@ +package mod.azure.azurelib.core2.render.pipeline.entity; + +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import net.minecraft.world.entity.Entity; + +import java.util.Collection; +import java.util.function.Supplier; + +public class AzEntityLayerRenderer extends AzLayerRenderer { + + public AzEntityLayerRenderer(Supplier>> renderLayerSupplier) { + super(renderLayerSupplier); + } + + /** + * Render the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer + */ + @Override + public void applyRenderLayers(AzRendererPipelineContext context) { + var animatable = context.animatable(); + + if (!animatable.isSpectator()) { + super.applyRenderLayers(context); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java similarity index 63% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java rename to common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java index 9c3f2c0fd..8737afdc1 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java @@ -1,90 +1,29 @@ -package mod.azure.azurelib.core2.render.pipeline.impl; +package mod.azure.azurelib.core2.render.pipeline.entity; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.entity.LivingEntityRenderer; import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Pose; -import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; -import java.util.List; - -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.entity.AzEntityLeashRenderUtil; -import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; - -public class AzEntityRendererPipeline extends AzRendererPipeline { - - private final AzEntityRenderer entityRenderer; +public class AzEntityModelRenderer extends AzModelRenderer { - protected Matrix4f entityRenderTranslations = new Matrix4f(); + private final AzEntityRendererPipeline entityRendererPipeline; - protected Matrix4f modelRenderTranslations = new Matrix4f(); - - public AzEntityRendererPipeline(AzEntityRenderer entityRenderer) { - this.entityRenderer = entityRenderer; - } - - @Override - protected AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { - return new AzEntityRendererPipelineContext<>(this); - } - - @Override - public @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { - return entityRenderer.getTextureLocation(animatable); - } - - @Override - protected List> getRenderLayers() { - return entityRenderer.getRenderLayers(); - } - - /** - * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this - * GeoRenderer.
      - * This should only be called immediately prior to rendering, and only - * - * @see AnimatableTexture#setAndUpdate(ResourceLocation, int) - */ - @Override - public void updateAnimatedTextureFrame(T entity) { - AnimatableTexture.setAndUpdate( - getTextureLocation(entity), - entity.getId() + entity.tickCount - ); - } - - /** - * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling - * and translating.
      - * {@link PoseStack} translations made here are kept until the end of the render process - */ - @Override - public void preRender(AzRendererPipelineContext context, boolean isReRender) { - var poseStack = context.poseStack(); - this.entityRenderTranslations.set(poseStack.last().pose()); - - scaleModelForRender( - context, - this.entityRenderer.getScaleWidth(), - this.entityRenderer.getScaleHeight(), - isReRender - ); + public AzEntityModelRenderer(AzEntityRendererPipeline entityRendererPipeline, AzLayerRenderer layerRenderer) { + super(entityRendererPipeline, layerRenderer); + this.entityRendererPipeline = entityRendererPipeline; } /** @@ -93,7 +32,7 @@ public void preRender(AzRendererPipelineContext context, boolean isReRender) * {@link AzEntityRendererPipeline#postRender} will be called directly after */ @Override - public void actuallyRender(AzRendererPipelineContext context, boolean isReRender) { + public void render(AzRendererPipelineContext context, boolean isReRender) { var animatable = context.animatable(); var partialTick = context.partialTick(); var poseStack = context.poseStack(); @@ -106,17 +45,17 @@ public void actuallyRender(AzRendererPipelineContext context, boolean isReRen float lerpBodyRot = livingEntity == null ? 0 : Mth.rotLerp( - partialTick, - livingEntity.yBodyRotO, - livingEntity.yBodyRot - ); + partialTick, + livingEntity.yBodyRotO, + livingEntity.yBodyRot + ); float lerpHeadRot = livingEntity == null ? 0 : Mth.rotLerp( - partialTick, - livingEntity.yHeadRotO, - livingEntity.yHeadRot - ); + partialTick, + livingEntity.yHeadRotO, + livingEntity.yHeadRot + ); float netHeadYaw = lerpHeadRot - lerpBodyRot; if (shouldSit && animatable.getVehicle() instanceof LivingEntity livingentity) { @@ -192,34 +131,22 @@ public void actuallyRender(AzRendererPipelineContext context, boolean isReRen // // this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); - var animator = entityRenderer.getAnimator(); + var animator = entityRendererPipeline.getRenderer().getAnimator(); if (animator != null) { animator.animate(animatable); } } - this.modelRenderTranslations.set(poseStack.last().pose()); + entityRendererPipeline.modelRenderTranslations.set(poseStack.last().pose()); if (!animatable.isInvisibleTo(Minecraft.getInstance().player)) { - super.actuallyRender(context, isReRender); + super.render(context, isReRender); } poseStack.popPose(); } - /** - * Render the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer - */ - @Override - public void applyRenderLayers(AzRendererPipelineContext context) { - var animatable = context.animatable(); - - if (!animatable.isSpectator()) { - super.applyRenderLayers(context); - } - } - /** * Renders the provided {@link AzBone} and its associated child bones */ @@ -239,11 +166,11 @@ public void renderRecursively(AzRendererPipelineContext context, AzBone bone, if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); - Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices(poseState, this.entityRenderTranslations); + Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices(poseState, entityRendererPipeline.entityRenderTranslations); - bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); + bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, entityRendererPipeline.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, entityRenderer.getRenderOffset(entity, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, entityRendererPipeline.getRenderer().getRenderOffset(entity, 1).toVector3f()) ); bone.setWorldSpaceMatrix( RenderUtils.translateMatrix(new Matrix4f(localMatrix), entity.position().toVector3f()) @@ -259,7 +186,7 @@ public void renderRecursively(AzRendererPipelineContext context, AzBone bone, renderCubesOfBone(context, bone); if (!isReRender) { - applyRenderLayersForBone(context, bone); + layerRenderer.applyRenderLayersForBone(context, bone); } renderChildBones(context, bone, isReRender); @@ -267,29 +194,6 @@ public void renderRecursively(AzRendererPipelineContext context, AzBone bone, poseStack.popPose(); } - @Override - public void renderFinal(AzRendererPipelineContext context) { - var bufferSource = context.multiBufferSource(); - var entity = context.animatable(); - var packedLight = context.packedLight(); - var partialTick = context.partialTick(); - var poseStack = context.poseStack(); - - entityRenderer.superRender(entity, 0, partialTick, poseStack, bufferSource, packedLight); - - if (!(entity instanceof Mob mob)) { - return; - } - - var leashHolder = mob.getLeashHolder(); - - if (leashHolder == null) { - return; - } - - AzEntityLeashRenderUtil.renderLeash(entityRenderer, mob, partialTick, poseStack, bufferSource, leashHolder); - } - /** * Applies rotation transformations to the renderer prior to render time to account for various entity states, * default scale of 1 @@ -316,7 +220,7 @@ protected void applyRotations( float partialTick, float nativeScale ) { - if (isShaking(animatable)) { + if (entityRendererPipeline.isShaking(animatable)) { rotationYaw += (float) (Math.cos(animatable.tickCount * 3.25d) * Math.PI * 0.4d); } @@ -325,11 +229,14 @@ protected void applyRotations( } if (animatable instanceof LivingEntity livingEntity) { + + var deathMaxRotation = entityRendererPipeline.getDeathMaxRotation(animatable); + if (livingEntity.deathTime > 0) { float deathRotation = (livingEntity.deathTime + partialTick - 1f) / 20f * 1.6f; poseStack.mulPose( - Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable)) + Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * deathMaxRotation) ); } else if (livingEntity.isAutoSpinAttack()) { poseStack.mulPose(Axis.XP.rotationDegrees(-90f - livingEntity.getXRot())); @@ -342,7 +249,7 @@ protected void applyRotations( bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw ) ); - poseStack.mulPose(Axis.ZP.rotationDegrees(getDeathMaxRotation(animatable))); + poseStack.mulPose(Axis.ZP.rotationDegrees(deathMaxRotation)); poseStack.mulPose(Axis.YP.rotationDegrees(270f)); } else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { poseStack.translate(0, (animatable.getBbHeight() + 0.1f) / nativeScale, 0); @@ -350,19 +257,4 @@ protected void applyRotations( } } } - - /** - * Gets the max rotation value for dying entities.
      - * You might want to modify this for different aesthetics, such as a - * {@link net.minecraft.world.entity.monster.Spider} flipping upside down on death.
      - * Functionally equivalent to {@link net.minecraft.client.renderer.entity.LivingEntityRenderer#getFlipDegrees} - */ - protected float getDeathMaxRotation(T entity) { - return 90f; - } - - public boolean isShaking(T entity) { - return entity.isFullyFrozen(); - } - } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java new file mode 100644 index 000000000..5132eb6e5 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java @@ -0,0 +1,134 @@ +package mod.azure.azurelib.core2.render.pipeline.entity; + +import com.mojang.blaze3d.vertex.PoseStack; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.render.entity.AzEntityLeashRenderUtil; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Mob; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; + +import java.util.List; + +public class AzEntityRendererPipeline extends AzRendererPipeline { + + private final AzEntityRenderer entityRenderer; + + protected Matrix4f entityRenderTranslations = new Matrix4f(); + + protected Matrix4f modelRenderTranslations = new Matrix4f(); + + public AzEntityRendererPipeline(AzEntityRenderer entityRenderer) { + super(); + this.entityRenderer = entityRenderer; + } + + @Override + protected AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { + return new AzEntityRendererPipelineContext<>(this); + } + + @Override + protected AzModelRenderer createModelRenderer(AzLayerRenderer layerRenderer) { + return new AzEntityModelRenderer<>(this, layerRenderer); + } + + @Override + protected AzLayerRenderer createLayerRenderer() { + return new AzEntityLayerRenderer<>(this::getRenderLayers); + } + + @Override + public @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { + return entityRenderer.getTextureLocation(animatable); + } + + @Override + protected List> getRenderLayers() { + return entityRenderer.getRenderLayers(); + } + + /** + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
      + * This should only be called immediately prior to rendering, and only + * + * @see AnimatableTexture#setAndUpdate(ResourceLocation, int) + */ + @Override + public void updateAnimatedTextureFrame(T entity) { + AnimatableTexture.setAndUpdate( + getTextureLocation(entity), + entity.getId() + entity.tickCount + ); + } + + /** + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
      + * {@link PoseStack} translations made here are kept until the end of the render process + */ + @Override + public void preRender(AzRendererPipelineContext context, boolean isReRender) { + var poseStack = context.poseStack(); + this.entityRenderTranslations.set(poseStack.last().pose()); + + scaleModelForRender( + context, + this.entityRenderer.getScaleWidth(), + this.entityRenderer.getScaleHeight(), + isReRender + ); + } + + @Override + public void postRender(AzRendererPipelineContext context, boolean isReRender) {} + + @Override + public void renderFinal(AzRendererPipelineContext context) { + var bufferSource = context.multiBufferSource(); + var entity = context.animatable(); + var packedLight = context.packedLight(); + var partialTick = context.partialTick(); + var poseStack = context.poseStack(); + + entityRenderer.superRender(entity, 0, partialTick, poseStack, bufferSource, packedLight); + + if (!(entity instanceof Mob mob)) { + return; + } + + var leashHolder = mob.getLeashHolder(); + + if (leashHolder == null) { + return; + } + + AzEntityLeashRenderUtil.renderLeash(entityRenderer, mob, partialTick, poseStack, bufferSource, leashHolder); + } + + /** + * Gets the max rotation value for dying entities.
      + * You might want to modify this for different aesthetics, such as a + * {@link net.minecraft.world.entity.monster.Spider} flipping upside down on death.
      + * Functionally equivalent to {@link net.minecraft.client.renderer.entity.LivingEntityRenderer#getFlipDegrees} + */ + protected float getDeathMaxRotation(T entity) { + return 90f; + } + + public boolean isShaking(T entity) { + return entity.isFullyFrozen(); + } + + public AzEntityRenderer getRenderer() { + return entityRenderer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipelineContext.java similarity index 96% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipelineContext.java rename to common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipelineContext.java index d0bb6bb08..e4fd08a8b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzEntityRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipelineContext.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline.impl; +package mod.azure.azurelib.core2.render.pipeline.entity; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemModelRenderer.java new file mode 100644 index 000000000..67e708e92 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemModelRenderer.java @@ -0,0 +1,68 @@ +package mod.azure.azurelib.core2.render.pipeline.item; + +import mod.azure.azurelib.core2.render.pipeline.AzPhasedRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; + +public class AzItemModelRenderer extends AzModelRenderer { + + private final AzItemRendererPipeline itemRendererPipeline; + + public AzItemModelRenderer(AzItemRendererPipeline itemRendererPipeline, AzLayerRenderer layerRenderer) { + super(itemRendererPipeline, layerRenderer); + this.itemRendererPipeline = itemRendererPipeline; + } + + /** + * The actual render method that subtype renderers should override to handle their specific rendering tasks.
      + * {@link AzPhasedRenderer#preRender} has already been called by this stage, and {@link AzPhasedRenderer#postRender} will be + * called directly after + */ + @Override + public void render(AzRendererPipelineContext context, boolean isReRender) { + if (!isReRender) { + var animatable = context.animatable(); + var animator = itemRendererPipeline.getRenderer().getAnimator(); + + if (animator != null) { + animator.animate(animatable); + } + } + + var poseStack = context.poseStack(); + + itemRendererPipeline.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); + + super.render(context, isReRender); + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + @Override + public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + if (bone.isTrackingMatrices()) { + var animatable = context.animatable(); + var poseStack = context.poseStack(); + var poseState = new Matrix4f(poseStack.last().pose()); + var localMatrix = RenderUtils.invertAndMultiplyMatrices(poseState, itemRendererPipeline.itemRenderTranslations); + + bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, itemRendererPipeline.modelRenderTranslations)); + bone.setLocalSpaceMatrix( + RenderUtils.translateMatrix(localMatrix, getRenderOffset(animatable, 1).toVector3f()) + ); + } + + super.renderRecursively(context, bone, isReRender); + } + + public Vec3 getRenderOffset(ItemStack itemStack, float f) { + return Vec3.ZERO; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java similarity index 63% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java rename to common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java index d1a2af3ce..8de002d84 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java @@ -1,24 +1,21 @@ -package mod.azure.azurelib.core2.render.pipeline.impl; +package mod.azure.azurelib.core2.render.pipeline.item; import com.mojang.blaze3d.vertex.PoseStack; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.render.item.AzItemRenderer; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; import java.util.List; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.item.AzItemRenderer; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; - public class AzItemRendererPipeline extends AzRendererPipeline { private final AzItemRenderer itemRenderer; @@ -28,6 +25,7 @@ public class AzItemRendererPipeline extends AzRendererPipeline { protected Matrix4f modelRenderTranslations = new Matrix4f(); public AzItemRendererPipeline(AzItemRenderer itemRenderer) { + super(); this.itemRenderer = itemRenderer; } @@ -36,6 +34,16 @@ protected AzRendererPipelineContext createContext(AzRendererPipeline< return new AzItemRendererPipelineContext(rendererPipeline); } + @Override + protected AzItemModelRenderer createModelRenderer(AzLayerRenderer layerRenderer) { + return new AzItemModelRenderer(this, layerRenderer); + } + + @Override + protected AzLayerRenderer createLayerRenderer() { + return new AzLayerRenderer<>(this::getRenderLayers); + } + @Override public @NotNull ResourceLocation getTextureLocation(@NotNull ItemStack animatable) { return itemRenderer.getTextureLocation(animatable); @@ -63,48 +71,8 @@ public void preRender(AzRendererPipelineContext context, boolean isRe } } - /** - * The actual render method that subtype renderers should override to handle their specific rendering tasks.
      - * {@link GeoRenderer#preRender} has already been called by this stage, and {@link GeoRenderer#postRender} will be - * called directly after - */ - @Override - public void actuallyRender(AzRendererPipelineContext context, boolean isReRender) { - if (!isReRender) { - var animatable = context.animatable(); - var animator = itemRenderer.getAnimator(); - - if (animator != null) { - animator.animate(animatable); - } - } - - var poseStack = context.poseStack(); - - this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); - - super.actuallyRender(context, isReRender); - } - - /** - * Renders the provided {@link AzBone} and its associated child bones - */ @Override - public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { - if (bone.isTrackingMatrices()) { - var animatable = context.animatable(); - var poseStack = context.poseStack(); - var poseState = new Matrix4f(poseStack.last().pose()); - var localMatrix = RenderUtils.invertAndMultiplyMatrices(poseState, this.itemRenderTranslations); - - bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); - bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(animatable, 1).toVector3f()) - ); - } - - super.renderRecursively(context, bone, isReRender); - } + public void postRender(AzRendererPipelineContext context, boolean isReRender) {} /** * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this @@ -121,10 +89,6 @@ public void updateAnimatedTextureFrame(ItemStack animatable) { ); } - public Vec3 getRenderOffset(ItemStack itemStack, float f) { - return Vec3.ZERO; - } - /** * Determines whether to apply the y offset for a model due to the change in BlockBench 4.11. * @@ -135,4 +99,8 @@ public Vec3 getRenderOffset(ItemStack itemStack, float f) { public boolean useNewOffset() { return false; } + + public AzItemRenderer getRenderer() { + return itemRenderer; + } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipelineContext.java similarity index 94% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java rename to common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipelineContext.java index a3e85fee5..c5541b9c8 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzItemRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipelineContext.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline.impl; +package mod.azure.azurelib.core2.render.pipeline.item; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; From 0def8f3855dcb26b8cd06ad221c5292586191e34 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 02:00:50 -0500 Subject: [PATCH 140/224] Added render config for renderer properties. Signed-off-by: = --- .../internal/common/util/AzureLibUtil.java | 1 - .../ItemStackMixin_AzItemAnimatorCache.java | 3 +- .../core2/render/AzItemRendererConfig.java | 76 +++++++++++++++++++ .../core2/render/AzRendererConfig.java | 55 ++++++++++++++ .../core2/render/entity/AzEntityRenderer.java | 35 +++------ .../core2/render/item/AzItemRenderer.java | 65 ++++++---------- .../render/pipeline/AzLayerRenderer.java | 6 +- .../render/pipeline/AzModelRenderer.java | 7 +- .../render/pipeline/AzRendererPipeline.java | 7 +- .../entity/AzEntityLayerRenderer.java | 7 +- .../entity/AzEntityModelRenderer.java | 41 ++++++---- .../entity/AzEntityRendererPipeline.java | 26 +++---- .../pipeline/item/AzItemModelRenderer.java | 22 ++++-- .../pipeline/item/AzItemRendererPipeline.java | 34 ++++----- 14 files changed, 244 insertions(+), 141 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java index 3854e831f..28acb96b6 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java @@ -27,7 +27,6 @@ */ public record AzureLibUtil() { - public static T self(Object object) { return (T) object; } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java index e9ad7b808..a73e1317a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java @@ -1,7 +1,5 @@ package mod.azure.azurelib.common.internal.mixins; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; -import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; @@ -9,6 +7,7 @@ import java.lang.ref.WeakReference; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.cache.AzIdentifiableItemStackAnimatorCache; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java new file mode 100644 index 000000000..90b5333ae --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java @@ -0,0 +1,76 @@ +package mod.azure.azurelib.core2.render; + +public class AzItemRendererConfig extends AzRendererConfig { + + private final boolean useEntityGuiLighting; + + private final boolean useNewOffset; + + private AzItemRendererConfig( + float scaleHeight, + float scaleWidth, + boolean useEntityGuiLighting, + boolean useNewOffset + ) { + super(scaleHeight, scaleWidth); + this.useEntityGuiLighting = useEntityGuiLighting; + this.useNewOffset = useNewOffset; + } + + public boolean useEntityGuiLighting() { + return useEntityGuiLighting; + } + + public boolean useNewOffset() { + return useNewOffset; + } + + public static AzItemRendererConfig defaultConfig() { + return builder().build(); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AzRendererConfig.Builder { + + private boolean useEntityGuiLighting; + + private boolean useNewOffset; + + protected Builder() { + super(); + this.useEntityGuiLighting = false; + this.useNewOffset = false; + } + + public Builder useEntityGuiLighting() { + this.useEntityGuiLighting = true; + return this; + } + + public boolean useNewOffset() { + return useNewOffset; + } + + /** + * @param useNewOffset Determines whether to apply the y offset for a model due to the change in BlockBench + * 4.11. + */ + public AzRendererConfig.Builder useNewOffset(boolean useNewOffset) { + this.useNewOffset = useNewOffset; + return this; + } + + public AzItemRendererConfig build() { + var baseConfig = super.build(); + return new AzItemRendererConfig( + baseConfig.scaleHeight(), + baseConfig.scaleWidth(), + useEntityGuiLighting, + useNewOffset + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java new file mode 100644 index 000000000..d84ec35b6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java @@ -0,0 +1,55 @@ +package mod.azure.azurelib.core2.render; + +public class AzRendererConfig { + + private final float scaleHeight; + + private final float scaleWidth; + + public AzRendererConfig(float scaleHeight, float scaleWidth) { + this.scaleHeight = scaleHeight; + this.scaleWidth = scaleWidth; + } + + public float scaleHeight() { + return scaleHeight; + } + + public float scaleWidth() { + return scaleWidth; + } + + public static AzRendererConfig defaultConfig() { + return builder().build(); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private float scaleHeight; + + private float scaleWidth; + + protected Builder() { + this.scaleHeight = 1; + this.scaleWidth = 1; + } + + public Builder withScale(float scale) { + return withScale(scale, scale); + } + + public Builder withScale(float scaleWidth, float scaleHeight) { + this.scaleHeight = scaleHeight; + this.scaleWidth = scaleWidth; + return this; + } + + public AzRendererConfig build() { + return new AzRendererConfig(scaleHeight, scaleWidth); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index fdd878cae..0f26e9a88 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -17,6 +17,7 @@ import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; +import mod.azure.azurelib.core2.render.AzRendererConfig; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import mod.azure.azurelib.core2.render.pipeline.entity.AzEntityRendererPipeline; @@ -26,15 +27,18 @@ public abstract class AzEntityRenderer extends EntityRenderer< private final List> renderLayers; - private float scaleWidth = 1; - - private float scaleHeight = 1; + private final AzRendererConfig config; @Nullable private AzEntityAnimator reusedAzEntityAnimator; protected AzEntityRenderer(EntityRendererProvider.Context context) { + this(AzRendererConfig.defaultConfig(), context); + } + + protected AzEntityRenderer(AzRendererConfig config, EntityRendererProvider.Context context) { super(context); + this.config = config; this.rendererPipeline = new AzEntityRendererPipeline<>(this); this.renderLayers = new ObjectArrayList<>(); } @@ -115,23 +119,6 @@ public void render( return cachedEntityAnimator; } - /** - * Sets a scale override for this renderer, telling AzureLib to pre-scale the model - */ - public AzEntityRenderer withScale(float scale) { - return withScale(scale, scale); - } - - /** - * Sets a scale override for this renderer, telling AzureLib to pre-scale the model - */ - public AzEntityRenderer withScale(float scaleWidth, float scaleHeight) { - this.scaleWidth = scaleWidth; - this.scaleHeight = scaleHeight; - - return this; - } - /** * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer */ @@ -167,11 +154,7 @@ public AzEntityAnimator getAnimator() { return reusedAzEntityAnimator; } - public float getScaleHeight() { - return scaleHeight; - } - - public float getScaleWidth() { - return scaleWidth; + public AzRendererConfig config() { + return config; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java index 5644b72a6..c5180e185 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -20,11 +20,11 @@ import java.util.List; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; +import mod.azure.azurelib.core2.render.AzItemRendererConfig; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import mod.azure.azurelib.core2.render.pipeline.item.AzItemRendererPipeline; @@ -34,23 +34,32 @@ public abstract class AzItemRenderer extends BlockEntityWithoutLevelRenderer { private final List> renderLayers; - protected float scaleWidth = 1; - - protected float scaleHeight = 1; - - protected boolean useEntityGuiLighting = false; + private final AzItemRendererConfig config; @Nullable private AzItemAnimator reusedAzItemAnimator; protected AzItemRenderer() { - this(Minecraft.getInstance().getBlockEntityRenderDispatcher(), Minecraft.getInstance().getEntityModels()); + this(AzItemRendererConfig.defaultConfig()); + } + + protected AzItemRenderer(AzItemRendererConfig config) { + this( + Minecraft.getInstance().getBlockEntityRenderDispatcher(), + Minecraft.getInstance().getEntityModels(), + config + ); } - protected AzItemRenderer(BlockEntityRenderDispatcher dispatcher, EntityModelSet modelSet) { + protected AzItemRenderer( + BlockEntityRenderDispatcher dispatcher, + EntityModelSet modelSet, + AzItemRendererConfig config + ) { super(dispatcher, modelSet); this.rendererPipeline = new AzItemRendererPipeline(this); this.renderLayers = new ObjectArrayList<>(); + this.config = config; } protected abstract @NotNull ResourceLocation getModelLocation(ItemStack item); @@ -137,7 +146,7 @@ protected void renderInGui( int packedLight, int packedOverlay ) { - if (this.useEntityGuiLighting) { + if (config.useEntityGuiLighting()) { Lighting.setupForEntityInInventory(); } else { Lighting.setupForFlatItems(); @@ -209,40 +218,14 @@ protected void renderInGui( } /** - * Mark this renderer so that it uses an alternate lighting scheme when rendering the item in GUI - *

      - * This can help with improperly lit 3d models - */ - public AzItemRenderer useAlternateGuiLighting() { - this.useEntityGuiLighting = true; - return this; - } - - /** - * Sets a scale override for this renderer, telling AzureLib to pre-scale the model - */ - public AzItemRenderer withScale(float scale) { - return withScale(scale, scale); - } - - /** - * Sets a scale override for this renderer, telling AzureLib to pre-scale the model - */ - public AzItemRenderer withScale(float scaleWidth, float scaleHeight) { - this.scaleWidth = scaleWidth; - this.scaleHeight = scaleHeight; - return this; - } - - /** - * Returns the list of registered {@link GeoRenderLayer GeoRenderLayers} for this renderer + * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer */ public List> getRenderLayers() { return renderLayers; } /** - * Adds a {@link GeoRenderLayer} to this renderer, to be called after the main model is rendered each frame + * Adds a {@link AzRenderLayer} to this renderer, to be called after the main model is rendered each frame */ public AzItemRenderer addRenderLayer(AzRenderLayer renderLayer) { this.renderLayers.add(renderLayer); @@ -253,11 +236,7 @@ public AzItemRenderer addRenderLayer(AzRenderLayer renderLayer) { return reusedAzItemAnimator; } - public float getScaleHeight() { - return scaleHeight; - } - - public float getScaleWidth() { - return scaleWidth; + public AzItemRendererConfig config() { + return config; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzLayerRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzLayerRenderer.java index 374fcd728..746810a85 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzLayerRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzLayerRenderer.java @@ -1,11 +1,11 @@ package mod.azure.azurelib.core2.render.pipeline; -import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; - import java.util.Collection; import java.util.function.Supplier; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + public class AzLayerRenderer { private final Supplier>> renderLayerSupplier; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzModelRenderer.java index 91d07b9a1..ba592d225 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzModelRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzModelRenderer.java @@ -1,14 +1,15 @@ package mod.azure.azurelib.core2.render.pipeline; import com.mojang.blaze3d.vertex.VertexConsumer; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.joml.Vector4f; + import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; import mod.azure.azurelib.core2.model.AzBone; -import org.joml.Matrix4f; -import org.joml.Vector3f; -import org.joml.Vector4f; public class AzModelRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index be742848e..f81563d58 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -2,9 +2,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core2.model.AzBakedModel; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; @@ -13,6 +10,10 @@ import java.util.List; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + public abstract class AzRendererPipeline implements AzPhasedRenderer { private final AzRendererPipelineContext context; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityLayerRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityLayerRenderer.java index dbfde6a56..e097ac1ab 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityLayerRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityLayerRenderer.java @@ -1,13 +1,14 @@ package mod.azure.azurelib.core2.render.pipeline.entity; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; -import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; import net.minecraft.world.entity.Entity; import java.util.Collection; import java.util.function.Supplier; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; + public class AzEntityLayerRenderer extends AzLayerRenderer { public AzEntityLayerRenderer(Supplier>> renderLayerSupplier) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java index 8737afdc1..01a6ec2c9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java @@ -3,11 +3,6 @@ import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.entity.LivingEntityRenderer; import net.minecraft.core.Direction; @@ -17,6 +12,12 @@ import net.minecraft.world.entity.Pose; import org.joml.Matrix4f; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; + public class AzEntityModelRenderer extends AzModelRenderer { private final AzEntityRendererPipeline entityRendererPipeline; @@ -45,17 +46,17 @@ public void render(AzRendererPipelineContext context, boolean isReRender) { float lerpBodyRot = livingEntity == null ? 0 : Mth.rotLerp( - partialTick, - livingEntity.yBodyRotO, - livingEntity.yBodyRot - ); + partialTick, + livingEntity.yBodyRotO, + livingEntity.yBodyRot + ); float lerpHeadRot = livingEntity == null ? 0 : Mth.rotLerp( - partialTick, - livingEntity.yHeadRotO, - livingEntity.yHeadRot - ); + partialTick, + livingEntity.yHeadRotO, + livingEntity.yHeadRot + ); float netHeadYaw = lerpHeadRot - lerpBodyRot; if (shouldSit && animatable.getVehicle() instanceof LivingEntity livingentity) { @@ -166,11 +167,19 @@ public void renderRecursively(AzRendererPipelineContext context, AzBone bone, if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); - Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices(poseState, entityRendererPipeline.entityRenderTranslations); + Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices( + poseState, + entityRendererPipeline.entityRenderTranslations + ); - bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, entityRendererPipeline.modelRenderTranslations)); + bone.setModelSpaceMatrix( + RenderUtils.invertAndMultiplyMatrices(poseState, entityRendererPipeline.modelRenderTranslations) + ); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, entityRendererPipeline.getRenderer().getRenderOffset(entity, 1).toVector3f()) + RenderUtils.translateMatrix( + localMatrix, + entityRendererPipeline.getRenderer().getRenderOffset(entity, 1).toVector3f() + ) ); bone.setWorldSpaceMatrix( RenderUtils.translateMatrix(new Matrix4f(localMatrix), entity.position().toVector3f()) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java index 5132eb6e5..f240091b4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java @@ -1,6 +1,14 @@ package mod.azure.azurelib.core2.render.pipeline.entity; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Mob; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; + +import java.util.List; + import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; import mod.azure.azurelib.core2.render.entity.AzEntityLeashRenderUtil; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; @@ -9,13 +17,6 @@ import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.Mob; -import org.jetbrains.annotations.NotNull; -import org.joml.Matrix4f; - -import java.util.List; public class AzEntityRendererPipeline extends AzRendererPipeline { @@ -80,12 +81,11 @@ public void preRender(AzRendererPipelineContext context, boolean isReRender) var poseStack = context.poseStack(); this.entityRenderTranslations.set(poseStack.last().pose()); - scaleModelForRender( - context, - this.entityRenderer.getScaleWidth(), - this.entityRenderer.getScaleHeight(), - isReRender - ); + var config = entityRenderer.config(); + var scaleWidth = config.scaleWidth(); + var scaleHeight = config.scaleHeight(); + + scaleModelForRender(context, scaleWidth, scaleHeight, isReRender); } @Override diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemModelRenderer.java index 67e708e92..94c779707 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemModelRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemModelRenderer.java @@ -1,14 +1,15 @@ package mod.azure.azurelib.core2.render.pipeline.item; -import mod.azure.azurelib.core2.render.pipeline.AzPhasedRenderer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; + import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzPhasedRenderer; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.Vec3; -import org.joml.Matrix4f; public class AzItemModelRenderer extends AzModelRenderer { @@ -21,8 +22,8 @@ public AzItemModelRenderer(AzItemRendererPipeline itemRendererPipeline, AzLayerR /** * The actual render method that subtype renderers should override to handle their specific rendering tasks.
      - * {@link AzPhasedRenderer#preRender} has already been called by this stage, and {@link AzPhasedRenderer#postRender} will be - * called directly after + * {@link AzPhasedRenderer#preRender} has already been called by this stage, and {@link AzPhasedRenderer#postRender} + * will be called directly after */ @Override public void render(AzRendererPipelineContext context, boolean isReRender) { @@ -51,9 +52,14 @@ public void renderRecursively(AzRendererPipelineContext context, AzBo var animatable = context.animatable(); var poseStack = context.poseStack(); var poseState = new Matrix4f(poseStack.last().pose()); - var localMatrix = RenderUtils.invertAndMultiplyMatrices(poseState, itemRendererPipeline.itemRenderTranslations); + var localMatrix = RenderUtils.invertAndMultiplyMatrices( + poseState, + itemRendererPipeline.itemRenderTranslations + ); - bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, itemRendererPipeline.modelRenderTranslations)); + bone.setModelSpaceMatrix( + RenderUtils.invertAndMultiplyMatrices(poseState, itemRendererPipeline.modelRenderTranslations) + ); bone.setLocalSpaceMatrix( RenderUtils.translateMatrix(localMatrix, getRenderOffset(animatable, 1).toVector3f()) ); diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java index 8de002d84..5ffc8cd9e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java @@ -1,13 +1,6 @@ package mod.azure.azurelib.core2.render.pipeline.item; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core2.render.item.AzItemRenderer; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; -import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -16,6 +9,14 @@ import java.util.List; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.render.item.AzItemRenderer; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; + public class AzItemRendererPipeline extends AzRendererPipeline { private final AzItemRenderer itemRenderer; @@ -64,10 +65,14 @@ public void preRender(AzRendererPipelineContext context, boolean isRe var poseStack = context.poseStack(); this.itemRenderTranslations = new Matrix4f(poseStack.last().pose()); - scaleModelForRender(context, this.itemRenderer.getScaleWidth(), this.itemRenderer.getScaleHeight(), isReRender); + var config = itemRenderer.config(); + var scaleWidth = config.scaleWidth(); + var scaleHeight = config.scaleHeight(); + scaleModelForRender(context, scaleWidth, scaleHeight, isReRender); if (!isReRender) { - poseStack.translate(0.5f, this.useNewOffset() ? 0.0f : 0.51f, 0.5f); + var useNewOffset = config.useNewOffset(); + poseStack.translate(0.5f, useNewOffset ? 0.0f : 0.51f, 0.5f); } } @@ -89,17 +94,6 @@ public void updateAnimatedTextureFrame(ItemStack animatable) { ); } - /** - * Determines whether to apply the y offset for a model due to the change in BlockBench 4.11. - * - * @return {@code false} by default, meaning the Y-offset will be {@code 0.51f}. Override this method or change the - * return value to {@code true} to use the new Y-offset of {@code 0.0f} for anything created in 4.11+ of - * Blockbench. - */ - public boolean useNewOffset() { - return false; - } - public AzItemRenderer getRenderer() { return itemRenderer; } From a18fc8c6e103e04673e14f454d3319cb82000d8b Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 02:22:56 -0500 Subject: [PATCH 141/224] Added AzEntityRendererConfig, fixed Marauder death rotation. Signed-off-by: = --- .../core2/render/AzEntityRendererConfig.java | 63 +++++++++++++++++++ .../core2/render/AzItemRendererConfig.java | 5 +- .../core2/render/AzRendererConfig.java | 14 +---- .../core2/render/entity/AzEntityRenderer.java | 10 +-- .../entity/AzEntityModelRenderer.java | 6 +- .../entity/AzEntityRendererPipeline.java | 14 ----- .../entities/marauder/MarauderRenderer.java | 8 ++- 7 files changed, 82 insertions(+), 38 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java new file mode 100644 index 000000000..8ead043b8 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java @@ -0,0 +1,63 @@ +package mod.azure.azurelib.core2.render; + +import net.minecraft.world.entity.Entity; + +import java.util.function.Function; + +public class AzEntityRendererConfig extends AzRendererConfig { + + private final Function deathMaxRotationProvider; + + private AzEntityRendererConfig( + float scaleHeight, + float scaleWidth, + Function deathMaxRotationProvider + ) { + super(scaleHeight, scaleWidth); + this.deathMaxRotationProvider = deathMaxRotationProvider; + } + + public float getDeathMaxRotation(T entity) { + return deathMaxRotationProvider.apply(entity); + } + + @SuppressWarnings("unchecked") + public static AzEntityRendererConfig defaultConfig() { + return (AzEntityRendererConfig) builder().build(); + } + + public static Builder builder() { + return new Builder<>(); + } + + public static class Builder extends AzRendererConfig.Builder { + + private Function deathMaxRotationProvider; + + protected Builder() { + super(); + this.deathMaxRotationProvider = $ -> 90F; + } + + /** + * Sets a provider for the max rotation value for dying entities.
      + * You might want to modify this for different aesthetics, such as a + * {@link net.minecraft.world.entity.monster.Spider} flipping upside down on death.
      + * Functionally equivalent to {@link net.minecraft.client.renderer.entity.LivingEntityRenderer#getFlipDegrees} + */ + public Builder setDeathMaxRotationProvider(Function deathMaxRotationProvider) { + this.deathMaxRotationProvider = deathMaxRotationProvider; + return this; + } + + public AzEntityRendererConfig build() { + var baseConfig = super.build(); + + return new AzEntityRendererConfig( + baseConfig.scaleHeight(), + baseConfig.scaleWidth(), + deathMaxRotationProvider + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java index 90b5333ae..6c2a9e319 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java @@ -50,10 +50,6 @@ public Builder useEntityGuiLighting() { return this; } - public boolean useNewOffset() { - return useNewOffset; - } - /** * @param useNewOffset Determines whether to apply the y offset for a model due to the change in BlockBench * 4.11. @@ -65,6 +61,7 @@ public AzRendererConfig.Builder useNewOffset(boolean useNewOffset) { public AzItemRendererConfig build() { var baseConfig = super.build(); + return new AzItemRendererConfig( baseConfig.scaleHeight(), baseConfig.scaleWidth(), diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java index d84ec35b6..f2c9cd0b2 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java @@ -19,14 +19,6 @@ public float scaleWidth() { return scaleWidth; } - public static AzRendererConfig defaultConfig() { - return builder().build(); - } - - public static Builder builder() { - return new Builder(); - } - public static class Builder { private float scaleHeight; @@ -38,11 +30,11 @@ protected Builder() { this.scaleWidth = 1; } - public Builder withScale(float scale) { - return withScale(scale, scale); + public Builder setScale(float scale) { + return setScale(scale, scale); } - public Builder withScale(float scaleWidth, float scaleHeight) { + public Builder setScale(float scaleWidth, float scaleHeight) { this.scaleHeight = scaleHeight; this.scaleWidth = scaleWidth; return this; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 0f26e9a88..881ea4eff 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -17,7 +17,7 @@ import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; -import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.AzEntityRendererConfig; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import mod.azure.azurelib.core2.render.pipeline.entity.AzEntityRendererPipeline; @@ -27,16 +27,16 @@ public abstract class AzEntityRenderer extends EntityRenderer< private final List> renderLayers; - private final AzRendererConfig config; + private final AzEntityRendererConfig config; @Nullable private AzEntityAnimator reusedAzEntityAnimator; protected AzEntityRenderer(EntityRendererProvider.Context context) { - this(AzRendererConfig.defaultConfig(), context); + this(AzEntityRendererConfig.defaultConfig(), context); } - protected AzEntityRenderer(AzRendererConfig config, EntityRendererProvider.Context context) { + protected AzEntityRenderer(AzEntityRendererConfig config, EntityRendererProvider.Context context) { super(context); this.config = config; this.rendererPipeline = new AzEntityRendererPipeline<>(this); @@ -154,7 +154,7 @@ public AzEntityAnimator getAnimator() { return reusedAzEntityAnimator; } - public AzRendererConfig config() { + public AzEntityRendererConfig config() { return config; } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java index 01a6ec2c9..b4d4ad661 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java @@ -229,7 +229,7 @@ protected void applyRotations( float partialTick, float nativeScale ) { - if (entityRendererPipeline.isShaking(animatable)) { + if (animatable.isFullyFrozen()) { rotationYaw += (float) (Math.cos(animatable.tickCount * 3.25d) * Math.PI * 0.4d); } @@ -238,8 +238,8 @@ protected void applyRotations( } if (animatable instanceof LivingEntity livingEntity) { - - var deathMaxRotation = entityRendererPipeline.getDeathMaxRotation(animatable); + var config = entityRendererPipeline.getRenderer().config(); + var deathMaxRotation = config.getDeathMaxRotation(animatable); if (livingEntity.deathTime > 0) { float deathRotation = (livingEntity.deathTime + partialTick - 1f) / 20f * 1.6f; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java index f240091b4..3eaece019 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java @@ -114,20 +114,6 @@ public void renderFinal(AzRendererPipelineContext context) { AzEntityLeashRenderUtil.renderLeash(entityRenderer, mob, partialTick, poseStack, bufferSource, leashHolder); } - /** - * Gets the max rotation value for dying entities.
      - * You might want to modify this for different aesthetics, such as a - * {@link net.minecraft.world.entity.monster.Spider} flipping upside down on death.
      - * Functionally equivalent to {@link net.minecraft.client.renderer.entity.LivingEntityRenderer#getFlipDegrees} - */ - protected float getDeathMaxRotation(T entity) { - return 90f; - } - - public boolean isShaking(T entity) { - return entity.isFullyFrozen(); - } - public AzEntityRenderer getRenderer() { return entityRenderer; } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java index df555215e..26397bb35 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java @@ -1,5 +1,6 @@ package mod.azure.azurelib.fabric.core2.example.entities.marauder; +import mod.azure.azurelib.core2.render.AzEntityRendererConfig; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; @@ -17,7 +18,12 @@ public class MarauderRenderer extends AzEntityRenderer { private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/marauder.png"); public MarauderRenderer(EntityRendererProvider.Context context) { - super(context); + super( + AzEntityRendererConfig.builder() + .setDeathMaxRotationProvider($ -> 0F) + .build(), + context + ); addRenderLayer(new AzAutoGlowingLayer<>()); } From 12834d471e9fcb77d0112c179f5575ef86b07fe6 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 03:00:48 -0500 Subject: [PATCH 142/224] Provide no-arg constructor for animators for convenience. Signed-off-by: = --- .../java/mod/azure/azurelib/core2/animation/AzAnimator.java | 4 ++++ .../azure/azurelib/core2/animation/impl/AzEntityAnimator.java | 4 ++++ .../azure/azurelib/core2/animation/impl/AzItemAnimator.java | 4 ++++ .../core2/example/entities/doomhunter/DoomHunterAnimator.java | 3 +-- .../fabric/core2/example/entities/drone/DroneAnimator.java | 3 +-- .../core2/example/entities/marauder/MarauderAnimator.java | 3 +-- .../core2/example/entities/marauder/MarauderRenderer.java | 2 +- 7 files changed, 16 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index 91c3f4330..47de3255c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -24,6 +24,10 @@ public abstract class AzAnimator { public boolean reloadAnimations; + protected AzAnimator() { + this(AzAnimatorConfig.defaultConfig()); + } + protected AzAnimator(AzAnimatorConfig config) { this.animationControllerContainer = new AzAnimationControllerContainer<>(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java index 5bfb91e1c..6d69aefab 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java @@ -13,6 +13,10 @@ public abstract class AzEntityAnimator extends AzAnimator { + protected AzEntityAnimator() { + super(); + } + protected AzEntityAnimator(AzAnimatorConfig config) { super(config); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java index 9765833b0..e8595ba59 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java @@ -7,6 +7,10 @@ public abstract class AzItemAnimator extends AzAnimator { + protected AzItemAnimator() { + super(); + } + protected AzItemAnimator(AzAnimatorConfig config) { super(config); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimator.java index b8445233f..87e536287 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimator.java @@ -4,7 +4,6 @@ import org.jetbrains.annotations.NotNull; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.AzAnimatorConfig; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; @@ -25,7 +24,7 @@ public class DoomHunterAnimator extends AzEntityAnimator { private static final AzRawAnimation MELEE_ANIMATION = AzRawAnimation.begin().thenLoop(MELEE_ANIMATION_NAME); public DoomHunterAnimator() { - super(AzAnimatorConfig.defaultConfig()); + super(); } @Override diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimator.java index bc4472418..7d3348535 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneAnimator.java @@ -4,7 +4,6 @@ import org.jetbrains.annotations.NotNull; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.AzAnimatorConfig; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; @@ -14,7 +13,7 @@ public class DroneAnimator extends AzEntityAnimator { private static final ResourceLocation ANIMATIONS = AzureLib.modResource("animations/entity/drone.animation.json"); public DroneAnimator() { - super(AzAnimatorConfig.defaultConfig()); + super(); } @Override diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java index c9c577b4f..34b62d952 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java @@ -6,7 +6,6 @@ import org.jetbrains.annotations.NotNull; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.AzAnimatorConfig; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyFrameCallbacks; @@ -48,7 +47,7 @@ public class MarauderAnimator extends AzEntityAnimator { .then(MELEE_ANIMATION_NAME, AzLoopType.PLAY_ONCE); public MarauderAnimator() { - super(AzAnimatorConfig.defaultConfig()); + super(); } @Override diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java index 26397bb35..fb326e749 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java @@ -1,6 +1,5 @@ package mod.azure.azurelib.fabric.core2.example.entities.marauder; -import mod.azure.azurelib.core2.render.AzEntityRendererConfig; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; @@ -8,6 +7,7 @@ import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.AzEntityRendererConfig; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; import mod.azure.azurelib.core2.render.layer.AzAutoGlowingLayer; From dcd95d6acaa81b0aa82ca76afb2bb397b3b0da4f Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 03:18:45 -0500 Subject: [PATCH 143/224] Move render layer additions to renderer config. Signed-off-by: = --- .../core2/render/AzEntityRendererConfig.java | 16 +++++-- .../core2/render/AzItemRendererConfig.java | 21 +++++++-- .../core2/render/AzRendererConfig.java | 43 ++++++++++++++++--- .../core2/render/entity/AzEntityRenderer.java | 25 +---------- .../core2/render/item/AzItemRenderer.java | 10 ++--- .../render/pipeline/AzRendererPipeline.java | 14 ++---- .../entity/AzEntityRendererPipeline.java | 18 +++----- .../pipeline/item/AzItemRendererPipeline.java | 18 +++----- .../entities/marauder/MarauderRenderer.java | 2 +- 9 files changed, 89 insertions(+), 78 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java index 8ead043b8..23cfda2e9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java @@ -2,18 +2,22 @@ import net.minecraft.world.entity.Entity; +import java.util.List; import java.util.function.Function; -public class AzEntityRendererConfig extends AzRendererConfig { +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +public class AzEntityRendererConfig extends AzRendererConfig { private final Function deathMaxRotationProvider; private AzEntityRendererConfig( + List> renderLayers, float scaleHeight, float scaleWidth, Function deathMaxRotationProvider ) { - super(scaleHeight, scaleWidth); + super(renderLayers, scaleHeight, scaleWidth); this.deathMaxRotationProvider = deathMaxRotationProvider; } @@ -30,7 +34,7 @@ public static Builder builder() { return new Builder<>(); } - public static class Builder extends AzRendererConfig.Builder { + public static class Builder extends AzRendererConfig.Builder { private Function deathMaxRotationProvider; @@ -39,6 +43,11 @@ protected Builder() { this.deathMaxRotationProvider = $ -> 90F; } + @Override + public Builder addRenderLayer(AzRenderLayer renderLayer) { + return (Builder) super.addRenderLayer(renderLayer); + } + /** * Sets a provider for the max rotation value for dying entities.
      * You might want to modify this for different aesthetics, such as a @@ -54,6 +63,7 @@ public AzEntityRendererConfig build() { var baseConfig = super.build(); return new AzEntityRendererConfig( + baseConfig.renderLayers(), baseConfig.scaleHeight(), baseConfig.scaleWidth(), deathMaxRotationProvider diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java index 6c2a9e319..bec24c1d9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java @@ -1,18 +1,25 @@ package mod.azure.azurelib.core2.render; -public class AzItemRendererConfig extends AzRendererConfig { +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +public class AzItemRendererConfig extends AzRendererConfig { private final boolean useEntityGuiLighting; private final boolean useNewOffset; private AzItemRendererConfig( + List> renderLayers, float scaleHeight, float scaleWidth, boolean useEntityGuiLighting, boolean useNewOffset ) { - super(scaleHeight, scaleWidth); + super(renderLayers, scaleHeight, scaleWidth); this.useEntityGuiLighting = useEntityGuiLighting; this.useNewOffset = useNewOffset; } @@ -33,7 +40,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder extends AzRendererConfig.Builder { + public static class Builder extends AzRendererConfig.Builder { private boolean useEntityGuiLighting; @@ -45,6 +52,11 @@ protected Builder() { this.useNewOffset = false; } + @Override + public Builder addRenderLayer(AzRenderLayer renderLayer) { + return (Builder) super.addRenderLayer(renderLayer); + } + public Builder useEntityGuiLighting() { this.useEntityGuiLighting = true; return this; @@ -54,7 +66,7 @@ public Builder useEntityGuiLighting() { * @param useNewOffset Determines whether to apply the y offset for a model due to the change in BlockBench * 4.11. */ - public AzRendererConfig.Builder useNewOffset(boolean useNewOffset) { + public AzRendererConfig.Builder useNewOffset(boolean useNewOffset) { this.useNewOffset = useNewOffset; return this; } @@ -63,6 +75,7 @@ public AzItemRendererConfig build() { var baseConfig = super.build(); return new AzItemRendererConfig( + baseConfig.renderLayers(), baseConfig.scaleHeight(), baseConfig.scaleWidth(), useEntityGuiLighting, diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java index f2c9cd0b2..46bc07ff7 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java @@ -1,16 +1,34 @@ package mod.azure.azurelib.core2.render; -public class AzRendererConfig { +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +import java.util.Collections; +import java.util.List; + +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +public class AzRendererConfig { + + private final List> renderLayers; private final float scaleHeight; private final float scaleWidth; - public AzRendererConfig(float scaleHeight, float scaleWidth) { + public AzRendererConfig( + List> renderLayers, + float scaleHeight, + float scaleWidth + ) { + this.renderLayers = Collections.unmodifiableList(renderLayers); this.scaleHeight = scaleHeight; this.scaleWidth = scaleWidth; } + public List> renderLayers() { + return renderLayers; + } + public float scaleHeight() { return scaleHeight; } @@ -19,29 +37,40 @@ public float scaleWidth() { return scaleWidth; } - public static class Builder { + public static class Builder { + + private final List> renderLayers; private float scaleHeight; private float scaleWidth; protected Builder() { + this.renderLayers = new ObjectArrayList<>(); this.scaleHeight = 1; this.scaleWidth = 1; } - public Builder setScale(float scale) { + /** + * Adds a {@link AzRenderLayer} to this config, to be called after the main model is rendered each frame + */ + public Builder addRenderLayer(AzRenderLayer renderLayer) { + this.renderLayers.add(renderLayer); + return this; + } + + public Builder setScale(float scale) { return setScale(scale, scale); } - public Builder setScale(float scaleWidth, float scaleHeight) { + public Builder setScale(float scaleWidth, float scaleHeight) { this.scaleHeight = scaleHeight; this.scaleWidth = scaleWidth; return this; } - public AzRendererConfig build() { - return new AzRendererConfig(scaleHeight, scaleWidth); + public AzRendererConfig build() { + return new AzRendererConfig<>(renderLayers, scaleHeight, scaleWidth); } } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 881ea4eff..1b92df889 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -1,7 +1,6 @@ package mod.azure.azurelib.core2.render.entity; import com.mojang.blaze3d.vertex.PoseStack; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererProvider; @@ -11,22 +10,17 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; - import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; import mod.azure.azurelib.core2.render.AzEntityRendererConfig; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import mod.azure.azurelib.core2.render.pipeline.entity.AzEntityRendererPipeline; public abstract class AzEntityRenderer extends EntityRenderer { private final AzEntityRendererPipeline rendererPipeline; - private final List> renderLayers; - private final AzEntityRendererConfig config; @Nullable @@ -39,8 +33,7 @@ protected AzEntityRenderer(EntityRendererProvider.Context context) { protected AzEntityRenderer(AzEntityRendererConfig config, EntityRendererProvider.Context context) { super(context); this.config = config; - this.rendererPipeline = new AzEntityRendererPipeline<>(this); - this.renderLayers = new ObjectArrayList<>(); + this.rendererPipeline = new AzEntityRendererPipeline<>(config, this); } protected abstract @NotNull ResourceLocation getModelLocation(T entity); @@ -119,22 +112,6 @@ public void render( return cachedEntityAnimator; } - /** - * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer - */ - public List> getRenderLayers() { - return this.renderLayers; - } - - /** - * Adds a {@link AzRenderLayer} to this renderer, to be called after the main model is rendered each frame - */ - public AzEntityRenderer addRenderLayer(AzRenderLayer renderLayer) { - this.renderLayers.add(renderLayer); - - return this; - } - /** * Whether the entity's nametag should be rendered or not.
      * Pretty much exclusively used in {@link EntityRenderer#renderNameTag} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java index c5180e185..7a9e8a6a6 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -45,19 +45,19 @@ protected AzItemRenderer() { protected AzItemRenderer(AzItemRendererConfig config) { this( + config, Minecraft.getInstance().getBlockEntityRenderDispatcher(), - Minecraft.getInstance().getEntityModels(), - config + Minecraft.getInstance().getEntityModels() ); } protected AzItemRenderer( + AzItemRendererConfig config, BlockEntityRenderDispatcher dispatcher, - EntityModelSet modelSet, - AzItemRendererConfig config + EntityModelSet modelSet ) { super(dispatcher, modelSet); - this.rendererPipeline = new AzItemRendererPipeline(this); + this.rendererPipeline = new AzItemRendererPipeline(config, this); this.renderLayers = new ObjectArrayList<>(); this.config = config; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index f81563d58..287de3efd 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -2,14 +2,13 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; +import mod.azure.azurelib.core2.render.AzRendererConfig; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; - import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; @@ -22,9 +21,9 @@ public abstract class AzRendererPipeline implements AzPhasedRenderer { private final AzModelRenderer modelRenderer; - protected AzRendererPipeline() { + protected AzRendererPipeline(AzRendererConfig config) { this.context = createContext(this); - this.layerRenderer = createLayerRenderer(); + this.layerRenderer = createLayerRenderer(config); this.modelRenderer = createModelRenderer(layerRenderer); } @@ -32,15 +31,10 @@ protected AzRendererPipeline() { protected abstract AzModelRenderer createModelRenderer(AzLayerRenderer layerRenderer); - protected abstract AzLayerRenderer createLayerRenderer(); + protected abstract AzLayerRenderer createLayerRenderer(AzRendererConfig config); public abstract @NotNull ResourceLocation getTextureLocation(@NotNull T animatable); - /** - * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer - */ - protected abstract List> getRenderLayers(); - /** * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this * GeoRenderer.
      diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java index 3eaece019..523137aa3 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java @@ -1,18 +1,17 @@ package mod.azure.azurelib.core2.render.pipeline.entity; import com.mojang.blaze3d.vertex.PoseStack; +import mod.azure.azurelib.core2.render.AzRendererConfig; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Mob; import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; -import java.util.List; - import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.render.AzEntityRendererConfig; import mod.azure.azurelib.core2.render.entity.AzEntityLeashRenderUtil; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; @@ -26,8 +25,8 @@ public class AzEntityRendererPipeline extends AzRendererPipeli protected Matrix4f modelRenderTranslations = new Matrix4f(); - public AzEntityRendererPipeline(AzEntityRenderer entityRenderer) { - super(); + public AzEntityRendererPipeline(AzEntityRendererConfig config, AzEntityRenderer entityRenderer) { + super(config); this.entityRenderer = entityRenderer; } @@ -42,8 +41,8 @@ protected AzModelRenderer createModelRenderer(AzLayerRenderer layerRendere } @Override - protected AzLayerRenderer createLayerRenderer() { - return new AzEntityLayerRenderer<>(this::getRenderLayers); + protected AzLayerRenderer createLayerRenderer(AzRendererConfig config) { + return new AzEntityLayerRenderer<>(config::renderLayers); } @Override @@ -51,11 +50,6 @@ protected AzLayerRenderer createLayerRenderer() { return entityRenderer.getTextureLocation(animatable); } - @Override - protected List> getRenderLayers() { - return entityRenderer.getRenderLayers(); - } - /** * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this * GeoRenderer.
      diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java index 5ffc8cd9e..043d1847c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java @@ -1,18 +1,17 @@ package mod.azure.azurelib.core2.render.pipeline.item; import com.mojang.blaze3d.vertex.PoseStack; +import mod.azure.azurelib.core2.render.AzRendererConfig; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; -import java.util.List; - import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.render.AzItemRendererConfig; import mod.azure.azurelib.core2.render.item.AzItemRenderer; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; @@ -25,8 +24,8 @@ public class AzItemRendererPipeline extends AzRendererPipeline { protected Matrix4f modelRenderTranslations = new Matrix4f(); - public AzItemRendererPipeline(AzItemRenderer itemRenderer) { - super(); + public AzItemRendererPipeline(AzItemRendererConfig config, AzItemRenderer itemRenderer) { + super(config); this.itemRenderer = itemRenderer; } @@ -41,8 +40,8 @@ protected AzItemModelRenderer createModelRenderer(AzLayerRenderer lay } @Override - protected AzLayerRenderer createLayerRenderer() { - return new AzLayerRenderer<>(this::getRenderLayers); + protected AzLayerRenderer createLayerRenderer(AzRendererConfig config) { + return new AzLayerRenderer<>(config::renderLayers); } @Override @@ -50,11 +49,6 @@ protected AzLayerRenderer createLayerRenderer() { return itemRenderer.getTextureLocation(animatable); } - @Override - protected List> getRenderLayers() { - return itemRenderer.getRenderLayers(); - } - /** * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling * and translating.
      diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java index fb326e749..ae72cb4c6 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java @@ -20,11 +20,11 @@ public class MarauderRenderer extends AzEntityRenderer { public MarauderRenderer(EntityRendererProvider.Context context) { super( AzEntityRendererConfig.builder() + .addRenderLayer(new AzAutoGlowingLayer<>()) .setDeathMaxRotationProvider($ -> 0F) .build(), context ); - addRenderLayer(new AzAutoGlowingLayer<>()); } @Override From a8972813a97acff4c49859a3da2ee1b15cf7eaa7 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 03:19:52 -0500 Subject: [PATCH 144/224] Lint, provide setDeathMaxRotation overload. Signed-off-by: = --- .../azurelib/core2/render/AzEntityRendererConfig.java | 7 ++++++- .../azurelib/core2/render/pipeline/AzRendererPipeline.java | 2 +- .../render/pipeline/entity/AzEntityRendererPipeline.java | 2 +- .../core2/render/pipeline/item/AzItemRendererPipeline.java | 2 +- .../core2/example/entities/marauder/MarauderRenderer.java | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java index 23cfda2e9..2b3e83ea1 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java @@ -48,13 +48,18 @@ public Builder addRenderLayer(AzRenderLayer renderLayer) { return (Builder) super.addRenderLayer(renderLayer); } + public Builder setDeathMaxRotation(float angle) { + this.deathMaxRotationProvider = $ -> angle; + return this; + } + /** * Sets a provider for the max rotation value for dying entities.
      * You might want to modify this for different aesthetics, such as a * {@link net.minecraft.world.entity.monster.Spider} flipping upside down on death.
      * Functionally equivalent to {@link net.minecraft.client.renderer.entity.LivingEntityRenderer#getFlipDegrees} */ - public Builder setDeathMaxRotationProvider(Function deathMaxRotationProvider) { + public Builder setDeathMaxRotation(Function deathMaxRotationProvider) { this.deathMaxRotationProvider = deathMaxRotationProvider; return this; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index 287de3efd..485d88876 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -2,7 +2,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.core2.render.AzRendererConfig; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; @@ -11,6 +10,7 @@ import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.render.AzRendererConfig; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; public abstract class AzRendererPipeline implements AzPhasedRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java index 523137aa3..316e28767 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java @@ -1,7 +1,6 @@ package mod.azure.azurelib.core2.render.pipeline.entity; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.core2.render.AzRendererConfig; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Mob; @@ -10,6 +9,7 @@ import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; import mod.azure.azurelib.core2.render.AzEntityRendererConfig; +import mod.azure.azurelib.core2.render.AzRendererConfig; import mod.azure.azurelib.core2.render.entity.AzEntityLeashRenderUtil; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java index 043d1847c..47befcd0f 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java @@ -1,7 +1,6 @@ package mod.azure.azurelib.core2.render.pipeline.item; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.core2.render.AzRendererConfig; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -11,6 +10,7 @@ import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; import mod.azure.azurelib.core2.render.AzItemRendererConfig; +import mod.azure.azurelib.core2.render.AzRendererConfig; import mod.azure.azurelib.core2.render.item.AzItemRenderer; import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java index ae72cb4c6..c86249c72 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java @@ -21,7 +21,7 @@ public MarauderRenderer(EntityRendererProvider.Context context) { super( AzEntityRendererConfig.builder() .addRenderLayer(new AzAutoGlowingLayer<>()) - .setDeathMaxRotationProvider($ -> 0F) + .setDeathMaxRotation(0F) .build(), context ); From fc18d449e6474713af4e36d38077770a02661c8f Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 03:58:53 -0500 Subject: [PATCH 145/224] More config work. Signed-off-by: = --- .../core2/render/AzEntityRendererConfig.java | 49 +++++++++++----- .../core2/render/AzItemRendererConfig.java | 39 ++++++++++--- .../core2/render/AzRendererConfig.java | 57 ++++++++++++++++++- .../core2/render/entity/AzEntityRenderer.java | 19 +++---- .../core2/render/item/AzItemRenderer.java | 21 ++----- .../render/layer/AzAutoGlowingLayer.java | 2 +- .../render/pipeline/AzRendererPipeline.java | 11 ++-- .../pipeline/AzRendererPipelineContext.java | 2 +- .../entity/AzEntityRendererPipeline.java | 8 +-- .../pipeline/item/AzItemRendererPipeline.java | 8 +-- .../doomhunter/DoomHunterRenderer.java | 26 +++------ .../example/entities/drone/DroneRenderer.java | 24 ++------ .../entities/marauder/MarauderRenderer.java | 21 +------ .../core2/example/items/AzPistolRenderer.java | 22 ++----- 14 files changed, 164 insertions(+), 145 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java index 2b3e83ea1..b143917a7 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java @@ -1,10 +1,14 @@ package mod.azure.azurelib.core2.render; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.Function; +import java.util.function.Supplier; +import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; public class AzEntityRendererConfig extends AzRendererConfig { @@ -12,12 +16,15 @@ public class AzEntityRendererConfig extends AzRendererConfig deathMaxRotationProvider; private AzEntityRendererConfig( + Supplier> animatorProvider, + Function deathMaxRotationProvider, + Function modelLocationProvider, List> renderLayers, + Function textureLocationProvider, float scaleHeight, - float scaleWidth, - Function deathMaxRotationProvider + float scaleWidth ) { - super(renderLayers, scaleHeight, scaleWidth); + super(animatorProvider, modelLocationProvider, renderLayers, textureLocationProvider, scaleHeight, scaleWidth); this.deathMaxRotationProvider = deathMaxRotationProvider; } @@ -25,21 +32,29 @@ public float getDeathMaxRotation(T entity) { return deathMaxRotationProvider.apply(entity); } - @SuppressWarnings("unchecked") - public static AzEntityRendererConfig defaultConfig() { - return (AzEntityRendererConfig) builder().build(); + public static Builder builder( + ResourceLocation modelLocation, + ResourceLocation textureLocation + ) { + return new Builder<>($ -> modelLocation, $ -> textureLocation); } - public static Builder builder() { - return new Builder<>(); + public static Builder builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + return new Builder<>(modelLocationProvider, textureLocationProvider); } public static class Builder extends AzRendererConfig.Builder { private Function deathMaxRotationProvider; - protected Builder() { - super(); + protected Builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + super(modelLocationProvider, textureLocationProvider); this.deathMaxRotationProvider = $ -> 90F; } @@ -48,6 +63,11 @@ public Builder addRenderLayer(AzRenderLayer renderLayer) { return (Builder) super.addRenderLayer(renderLayer); } + @Override + public Builder setAnimatorProvider(Supplier<@Nullable AzAnimator> animatorProvider) { + return (Builder) super.setAnimatorProvider(animatorProvider); + } + public Builder setDeathMaxRotation(float angle) { this.deathMaxRotationProvider = $ -> angle; return this; @@ -67,11 +87,14 @@ public Builder setDeathMaxRotation(Function deathMaxRotationProvide public AzEntityRendererConfig build() { var baseConfig = super.build(); - return new AzEntityRendererConfig( + return new AzEntityRendererConfig<>( + baseConfig::createAnimator, + deathMaxRotationProvider, + baseConfig::modelLocation, baseConfig.renderLayers(), + baseConfig::textureLocation, baseConfig.scaleHeight(), - baseConfig.scaleWidth(), - deathMaxRotationProvider + baseConfig.scaleWidth() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java index bec24c1d9..55c507bcf 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java @@ -1,9 +1,14 @@ package mod.azure.azurelib.core2.render; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; +import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; public class AzItemRendererConfig extends AzRendererConfig { @@ -13,13 +18,16 @@ public class AzItemRendererConfig extends AzRendererConfig { private final boolean useNewOffset; private AzItemRendererConfig( + Supplier> animatorProvider, + Function modelLocationProvider, List> renderLayers, + Function textureLocationProvider, float scaleHeight, float scaleWidth, boolean useEntityGuiLighting, boolean useNewOffset ) { - super(renderLayers, scaleHeight, scaleWidth); + super(animatorProvider, modelLocationProvider, renderLayers, textureLocationProvider, scaleHeight, scaleWidth); this.useEntityGuiLighting = useEntityGuiLighting; this.useNewOffset = useNewOffset; } @@ -32,12 +40,18 @@ public boolean useNewOffset() { return useNewOffset; } - public static AzItemRendererConfig defaultConfig() { - return builder().build(); + public static Builder builder( + ResourceLocation modelLocation, + ResourceLocation textureLocation + ) { + return new Builder($ -> modelLocation, $ -> textureLocation); } - public static Builder builder() { - return new Builder(); + public static Builder builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + return new Builder(modelLocationProvider, textureLocationProvider); } public static class Builder extends AzRendererConfig.Builder { @@ -46,8 +60,11 @@ public static class Builder extends AzRendererConfig.Builder { private boolean useNewOffset; - protected Builder() { - super(); + protected Builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + super(modelLocationProvider, textureLocationProvider); this.useEntityGuiLighting = false; this.useNewOffset = false; } @@ -57,6 +74,11 @@ public Builder addRenderLayer(AzRenderLayer renderLayer) { return (Builder) super.addRenderLayer(renderLayer); } + @Override + public Builder setAnimatorProvider(Supplier<@Nullable AzAnimator> animatorProvider) { + return (Builder) super.setAnimatorProvider(animatorProvider); + } + public Builder useEntityGuiLighting() { this.useEntityGuiLighting = true; return this; @@ -75,7 +97,10 @@ public AzItemRendererConfig build() { var baseConfig = super.build(); return new AzItemRendererConfig( + baseConfig::createAnimator, + baseConfig::modelLocation, baseConfig.renderLayers(), + baseConfig::textureLocation, baseConfig.scaleHeight(), baseConfig.scaleWidth(), useEntityGuiLighting, diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java index 46bc07ff7..05ac85f37 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java @@ -1,30 +1,59 @@ package mod.azure.azurelib.core2.render; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; import java.util.Collections; import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; +import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; public class AzRendererConfig { + private final Supplier<@Nullable AzAnimator> animatorProvider; + + private final Function modelLocationProvider; + private final List> renderLayers; + private final Function textureLocationProvider; + private final float scaleHeight; private final float scaleWidth; public AzRendererConfig( + Supplier> animatorProvider, + Function modelLocationProvider, List> renderLayers, + Function textureLocationProvider, float scaleHeight, float scaleWidth ) { + this.animatorProvider = animatorProvider; + this.modelLocationProvider = modelLocationProvider; this.renderLayers = Collections.unmodifiableList(renderLayers); + this.textureLocationProvider = textureLocationProvider; this.scaleHeight = scaleHeight; this.scaleWidth = scaleWidth; } + public @Nullable AzAnimator createAnimator() { + return animatorProvider.get(); + } + + public ResourceLocation modelLocation(T animatable) { + return modelLocationProvider.apply(animatable); + } + + public ResourceLocation textureLocation(T animatable) { + return textureLocationProvider.apply(animatable); + } + public List> renderLayers() { return renderLayers; } @@ -39,18 +68,35 @@ public float scaleWidth() { public static class Builder { + private final Function modelLocationProvider; + private final List> renderLayers; + private final Function textureLocationProvider; + + private Supplier<@Nullable AzAnimator> animatorProvider; + private float scaleHeight; private float scaleWidth; - protected Builder() { + protected Builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + this.animatorProvider = () -> null; + this.modelLocationProvider = modelLocationProvider; this.renderLayers = new ObjectArrayList<>(); + this.textureLocationProvider = textureLocationProvider; this.scaleHeight = 1; this.scaleWidth = 1; } + public Builder setAnimatorProvider(Supplier<@Nullable AzAnimator> animatorProvider) { + this.animatorProvider = animatorProvider; + return this; + } + /** * Adds a {@link AzRenderLayer} to this config, to be called after the main model is rendered each frame */ @@ -70,7 +116,14 @@ public Builder setScale(float scaleWidth, float scaleHeight) { } public AzRendererConfig build() { - return new AzRendererConfig<>(renderLayers, scaleHeight, scaleWidth); + return new AzRendererConfig<>( + animatorProvider, + modelLocationProvider, + renderLayers, + textureLocationProvider, + scaleHeight, + scaleWidth + ); } } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 1b92df889..a882f8983 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -26,17 +26,16 @@ public abstract class AzEntityRenderer extends EntityRenderer< @Nullable private AzEntityAnimator reusedAzEntityAnimator; - protected AzEntityRenderer(EntityRendererProvider.Context context) { - this(AzEntityRendererConfig.defaultConfig(), context); - } - protected AzEntityRenderer(AzEntityRendererConfig config, EntityRendererProvider.Context context) { super(context); this.config = config; this.rendererPipeline = new AzEntityRendererPipeline<>(config, this); } - protected abstract @NotNull ResourceLocation getModelLocation(T entity); + @Override + public final @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { + return config.textureLocation(animatable); + } public void superRender( @NotNull T entity, @@ -82,16 +81,12 @@ public void render( ); } - protected @Nullable AzEntityAnimator createAnimator() { - return null; - } - protected @Nullable AzBakedModel provideBakedModel(@NotNull T entity) { - var modelResourceLocation = getModelLocation(entity); + var modelResourceLocation = config.modelLocation(entity); return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); } - protected @Nullable AzEntityAnimator provideAnimator(T entity) { + private @Nullable AzEntityAnimator provideAnimator(T entity) { // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for the // entity. var accessor = AzAnimatorAccessor.cast(entity); @@ -99,7 +94,7 @@ public void render( if (cachedEntityAnimator == null) { // If the cached animator is null, create a new one. We use a separate reference here just for some - cachedEntityAnimator = createAnimator(); + cachedEntityAnimator = (AzEntityAnimator) config.createAnimator(); if (cachedEntityAnimator != null) { // If the new animator we created is not null, then register its controllers. diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java index 7a9e8a6a6..66c0988d9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -12,7 +12,6 @@ import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; @@ -39,10 +38,6 @@ public abstract class AzItemRenderer extends BlockEntityWithoutLevelRenderer { @Nullable private AzItemAnimator reusedAzItemAnimator; - protected AzItemRenderer() { - this(AzItemRendererConfig.defaultConfig()); - } - protected AzItemRenderer(AzItemRendererConfig config) { this( config, @@ -62,10 +57,6 @@ protected AzItemRenderer( this.config = config; } - protected abstract @NotNull ResourceLocation getModelLocation(ItemStack item); - - public abstract @NotNull ResourceLocation getTextureLocation(ItemStack item); - @Override public void renderByItem( ItemStack stack, @@ -105,7 +96,7 @@ public void renderByItem( var renderType = rendererPipeline.getContext() .getDefaultRenderType( animatable, - getTextureLocation(animatable), + config.textureLocation(animatable), bufferSource, Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() ); @@ -158,7 +149,7 @@ protected void renderInGui( RenderType renderType = rendererPipeline.getContext() .getDefaultRenderType( animatable, - getTextureLocation(animatable), + config.textureLocation(animatable), defaultBufferSource, Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() ); @@ -187,12 +178,8 @@ protected void renderInGui( poseStack.popPose(); } - protected @Nullable AzItemAnimator createAnimator() { - return null; - } - protected @Nullable AzBakedModel provideBakedModel(@NotNull ItemStack item) { - var modelResourceLocation = getModelLocation(item); + var modelResourceLocation = config.modelLocation(item); return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); } @@ -204,7 +191,7 @@ protected void renderInGui( if (cachedItemAnimator == null) { // If the cached animator is null, create a new one. We use a separate reference here just for some - cachedItemAnimator = createAnimator(); + cachedItemAnimator = (AzItemAnimator) config.createAnimator(); if (cachedItemAnimator != null) { // If the new animator we created is not null, then register its controllers. diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java index 26bec5ef6..595f81de4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java @@ -29,7 +29,7 @@ public void preRender(AzRendererPipelineContext context) {} public void render(AzRendererPipelineContext context) { var animatable = context.animatable(); var renderPipeline = context.rendererPipeline(); - var textureLocation = renderPipeline.getTextureLocation(animatable); + var textureLocation = renderPipeline.config().textureLocation(animatable); var renderType = AutoGlowingTexture.getRenderType(textureLocation); if (context.renderType() != null) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index 485d88876..2adf70740 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -4,8 +4,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; @@ -15,6 +13,8 @@ public abstract class AzRendererPipeline implements AzPhasedRenderer { + protected final AzRendererConfig config; + private final AzRendererPipelineContext context; private final AzLayerRenderer layerRenderer; @@ -22,6 +22,7 @@ public abstract class AzRendererPipeline implements AzPhasedRenderer { private final AzModelRenderer modelRenderer; protected AzRendererPipeline(AzRendererConfig config) { + this.config = config; this.context = createContext(this); this.layerRenderer = createLayerRenderer(config); this.modelRenderer = createModelRenderer(layerRenderer); @@ -33,8 +34,6 @@ protected AzRendererPipeline(AzRendererConfig config) { protected abstract AzLayerRenderer createLayerRenderer(AzRendererConfig config); - public abstract @NotNull ResourceLocation getTextureLocation(@NotNull T animatable); - /** * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this * GeoRenderer.
      @@ -131,6 +130,10 @@ protected void scaleModelForRender( } } + public AzRendererConfig config() { + return config; + } + public AzRendererPipelineContext getContext() { return context; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java index 6dd41352c..4ccb00659 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java @@ -64,7 +64,7 @@ public void populate( this.renderColor = getRenderColor(animatable, partialTick, packedLight).argbInt(); if (renderType == null) { - var textureLocation = rendererPipeline.getTextureLocation(animatable); + var textureLocation = rendererPipeline.config().textureLocation(animatable); this.renderType = getDefaultRenderType(animatable, textureLocation, multiBufferSource, partialTick); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java index 316e28767..3fd382042 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java @@ -4,7 +4,6 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Mob; -import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; @@ -45,11 +44,6 @@ protected AzLayerRenderer createLayerRenderer(AzRendererConfig config) { return new AzEntityLayerRenderer<>(config::renderLayers); } - @Override - public @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { - return entityRenderer.getTextureLocation(animatable); - } - /** * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this * GeoRenderer.
      @@ -60,7 +54,7 @@ protected AzLayerRenderer createLayerRenderer(AzRendererConfig config) { @Override public void updateAnimatedTextureFrame(T entity) { AnimatableTexture.setAndUpdate( - getTextureLocation(entity), + config.textureLocation(entity), entity.getId() + entity.tickCount ); } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java index 47befcd0f..17bdc13f9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java @@ -4,7 +4,6 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; import mod.azure.azurelib.common.internal.client.util.RenderUtils; @@ -44,11 +43,6 @@ protected AzLayerRenderer createLayerRenderer(AzRendererConfig(config::renderLayers); } - @Override - public @NotNull ResourceLocation getTextureLocation(@NotNull ItemStack animatable) { - return itemRenderer.getTextureLocation(animatable); - } - /** * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling * and translating.
      @@ -83,7 +77,7 @@ public void postRender(AzRendererPipelineContext context, boolean isR @Override public void updateAnimatedTextureFrame(ItemStack animatable) { AnimatableTexture.setAndUpdate( - getTextureLocation(animatable), + config.textureLocation(animatable), Item.getId(animatable.getItem()) + (int) RenderUtils.getCurrentTick() ); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java index 795ca7acc..26e2b75e9 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java @@ -2,11 +2,9 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.AzEntityRendererConfig; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; public class DoomHunterRenderer extends AzEntityRenderer { @@ -16,21 +14,11 @@ public class DoomHunterRenderer extends AzEntityRenderer { private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/doomhunter.png"); public DoomHunterRenderer(EntityRendererProvider.Context context) { - super(context); - } - - @Override - protected @Nullable AzEntityAnimator createAnimator() { - return new DoomHunterAnimator(); - } - - @Override - protected @NotNull ResourceLocation getModelLocation(DoomHunter doomHunter) { - return MODEL; - } - - @Override - public @NotNull ResourceLocation getTextureLocation(@NotNull DoomHunter doomHunter) { - return TEXTURE; + super( + AzEntityRendererConfig.builder(MODEL, TEXTURE) + .setAnimatorProvider(DoomHunterAnimator::new) + .build(), + context + ); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneRenderer.java index 9fbc83b36..272590163 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneRenderer.java @@ -2,11 +2,9 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.AzEntityRendererConfig; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; public class DroneRenderer extends AzEntityRenderer { @@ -16,21 +14,9 @@ public class DroneRenderer extends AzEntityRenderer { private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/drone.png"); public DroneRenderer(EntityRendererProvider.Context context) { - super(context); - } - - @Override - protected @Nullable AzEntityAnimator createAnimator() { - return new DroneAnimator(); - } - - @Override - protected @NotNull ResourceLocation getModelLocation(Drone drone) { - return MODEL; - } - - @Override - public @NotNull ResourceLocation getTextureLocation(@NotNull Drone drone) { - return TEXTURE; + super( + AzEntityRendererConfig.builder(MODEL, TEXTURE).setAnimatorProvider(DroneAnimator::new).build(), + context + ); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java index c86249c72..33f6b5461 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java @@ -2,11 +2,8 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.render.AzEntityRendererConfig; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; import mod.azure.azurelib.core2.render.layer.AzAutoGlowingLayer; @@ -19,26 +16,12 @@ public class MarauderRenderer extends AzEntityRenderer { public MarauderRenderer(EntityRendererProvider.Context context) { super( - AzEntityRendererConfig.builder() + AzEntityRendererConfig.builder(MODEL, TEXTURE) .addRenderLayer(new AzAutoGlowingLayer<>()) + .setAnimatorProvider(MarauderAnimator::new) .setDeathMaxRotation(0F) .build(), context ); } - - @Override - protected @Nullable AzEntityAnimator createAnimator() { - return new MarauderAnimator(); - } - - @Override - protected @NotNull ResourceLocation getModelLocation(MarauderEntity drone) { - return MODEL; - } - - @Override - public @NotNull ResourceLocation getTextureLocation(@NotNull MarauderEntity drone) { - return TEXTURE; - } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java index dac7a95cc..8e3242398 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java @@ -1,12 +1,9 @@ package mod.azure.azurelib.fabric.core2.example.items; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; +import mod.azure.azurelib.core2.render.AzItemRendererConfig; import mod.azure.azurelib.core2.render.item.AzItemRenderer; public class AzPistolRenderer extends AzItemRenderer { @@ -15,18 +12,9 @@ public class AzPistolRenderer extends AzItemRenderer { private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/item/pistol.png"); - @Override - protected @Nullable AzItemAnimator createAnimator() { - return new AzPistolAnimator(); - } - - @Override - protected @NotNull ResourceLocation getModelLocation(ItemStack item) { - return MODEL; - } - - @Override - public @NotNull ResourceLocation getTextureLocation(ItemStack item) { - return TEXTURE; + public AzPistolRenderer() { + super( + AzItemRendererConfig.builder(MODEL, TEXTURE).setAnimatorProvider(AzPistolAnimator::new).build() + ); } } From 59623c691f6fa27df50d5c436304ff90e02d5a8f Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 03:59:23 -0500 Subject: [PATCH 146/224] getContext() -> context(). Signed-off-by: = --- .../mod/azure/azurelib/core2/render/item/AzItemRenderer.java | 4 ++-- .../azurelib/core2/render/pipeline/AzRendererPipeline.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java index 66c0988d9..c64a8c574 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -93,7 +93,7 @@ public void renderByItem( packedOverlay ); } else { - var renderType = rendererPipeline.getContext() + var renderType = rendererPipeline.context() .getDefaultRenderType( animatable, config.textureLocation(animatable), @@ -146,7 +146,7 @@ protected void renderInGui( bufferSource instanceof MultiBufferSource.BufferSource bufferSource2 ? bufferSource2 : Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); - RenderType renderType = rendererPipeline.getContext() + RenderType renderType = rendererPipeline.context() .getDefaultRenderType( animatable, config.textureLocation(animatable), diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java index 2adf70740..fcbeb2af7 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java @@ -134,7 +134,7 @@ public AzRendererConfig config() { return config; } - public AzRendererPipelineContext getContext() { + public AzRendererPipelineContext context() { return context; } } From 2a72b5b02618eccb526e2b0c69f95415f1e99f13 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Fri, 20 Dec 2024 09:31:08 -0500 Subject: [PATCH 147/224] We got blocks! --- .../AzBlockEntityDispatchCommandPacket.java | 52 +++++ ...ntityMixin_AzBlockEntityAnimatorCache.java | 26 +++ .../platform/services/AzureLibNetwork.java | 4 + .../dispatch/AzDispatchExecutor.java | 29 +++ .../core2/animation/impl/AzBlockAnimator.java | 12 ++ .../core2/render/block/AzBlockRenderer.java | 144 +++++++++++++ .../impl/AzBlockEntityRendererPipeline.java | 197 ++++++++++++++++++ .../AzBlockEntityRendererPipelineContext.java | 27 +++ .../azure/azurelib/fabric/ClientListener.java | 4 + .../azurelib/fabric/FabricAzureLibMod.java | 12 +- .../fabric/core2/example/blocks/Stargate.java | 12 ++ .../blocks/StargateAnimationDispatcher.java | 20 ++ .../example/blocks/StargateBlockEntity.java | 28 +-- .../blocks/StargateBlockEntityAnimator.java | 39 ++++ .../core2/example/blocks/StargateRender.java | 33 ++- .../resources/azurelib.fabric.mixins.json | 1 + .../neoforge/NeoForgeAzureLibMod.java | 5 + .../main/resources/azurelib.neo.mixins.json | 1 + 18 files changed, 613 insertions(+), 33 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzBlockEntityDispatchCommandPacket.java create mode 100644 common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzBlockAnimator.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzBlockEntityRendererPipeline.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzBlockEntityRendererPipelineContext.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateAnimationDispatcher.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntityAnimator.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzBlockEntityDispatchCommandPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzBlockEntityDispatchCommandPacket.java new file mode 100644 index 000000000..a4baddcd0 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzBlockEntityDispatchCommandPacket.java @@ -0,0 +1,52 @@ +package mod.azure.azurelib.common.internal.common.network.packet; + +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; + +public record AzBlockEntityDispatchCommandPacket( + BlockPos blockPos, + AzDispatchCommand dispatchCommand, + AzDispatchSide origin) implements AbstractPacket { + + public static final CustomPacketPayload.Type TYPE = new Type<>( + AzureLibNetwork.AZ_BLOCKENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID + ); + + public static final StreamCodec CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, + AzBlockEntityDispatchCommandPacket::blockPos, + AzDispatchCommand.CODEC, + AzBlockEntityDispatchCommandPacket::dispatchCommand, + AzDispatchSide.CODEC, + AzBlockEntityDispatchCommandPacket::origin, + AzBlockEntityDispatchCommandPacket::new + ); + + @Override + public void handle() { + var blockEntity = ClientUtils.getLevel().getBlockEntity(blockPos); + + if (blockEntity == null) { + return; + } + + var animator = AzAnimatorAccessor.getOrNull(blockEntity); + + if (animator != null) { + dispatchCommand.getActions().forEach(action -> action.handle(animator)); + } + } + + @Override + public Type type() { + return TYPE; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java new file mode 100644 index 000000000..315b64c14 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java @@ -0,0 +1,26 @@ +package mod.azure.azurelib.common.internal.mixins; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(BlockEntity.class) +public abstract class BlockEntityMixin_AzBlockEntityAnimatorCache implements AzAnimatorAccessor { + + @Unique + @Nullable + private AzAnimator animator; + + @Override + public void setAnimator(@Nullable AzAnimator animator) { + this.animator = animator; + } + + @Override + public @Nullable AzAnimator getAnimatorOrNull() { + return animator; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java index 9b65ab8fb..97c71903e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java @@ -24,6 +24,10 @@ public interface AzureLibNetwork { ResourceLocation ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("anim_trigger_sync"); + ResourceLocation AZ_BLOCKENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID = AzureLib.modResource( + "az_blockentity_dispatch_command_sync" + ); + ResourceLocation AZ_ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("az_entity_anim_trigger_sync"); ResourceLocation AZ_ENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID = AzureLib.modResource( diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java index 75da05d8f..dad1006fd 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java @@ -1,6 +1,8 @@ package mod.azure.azurelib.core2.animation.dispatch; +import mod.azure.azurelib.common.internal.common.network.packet.AzBlockEntityDispatchCommandPacket; import net.minecraft.core.component.PatchedDataComponentMap; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; @@ -13,6 +15,7 @@ import mod.azure.azurelib.common.platform.Services; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; +import net.minecraft.world.level.block.entity.BlockEntity; public record AzDispatchExecutor( List commands, @@ -31,6 +34,18 @@ public void sendForEntity(Entity entity) { } } + public void sendForBlockEntity(BlockEntity entity) { + if (!canNotProceed(entity)) { + // TODO: Log here. + return; + } + + switch (origin) { + case CLIENT -> dispatchFromClient(entity); + case SERVER -> handleServerDispatchForBlockEntity(entity); + } + } + public void sendForItem(Entity entity, ItemStack itemStack) { if (!canNotProceed(entity)) { // TODO: Log here. @@ -77,6 +92,16 @@ private void handleServerDispatchForEntity(Entity entity) { }); } + private void handleServerDispatchForBlockEntity(BlockEntity entity) { + var entityBlockPos = entity.getBlockPos(); + + commands.forEach(command -> { + // TODO: Buffer commands together. + var packet = new AzBlockEntityDispatchCommandPacket(entityBlockPos, command, origin); + Services.NETWORK.sendToEntitiesTrackingChunk(packet, (ServerLevel) entity.getLevel(), entityBlockPos); + }); + } + private void handleServerDispatchForItem(Entity entity, ItemStack itemStack) { var uuid = itemStack.get(AzureLib.AZ_ID.get()); commands.forEach(command -> { @@ -91,6 +116,10 @@ private boolean isClientSide(T animatable) { return entity.level().isClientSide(); } + if (animatable instanceof BlockEntity entity) { + return entity.getLevel().isClientSide(); + } + throw new IllegalArgumentException("Unhandled animatable type: " + animatable); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzBlockAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzBlockAnimator.java new file mode 100644 index 000000000..1320dd599 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzBlockAnimator.java @@ -0,0 +1,12 @@ +package mod.azure.azurelib.core2.animation.impl; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; +import net.minecraft.world.level.block.entity.BlockEntity; + +public abstract class AzBlockAnimator extends AzAnimator { + + protected AzBlockAnimator(AzAnimatorConfig config) { + super(config); + } +} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java new file mode 100644 index 000000000..04ffc3cfa --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java @@ -0,0 +1,144 @@ +package mod.azure.azurelib.core2.render.block; + +import com.mojang.blaze3d.vertex.PoseStack; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.impl.AzBlockAnimator; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import mod.azure.azurelib.core2.render.pipeline.impl.AzBlockEntityRendererPipeline; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public abstract class AzBlockRenderer implements BlockEntityRenderer { + + private final AzBlockEntityRendererPipeline rendererPipeline; + + private final List> renderLayers; + + private float scaleWidth = 1; + + private float scaleHeight = 1; + + @Nullable + private AzBlockAnimator reusedAzBlockAnimator; + + protected AzBlockRenderer() { + super(); + this.rendererPipeline = new AzBlockEntityRendererPipeline<>(this); + this.renderLayers = new ObjectArrayList<>(); + } + + protected abstract @NotNull ResourceLocation getModelLocation(T entity); + + public abstract @NotNull ResourceLocation getTextureLocation(T entity); + + @Override + public void render(@NotNull T entity, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource multiBufferSource, int packedLight, int packedOverlay) { + + var cachedEntityAnimator = provideAnimator(entity); + var azBakedModel = provideBakedModel(entity); + + if (cachedEntityAnimator != null && azBakedModel != null) { + cachedEntityAnimator.setActiveModel(azBakedModel); + } + + // Point the renderer's current animator reference to the cached entity animator before rendering. + reusedAzBlockAnimator = cachedEntityAnimator; + + // Execute the render pipeline. + rendererPipeline.render( + poseStack, + azBakedModel, + entity, + multiBufferSource, + null, + null, + 0, + partialTick, + packedLight + ); + } + + protected @Nullable AzBlockAnimator createAnimator() { + return null; + } + + protected @Nullable AzBakedModel provideBakedModel(@NotNull T entity) { + var modelResourceLocation = getModelLocation(entity); + return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); + } + + protected @Nullable AzBlockAnimator provideAnimator(T entity) { + // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for the + // entity. + var accessor = AzAnimatorAccessor.cast(entity); + var cachedBlockEntityAnimator = (AzBlockAnimator) accessor.getAnimatorOrNull(); + + if (cachedBlockEntityAnimator == null) { + // If the cached animator is null, create a new one. We use a separate reference here just for some + cachedBlockEntityAnimator = createAnimator(); + + if (cachedBlockEntityAnimator != null) { + // If the new animator we created is not null, then register its controllers. + cachedBlockEntityAnimator.registerControllers(cachedBlockEntityAnimator.getAnimationControllerContainer()); + // Also cache the animator so that the next time we fetch the animator, it's ready for us. + accessor.setAnimator(cachedBlockEntityAnimator); + } + } + + return cachedBlockEntityAnimator; + } + + /** + * Sets a scale override for this renderer, telling AzureLib to pre-scale the model + */ + public AzBlockRenderer withScale(float scale) { + return withScale(scale, scale); + } + + /** + * Sets a scale override for this renderer, telling AzureLib to pre-scale the model + */ + public AzBlockRenderer withScale(float scaleWidth, float scaleHeight) { + this.scaleWidth = scaleWidth; + this.scaleHeight = scaleHeight; + + return this; + } + + /** + * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer + */ + public List> getRenderLayers() { + return this.renderLayers; + } + + /** + * Adds a {@link AzRenderLayer} to this renderer, to be called after the main model is rendered each frame + */ + public AzBlockRenderer addRenderLayer(AzRenderLayer renderLayer) { + this.renderLayers.add(renderLayer); + + return this; + } + + public AzBlockAnimator getAnimator() { + return reusedAzBlockAnimator; + } + + public float getScaleHeight() { + return scaleHeight; + } + + public float getScaleWidth() { + return scaleWidth; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzBlockEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzBlockEntityRendererPipeline.java new file mode 100644 index 000000000..f006445ca --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzBlockEntityRendererPipeline.java @@ -0,0 +1,197 @@ +package mod.azure.azurelib.core2.render.pipeline.impl; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.block.AzBlockRenderer; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.DirectionalBlock; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; +import org.joml.Vector3f; + +import java.util.List; + +public class AzBlockEntityRendererPipeline extends AzRendererPipeline { + + private final AzBlockRenderer blockRenderer; + + protected Matrix4f entityRenderTranslations = new Matrix4f(); + + protected Matrix4f modelRenderTranslations = new Matrix4f(); + + public AzBlockEntityRendererPipeline(AzBlockRenderer entityRenderer) { + this.blockRenderer = entityRenderer; + } + + @Override + protected AzBlockEntityRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { + return new AzBlockEntityRendererPipelineContext<>(this); + } + + @Override + public @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { + return blockRenderer.getTextureLocation(animatable); + } + + @Override + protected List> getRenderLayers() { + return blockRenderer.getRenderLayers(); + } + + /** + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
      + * This should only be called immediately prior to rendering, and only + * + * @see AnimatableTexture#setAndUpdate(ResourceLocation, int) + */ + @Override + public void updateAnimatedTextureFrame(T entity) { + AnimatableTexture.setAndUpdate( + getTextureLocation(entity), + entity.getBlockPos().getX() + entity.getBlockPos().getY() + entity.getBlockPos().getZ() + + (int) RenderUtils.getCurrentTick() + ); + } + + /** + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
      + * {@link PoseStack} translations made here are kept until the end of the render process + */ + @Override + public void preRender(AzRendererPipelineContext context, boolean isReRender) { + var poseStack = context.poseStack(); + this.entityRenderTranslations.set(poseStack.last().pose()); + + scaleModelForRender( + context, + this.blockRenderer.getScaleWidth(), + this.blockRenderer.getScaleHeight(), + isReRender + ); + } + + /** + * The actual render method that subtype renderers should override to handle their specific rendering tasks.
      + * {@link AzBlockEntityRendererPipeline#preRender} has already been called by this stage, and + * {@link AzBlockEntityRendererPipeline#postRender} will be called directly after + */ + @Override + public void actuallyRender(AzRendererPipelineContext context, boolean isReRender) { + var entity = context.animatable(); + var poseStack = context.poseStack(); + + if (!isReRender) { + rotateBlock(getFacing(entity), poseStack); + + poseStack.translate(0.5, 0, 0.5); + var animator = blockRenderer.getAnimator(); + + if (animator != null) { + animator.animate(entity); + } + } + + this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); + + RenderSystem.setShaderTexture(0, getTextureLocation(entity)); + super.actuallyRender(context, isReRender); + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + @Override + public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + var buffer = context.vertexConsumer(); + var bufferSource = context.multiBufferSource(); + var entity = context.animatable(); + var poseStack = context.poseStack(); + var renderType = context.renderType(); + + poseStack.pushPose(); + RenderUtils.translateMatrixToBone(poseStack, bone); + RenderUtils.translateToPivotPoint(poseStack, bone); + RenderUtils.rotateMatrixAroundBone(poseStack, bone); + RenderUtils.scaleMatrixForBone(poseStack, bone); + + if (bone.isTrackingMatrices()) { + Matrix4f poseState = new Matrix4f(poseStack.last().pose()); + Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices(poseState, this.entityRenderTranslations); + + bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); + bone.setLocalSpaceMatrix( + RenderUtils.translateMatrix(localMatrix, Vec3.ZERO.toVector3f()) + ); + bone.setWorldSpaceMatrix( + RenderUtils.translateMatrix( + new Matrix4f(localMatrix), + new Vector3f( + entity.getBlockPos().getX(), + entity.getBlockPos().getY(), + entity.getBlockPos().getZ() + ) + ) + ); + } + + RenderUtils.translateAwayFromPivotPoint(poseStack, bone); + + if (!isReRender && buffer instanceof BufferBuilder builder && !builder.building) { + context.setVertexConsumer(bufferSource.getBuffer(renderType)); + } + + renderCubesOfBone(context, bone); + + if (!isReRender) { + applyRenderLayersForBone(context, bone); + } + + renderChildBones(context, bone, isReRender); + + poseStack.popPose(); + } + + /** + * Attempt to extract a direction from the block so that the model can be oriented correctly + */ + protected Direction getFacing(T block) { + BlockState blockState = block.getBlockState(); + + if (blockState.hasProperty(HorizontalDirectionalBlock.FACING)) + return blockState.getValue(HorizontalDirectionalBlock.FACING); + + if (blockState.hasProperty(DirectionalBlock.FACING)) + return blockState.getValue(DirectionalBlock.FACING); + + return Direction.NORTH; + } + + /** + * Rotate the {@link PoseStack} based on the determined {@link Direction} the block is facing + */ + protected void rotateBlock(Direction facing, PoseStack poseStack) { + switch (facing) { + case SOUTH -> poseStack.mulPose(Axis.YP.rotationDegrees(180)); + case WEST -> poseStack.mulPose(Axis.YP.rotationDegrees(90)); + case NORTH -> poseStack.mulPose(Axis.YP.rotationDegrees(0)); + case EAST -> poseStack.mulPose(Axis.YP.rotationDegrees(270)); + case UP -> poseStack.mulPose(Axis.XP.rotationDegrees(90)); + case DOWN -> poseStack.mulPose(Axis.XN.rotationDegrees(90)); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzBlockEntityRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzBlockEntityRendererPipelineContext.java new file mode 100644 index 000000000..cf4541040 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/impl/AzBlockEntityRendererPipelineContext.java @@ -0,0 +1,27 @@ +package mod.azure.azurelib.core2.render.pipeline.impl; + +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class AzBlockEntityRendererPipelineContext extends AzRendererPipelineContext { + + public AzBlockEntityRendererPipelineContext(AzRendererPipeline rendererPipeline) { + super(rendererPipeline); + } + + @Override + public @NotNull RenderType getDefaultRenderType( + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ) { + return RenderType.entityCutoutNoCull(texture); + } +} \ No newline at end of file diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index dae0227fc..ed4bb1544 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -71,6 +71,10 @@ public void onInitializeClient() { AzItemStackDispatchCommandPacket.TYPE, (packet, context) -> packet.handle() ); + ClientPlayNetworking.registerGlobalReceiver( + AzBlockEntityDispatchCommandPacket.TYPE, + (packet, context) -> packet.handle() + ); ClientPlayNetworking.registerGlobalReceiver( EntityAnimDataSyncPacket.TYPE, (packet, context) -> packet.handle() diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index abbcfabf7..37e2b79cb 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -1,5 +1,6 @@ package mod.azure.azurelib.fabric; +import mod.azure.azurelib.common.internal.common.network.packet.*; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; @@ -17,16 +18,6 @@ import mod.azure.azurelib.common.internal.common.config.AzureLibConfig; import mod.azure.azurelib.common.internal.common.config.format.ConfigFormats; import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import mod.azure.azurelib.common.internal.common.network.packet.AnimDataSyncPacket; -import mod.azure.azurelib.common.internal.common.network.packet.AnimTriggerPacket; -import mod.azure.azurelib.common.internal.common.network.packet.AzEntityAnimTriggerPacket; -import mod.azure.azurelib.common.internal.common.network.packet.AzEntityDispatchCommandPacket; -import mod.azure.azurelib.common.internal.common.network.packet.AzItemStackDispatchCommandPacket; -import mod.azure.azurelib.common.internal.common.network.packet.BlockEntityAnimDataSyncPacket; -import mod.azure.azurelib.common.internal.common.network.packet.BlockEntityAnimTriggerPacket; -import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimDataSyncPacket; -import mod.azure.azurelib.common.internal.common.network.packet.EntityAnimTriggerPacket; -import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; import mod.azure.azurelib.fabric.core2.example.armors.DoomArmor; import mod.azure.azurelib.fabric.core2.example.blocks.Stargate; @@ -52,6 +43,7 @@ public void onInitialize() { PayloadTypeRegistry.playS2C().register(BlockEntityAnimTriggerPacket.TYPE, BlockEntityAnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(BlockEntityAnimDataSyncPacket.TYPE, BlockEntityAnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(EntityAnimTriggerPacket.TYPE, EntityAnimTriggerPacket.CODEC); + PayloadTypeRegistry.playS2C().register(AzBlockEntityDispatchCommandPacket.TYPE, AzBlockEntityDispatchCommandPacket.CODEC); PayloadTypeRegistry.playS2C().register(AzEntityAnimTriggerPacket.TYPE, AzEntityAnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(AzEntityDispatchCommandPacket.TYPE, AzEntityDispatchCommandPacket.CODEC); PayloadTypeRegistry.playS2C() diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java index 5ee7a42eb..d935e899b 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java @@ -2,9 +2,12 @@ import com.mojang.serialization.MapCodec; import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.BaseEntityBlock; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,4 +31,13 @@ public Stargate(Properties properties) { public @Nullable BlockEntity newBlockEntity(BlockPos pos, BlockState state) { return ExampleEntityTypes.STARGATE.create(pos, state); } + + @Override + public BlockEntityTicker getTicker( + @NotNull Level level, + @NotNull BlockState state, + @NotNull BlockEntityType type + ) { + return createTickerHelper(type, ExampleEntityTypes.STARGATE, StargateBlockEntity::tick); + } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateAnimationDispatcher.java new file mode 100644 index 000000000..925333441 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateAnimationDispatcher.java @@ -0,0 +1,20 @@ +package mod.azure.azurelib.fabric.core2.example.blocks; + +import mod.azure.azurelib.core2.animation.dispatch.AzDispatcher; +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; + +public class StargateAnimationDispatcher { + + private static final String SPIN_ANIMATION_NAME = "spinning"; + + private static final AzDispatchCommand SPINNING_COMMAND = AzDispatchCommand.builder() + .playAnimation("base_controller", SPIN_ANIMATION_NAME) + .build(); + + public void serverSpin(BlockEntity entity) { + AzDispatcher.fromClient(SPINNING_COMMAND).sendForBlockEntity(entity); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java index cfecef419..402bab9c1 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java @@ -1,6 +1,8 @@ package mod.azure.azurelib.fabric.core2.example.blocks; +import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; @@ -13,30 +15,18 @@ import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; -public class StargateBlockEntity extends BlockEntity implements GeoBlockEntity { +public class StargateBlockEntity extends BlockEntity { - private final AnimatableInstanceCache cache = AzureLibUtil.createInstanceCache(this); - - private static final String SPIN_ANIMATION_NAME = "equipping"; - - private static final RawAnimation SPIN_ANIMATION = RawAnimation.begin().thenLoop(SPIN_ANIMATION_NAME); + public final StargateAnimationDispatcher animationDispatcher; public StargateBlockEntity(BlockPos pos, BlockState blockState) { super(ExampleEntityTypes.STARGATE, pos, blockState); + this.animationDispatcher = new StargateAnimationDispatcher(); } - @Override - public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { - controllers.add( - new AnimationController<>(this, "base_controller", 0, state -> PlayState.CONTINUE).triggerableAnim( - SPIN_ANIMATION_NAME, - SPIN_ANIMATION - ) - ); - } - - @Override - public AnimatableInstanceCache getAnimatableInstanceCache() { - return cache; + public static void tick(Level level, BlockPos pos, BlockState state, StargateBlockEntity blockEntity) { + if (blockEntity.level != null && level.isClientSide()) { + blockEntity.animationDispatcher.serverSpin(blockEntity); + } } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntityAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntityAnimator.java new file mode 100644 index 000000000..1f0208c21 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntityAnimator.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.fabric.core2.example.blocks; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzBlockAnimator; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +public class StargateBlockEntityAnimator extends AzBlockAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource( + "animations/block/stargate.animation.json" + ); + + private static final String SPIN_ANIMATION_NAME = "spinning"; + + private static final AzRawAnimation SPIN_ANIMATION = AzRawAnimation.begin().thenLoop(SPIN_ANIMATION_NAME); + + protected StargateBlockEntityAnimator() { + super(AzAnimatorConfig.defaultConfig()); + } + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + AzAnimationController.builder(this, "base_controller") + .triggerableAnim(SPIN_ANIMATION_NAME, SPIN_ANIMATION) + .build() + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(StargateBlockEntity animatable) { + return ANIMATIONS; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java index 6fd9dc875..e1c021d92 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java @@ -1,12 +1,37 @@ package mod.azure.azurelib.fabric.core2.example.blocks; -import mod.azure.azurelib.common.api.client.model.DefaultedBlockGeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoBlockRenderer; import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.impl.AzBlockAnimator; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.block.AzBlockRenderer; +import mod.azure.azurelib.fabric.core2.example.entities.drone.Drone; +import mod.azure.azurelib.fabric.core2.example.entities.drone.DroneAnimator; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public class StargateRender extends GeoBlockRenderer { +public class StargateRender extends AzBlockRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/block/stargate.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/block/stargate.png"); public StargateRender() { - super(new DefaultedBlockGeoModel<>(AzureLib.modResource("stargate"))); + super(); + } + + @Override + protected @Nullable AzBlockAnimator createAnimator() { + return new StargateBlockEntityAnimator(); + } + + @Override + protected @NotNull ResourceLocation getModelLocation(StargateBlockEntity entity) { + return MODEL; + } + + @Override + public @NotNull ResourceLocation getTextureLocation(StargateBlockEntity entity) { + return TEXTURE; } } diff --git a/fabric/src/main/resources/azurelib.fabric.mixins.json b/fabric/src/main/resources/azurelib.fabric.mixins.json index 08d156654..737e7cfeb 100644 --- a/fabric/src/main/resources/azurelib.fabric.mixins.json +++ b/fabric/src/main/resources/azurelib.fabric.mixins.json @@ -9,6 +9,7 @@ "PlayerListMixin" ], "client": [ + "BlockEntityMixin_AzBlockEntityAnimatorCache", "EntityMixin_AzEntityAnimatorCache", "ItemRendererAccessor", "ItemStackMixin_AzItemAnimatorCache", diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java index 378b9cc42..2dca17de0 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java @@ -73,6 +73,11 @@ public void registerMessages(RegisterPayloadHandlersEvent event) { AzItemStackDispatchCommandPacket.CODEC, (msg, ctx) -> msg.handle() ); + registrar.playBidirectional( + AzBlockEntityDispatchCommandPacket.TYPE, + AzBlockEntityDispatchCommandPacket.CODEC, + (msg, ctx) -> msg.handle() + ); registrar.playBidirectional( EntityAnimDataSyncPacket.TYPE, EntityAnimDataSyncPacket.CODEC, diff --git a/neo/src/main/resources/azurelib.neo.mixins.json b/neo/src/main/resources/azurelib.neo.mixins.json index 4a8ea8f50..59d0887da 100644 --- a/neo/src/main/resources/azurelib.neo.mixins.json +++ b/neo/src/main/resources/azurelib.neo.mixins.json @@ -9,6 +9,7 @@ "PlayerListMixin" ], "client": [ + "BlockEntityMixin_AzBlockEntityAnimatorCache", "EntityMixin_AzEntityAnimatorCache", "ItemRendererAccessor", "ItemStackMixin_AzItemAnimatorCache", From dc1ae14a9d3ce706593878748b284dad6ead05f2 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 09:51:35 -0500 Subject: [PATCH 148/224] Fixed up block entity to use new render pipeline flow. Signed-off-by: = --- .../AzBlockEntityDispatchCommandPacket.java | 32 ++--- ...ntityMixin_AzBlockEntityAnimatorCache.java | 5 +- .../platform/services/AzureLibNetwork.java | 2 +- .../dispatch/AzDispatchExecutor.java | 4 +- .../core2/animation/impl/AzBlockAnimator.java | 5 +- .../render/AzBlockEntityRendererConfig.java | 73 +++++++++++ .../core2/render/block/AzBlockRenderer.java | 114 +++++------------ .../AzBlockEntityModelRenderer.java} | 120 ++++++------------ .../block/AzBlockEntityRendererPipeline.java | 83 ++++++++++++ .../AzBlockEntityRendererPipelineContext.java | 17 +-- .../azure/azurelib/fabric/ClientListener.java | 4 +- .../azurelib/fabric/FabricAzureLibMod.java | 5 +- .../fabric/core2/example/blocks/Stargate.java | 6 +- .../blocks/StargateAnimationDispatcher.java | 5 +- .../example/blocks/StargateBlockEntity.java | 8 -- .../blocks/StargateBlockEntityAnimator.java | 13 +- .../core2/example/blocks/StargateRender.java | 31 ++--- .../neoforge/NeoForgeAzureLibMod.java | 6 +- 18 files changed, 288 insertions(+), 245 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/AzBlockEntityRendererConfig.java rename common/src/main/java/mod/azure/azurelib/core2/render/pipeline/{entity/AzBlockEntityRendererPipeline.java => block/AzBlockEntityModelRenderer.java} (52%) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipeline.java rename common/src/main/java/mod/azure/azurelib/core2/render/pipeline/{entity => block}/AzBlockEntityRendererPipelineContext.java (80%) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzBlockEntityDispatchCommandPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzBlockEntityDispatchCommandPacket.java index a4baddcd0..03931b90f 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzBlockEntityDispatchCommandPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzBlockEntityDispatchCommandPacket.java @@ -1,33 +1,35 @@ package mod.azure.azurelib.common.internal.common.network.packet; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; + import mod.azure.azurelib.common.api.client.helper.ClientUtils; import mod.azure.azurelib.common.internal.common.network.AbstractPacket; import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; public record AzBlockEntityDispatchCommandPacket( - BlockPos blockPos, - AzDispatchCommand dispatchCommand, - AzDispatchSide origin) implements AbstractPacket { + BlockPos blockPos, + AzDispatchCommand dispatchCommand, + AzDispatchSide origin +) implements AbstractPacket { public static final CustomPacketPayload.Type TYPE = new Type<>( - AzureLibNetwork.AZ_BLOCKENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID + AzureLibNetwork.AZ_BLOCKENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID ); public static final StreamCodec CODEC = StreamCodec.composite( - BlockPos.STREAM_CODEC, - AzBlockEntityDispatchCommandPacket::blockPos, - AzDispatchCommand.CODEC, - AzBlockEntityDispatchCommandPacket::dispatchCommand, - AzDispatchSide.CODEC, - AzBlockEntityDispatchCommandPacket::origin, - AzBlockEntityDispatchCommandPacket::new + BlockPos.STREAM_CODEC, + AzBlockEntityDispatchCommandPacket::blockPos, + AzDispatchCommand.CODEC, + AzBlockEntityDispatchCommandPacket::dispatchCommand, + AzDispatchSide.CODEC, + AzBlockEntityDispatchCommandPacket::origin, + AzBlockEntityDispatchCommandPacket::new ); @Override diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java index 315b64c14..0ce31ada2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java @@ -1,12 +1,13 @@ package mod.azure.azurelib.common.internal.mixins; -import mod.azure.azurelib.core2.animation.AzAnimator; -import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; + @Mixin(BlockEntity.class) public abstract class BlockEntityMixin_AzBlockEntityAnimatorCache implements AzAnimatorAccessor { diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java index 97c71903e..a1d167601 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java @@ -25,7 +25,7 @@ public interface AzureLibNetwork { ResourceLocation ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("anim_trigger_sync"); ResourceLocation AZ_BLOCKENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID = AzureLib.modResource( - "az_blockentity_dispatch_command_sync" + "az_blockentity_dispatch_command_sync" ); ResourceLocation AZ_ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("az_entity_anim_trigger_sync"); diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java index dad1006fd..cfa9a8470 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java @@ -1,21 +1,21 @@ package mod.azure.azurelib.core2.animation.dispatch; -import mod.azure.azurelib.common.internal.common.network.packet.AzBlockEntityDispatchCommandPacket; import net.minecraft.core.component.PatchedDataComponentMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; import java.util.List; import java.util.UUID; import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.network.packet.AzBlockEntityDispatchCommandPacket; import mod.azure.azurelib.common.internal.common.network.packet.AzEntityDispatchCommandPacket; import mod.azure.azurelib.common.internal.common.network.packet.AzItemStackDispatchCommandPacket; import mod.azure.azurelib.common.platform.Services; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; -import net.minecraft.world.level.block.entity.BlockEntity; public record AzDispatchExecutor( List commands, diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzBlockAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzBlockAnimator.java index 1320dd599..8396ed062 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzBlockAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzBlockAnimator.java @@ -1,12 +1,13 @@ package mod.azure.azurelib.core2.animation.impl; +import net.minecraft.world.level.block.entity.BlockEntity; + import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.AzAnimatorConfig; -import net.minecraft.world.level.block.entity.BlockEntity; public abstract class AzBlockAnimator extends AzAnimator { protected AzBlockAnimator(AzAnimatorConfig config) { super(config); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzBlockEntityRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzBlockEntityRendererConfig.java new file mode 100644 index 000000000..9d4036515 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzBlockEntityRendererConfig.java @@ -0,0 +1,73 @@ +package mod.azure.azurelib.core2.render; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +public class AzBlockEntityRendererConfig extends AzRendererConfig { + + private AzBlockEntityRendererConfig( + Supplier> animatorProvider, + Function modelLocationProvider, + List> renderLayers, + Function textureLocationProvider, + float scaleHeight, + float scaleWidth + ) { + super(animatorProvider, modelLocationProvider, renderLayers, textureLocationProvider, scaleHeight, scaleWidth); + } + + public static Builder builder( + ResourceLocation modelLocation, + ResourceLocation textureLocation + ) { + return new Builder<>($ -> modelLocation, $ -> textureLocation); + } + + public static Builder builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + return new Builder<>(modelLocationProvider, textureLocationProvider); + } + + public static class Builder extends AzRendererConfig.Builder { + + protected Builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + super(modelLocationProvider, textureLocationProvider); + } + + @Override + public Builder addRenderLayer(AzRenderLayer renderLayer) { + return (Builder) super.addRenderLayer(renderLayer); + } + + @Override + public Builder setAnimatorProvider(Supplier<@Nullable AzAnimator> animatorProvider) { + return (Builder) super.setAnimatorProvider(animatorProvider); + } + + public AzBlockEntityRendererConfig build() { + var baseConfig = super.build(); + + return new AzBlockEntityRendererConfig<>( + baseConfig::createAnimator, + baseConfig::modelLocation, + baseConfig.renderLayers(), + baseConfig::textureLocation, + baseConfig.scaleHeight(), + baseConfig.scaleWidth() + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java index 04ffc3cfa..664e0a55a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java @@ -1,48 +1,43 @@ package mod.azure.azurelib.core2.render.block; import com.mojang.blaze3d.vertex.PoseStack; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; -import mod.azure.azurelib.core2.animation.impl.AzBlockAnimator; -import mod.azure.azurelib.core2.model.AzBakedModel; -import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; -import mod.azure.azurelib.core2.render.pipeline.impl.AzBlockEntityRendererPipeline; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.impl.AzBlockAnimator; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; +import mod.azure.azurelib.core2.render.AzBlockEntityRendererConfig; +import mod.azure.azurelib.core2.render.pipeline.block.AzBlockEntityRendererPipeline; public abstract class AzBlockRenderer implements BlockEntityRenderer { - private final AzBlockEntityRendererPipeline rendererPipeline; - - private final List> renderLayers; + private final AzBlockEntityRendererConfig config; - private float scaleWidth = 1; - - private float scaleHeight = 1; + private final AzBlockEntityRendererPipeline rendererPipeline; @Nullable private AzBlockAnimator reusedAzBlockAnimator; - protected AzBlockRenderer() { + protected AzBlockRenderer(AzBlockEntityRendererConfig config) { super(); - this.rendererPipeline = new AzBlockEntityRendererPipeline<>(this); - this.renderLayers = new ObjectArrayList<>(); + this.config = config; + this.rendererPipeline = new AzBlockEntityRendererPipeline<>(config, this); } - protected abstract @NotNull ResourceLocation getModelLocation(T entity); - - public abstract @NotNull ResourceLocation getTextureLocation(T entity); - @Override - public void render(@NotNull T entity, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource multiBufferSource, int packedLight, int packedOverlay) { - + public void render( + @NotNull T entity, + float partialTick, + @NotNull PoseStack poseStack, + @NotNull MultiBufferSource multiBufferSource, + int packedLight, + int packedOverlay + ) { var cachedEntityAnimator = provideAnimator(entity); var azBakedModel = provideBakedModel(entity); @@ -55,24 +50,20 @@ public void render(@NotNull T entity, float partialTick, @NotNull PoseStack pose // Execute the render pipeline. rendererPipeline.render( - poseStack, - azBakedModel, - entity, - multiBufferSource, - null, - null, - 0, - partialTick, - packedLight + poseStack, + azBakedModel, + entity, + multiBufferSource, + null, + null, + 0, + partialTick, + packedLight ); } - protected @Nullable AzBlockAnimator createAnimator() { - return null; - } - protected @Nullable AzBakedModel provideBakedModel(@NotNull T entity) { - var modelResourceLocation = getModelLocation(entity); + var modelResourceLocation = config.modelLocation(entity); return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); } @@ -84,11 +75,13 @@ public void render(@NotNull T entity, float partialTick, @NotNull PoseStack pose if (cachedBlockEntityAnimator == null) { // If the cached animator is null, create a new one. We use a separate reference here just for some - cachedBlockEntityAnimator = createAnimator(); + cachedBlockEntityAnimator = (AzBlockAnimator) config.createAnimator(); if (cachedBlockEntityAnimator != null) { // If the new animator we created is not null, then register its controllers. - cachedBlockEntityAnimator.registerControllers(cachedBlockEntityAnimator.getAnimationControllerContainer()); + cachedBlockEntityAnimator.registerControllers( + cachedBlockEntityAnimator.getAnimationControllerContainer() + ); // Also cache the animator so that the next time we fetch the animator, it's ready for us. accessor.setAnimator(cachedBlockEntityAnimator); } @@ -97,48 +90,7 @@ public void render(@NotNull T entity, float partialTick, @NotNull PoseStack pose return cachedBlockEntityAnimator; } - /** - * Sets a scale override for this renderer, telling AzureLib to pre-scale the model - */ - public AzBlockRenderer withScale(float scale) { - return withScale(scale, scale); - } - - /** - * Sets a scale override for this renderer, telling AzureLib to pre-scale the model - */ - public AzBlockRenderer withScale(float scaleWidth, float scaleHeight) { - this.scaleWidth = scaleWidth; - this.scaleHeight = scaleHeight; - - return this; - } - - /** - * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer - */ - public List> getRenderLayers() { - return this.renderLayers; - } - - /** - * Adds a {@link AzRenderLayer} to this renderer, to be called after the main model is rendered each frame - */ - public AzBlockRenderer addRenderLayer(AzRenderLayer renderLayer) { - this.renderLayers.add(renderLayer); - - return this; - } - public AzBlockAnimator getAnimator() { return reusedAzBlockAnimator; } - - public float getScaleHeight() { - return scaleHeight; - } - - public float getScaleWidth() { - return scaleWidth; - } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzBlockEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityModelRenderer.java similarity index 52% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzBlockEntityRendererPipeline.java rename to common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityModelRenderer.java index f006445ca..04283b7df 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzBlockEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityModelRenderer.java @@ -1,88 +1,34 @@ -package mod.azure.azurelib.core2.render.pipeline.impl; +package mod.azure.azurelib.core2.render.pipeline.block; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.block.AzBlockRenderer; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.DirectionalBlock; import net.minecraft.world.level.block.HorizontalDirectionalBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; import org.joml.Vector3f; -import java.util.List; - -public class AzBlockEntityRendererPipeline extends AzRendererPipeline { - - private final AzBlockRenderer blockRenderer; - - protected Matrix4f entityRenderTranslations = new Matrix4f(); - - protected Matrix4f modelRenderTranslations = new Matrix4f(); - - public AzBlockEntityRendererPipeline(AzBlockRenderer entityRenderer) { - this.blockRenderer = entityRenderer; - } - - @Override - protected AzBlockEntityRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { - return new AzBlockEntityRendererPipelineContext<>(this); - } - - @Override - public @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { - return blockRenderer.getTextureLocation(animatable); - } +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; - @Override - protected List> getRenderLayers() { - return blockRenderer.getRenderLayers(); - } +public class AzBlockEntityModelRenderer extends AzModelRenderer { - /** - * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this - * GeoRenderer.
      - * This should only be called immediately prior to rendering, and only - * - * @see AnimatableTexture#setAndUpdate(ResourceLocation, int) - */ - @Override - public void updateAnimatedTextureFrame(T entity) { - AnimatableTexture.setAndUpdate( - getTextureLocation(entity), - entity.getBlockPos().getX() + entity.getBlockPos().getY() + entity.getBlockPos().getZ() - + (int) RenderUtils.getCurrentTick() - ); - } + private final AzBlockEntityRendererPipeline blockEntityRendererPipeline; - /** - * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling - * and translating.
      - * {@link PoseStack} translations made here are kept until the end of the render process - */ - @Override - public void preRender(AzRendererPipelineContext context, boolean isReRender) { - var poseStack = context.poseStack(); - this.entityRenderTranslations.set(poseStack.last().pose()); - - scaleModelForRender( - context, - this.blockRenderer.getScaleWidth(), - this.blockRenderer.getScaleHeight(), - isReRender - ); + public AzBlockEntityModelRenderer( + AzBlockEntityRendererPipeline blockEntityRendererPipeline, + AzLayerRenderer layerRenderer + ) { + super(blockEntityRendererPipeline, layerRenderer); + this.blockEntityRendererPipeline = blockEntityRendererPipeline; } /** @@ -91,7 +37,7 @@ public void preRender(AzRendererPipelineContext context, boolean isReRender) * {@link AzBlockEntityRendererPipeline#postRender} will be called directly after */ @Override - public void actuallyRender(AzRendererPipelineContext context, boolean isReRender) { + public void render(AzRendererPipelineContext context, boolean isReRender) { var entity = context.animatable(); var poseStack = context.poseStack(); @@ -99,17 +45,18 @@ public void actuallyRender(AzRendererPipelineContext context, boolean isReRen rotateBlock(getFacing(entity), poseStack); poseStack.translate(0.5, 0, 0.5); - var animator = blockRenderer.getAnimator(); + var animator = blockEntityRendererPipeline.getRenderer().getAnimator(); if (animator != null) { animator.animate(entity); } } - this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); + blockEntityRendererPipeline.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); - RenderSystem.setShaderTexture(0, getTextureLocation(entity)); - super.actuallyRender(context, isReRender); + var textureLocation = blockEntityRendererPipeline.config().textureLocation(entity); + RenderSystem.setShaderTexture(0, textureLocation); + super.render(context, isReRender); } /** @@ -131,21 +78,26 @@ public void renderRecursively(AzRendererPipelineContext context, AzBone bone, if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); - Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices(poseState, this.entityRenderTranslations); + Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices( + poseState, + blockEntityRendererPipeline.entityRenderTranslations + ); - bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); + bone.setModelSpaceMatrix( + RenderUtils.invertAndMultiplyMatrices(poseState, blockEntityRendererPipeline.modelRenderTranslations) + ); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, Vec3.ZERO.toVector3f()) + RenderUtils.translateMatrix(localMatrix, Vec3.ZERO.toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix( - new Matrix4f(localMatrix), - new Vector3f( - entity.getBlockPos().getX(), - entity.getBlockPos().getY(), - entity.getBlockPos().getZ() - ) + RenderUtils.translateMatrix( + new Matrix4f(localMatrix), + new Vector3f( + entity.getBlockPos().getX(), + entity.getBlockPos().getY(), + entity.getBlockPos().getZ() ) + ) ); } @@ -158,7 +110,7 @@ public void renderRecursively(AzRendererPipelineContext context, AzBone bone, renderCubesOfBone(context, bone); if (!isReRender) { - applyRenderLayersForBone(context, bone); + layerRenderer.applyRenderLayersForBone(context, bone); } renderChildBones(context, bone, isReRender); diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipeline.java new file mode 100644 index 000000000..cf52ab91d --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipeline.java @@ -0,0 +1,83 @@ +package mod.azure.azurelib.core2.render.pipeline.block; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.joml.Matrix4f; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.render.AzBlockEntityRendererConfig; +import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.block.AzBlockRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; + +public class AzBlockEntityRendererPipeline extends AzRendererPipeline { + + private final AzBlockRenderer blockRenderer; + + protected Matrix4f entityRenderTranslations = new Matrix4f(); + + protected Matrix4f modelRenderTranslations = new Matrix4f(); + + public AzBlockEntityRendererPipeline(AzBlockEntityRendererConfig config, AzBlockRenderer entityRenderer) { + super(config); + this.blockRenderer = entityRenderer; + } + + @Override + protected AzBlockEntityRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { + return new AzBlockEntityRendererPipelineContext<>(this); + } + + @Override + protected AzModelRenderer createModelRenderer(AzLayerRenderer layerRenderer) { + return new AzBlockEntityModelRenderer<>(this, layerRenderer); + } + + @Override + protected AzLayerRenderer createLayerRenderer(AzRendererConfig config) { + return new AzLayerRenderer<>(config::renderLayers); + } + + /** + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
      + * This should only be called immediately prior to rendering, and only + * + * @see AnimatableTexture#setAndUpdate(ResourceLocation, int) + */ + @Override + public void updateAnimatedTextureFrame(T entity) { + AnimatableTexture.setAndUpdate( + config.textureLocation(entity), + entity.getBlockPos().getX() + entity.getBlockPos().getY() + entity.getBlockPos().getZ() + + (int) RenderUtils.getCurrentTick() + ); + } + + /** + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
      + * {@link PoseStack} translations made here are kept until the end of the render process + */ + @Override + public void preRender(AzRendererPipelineContext context, boolean isReRender) { + var poseStack = context.poseStack(); + this.entityRenderTranslations.set(poseStack.last().pose()); + + var scaleWidth = config.scaleWidth(); + var scaleHeight = config.scaleHeight(); + scaleModelForRender(context, scaleWidth, scaleHeight, isReRender); + } + + @Override + public void postRender(AzRendererPipelineContext context, boolean isReRender) {} + + public AzBlockRenderer getRenderer() { + return blockRenderer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzBlockEntityRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipelineContext.java similarity index 80% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzBlockEntityRendererPipelineContext.java rename to common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipelineContext.java index cf4541040..c0dcd06c2 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzBlockEntityRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipelineContext.java @@ -1,7 +1,5 @@ -package mod.azure.azurelib.core2.render.pipeline.impl; +package mod.azure.azurelib.core2.render.pipeline.block; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; @@ -9,6 +7,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; +import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; + public class AzBlockEntityRendererPipelineContext extends AzRendererPipelineContext { public AzBlockEntityRendererPipelineContext(AzRendererPipeline rendererPipeline) { @@ -17,11 +18,11 @@ public AzBlockEntityRendererPipelineContext(AzRendererPipeline rendererPipeli @Override public @NotNull RenderType getDefaultRenderType( - T animatable, - ResourceLocation texture, - @Nullable MultiBufferSource bufferSource, - float partialTick + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick ) { return RenderType.entityCutoutNoCull(texture); } -} \ No newline at end of file +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index ed4bb1544..3cf9c28ce 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -72,8 +72,8 @@ public void onInitializeClient() { (packet, context) -> packet.handle() ); ClientPlayNetworking.registerGlobalReceiver( - AzBlockEntityDispatchCommandPacket.TYPE, - (packet, context) -> packet.handle() + AzBlockEntityDispatchCommandPacket.TYPE, + (packet, context) -> packet.handle() ); ClientPlayNetworking.registerGlobalReceiver( EntityAnimDataSyncPacket.TYPE, diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 37e2b79cb..9c3a67f24 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -1,6 +1,5 @@ package mod.azure.azurelib.fabric; -import mod.azure.azurelib.common.internal.common.network.packet.*; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; @@ -18,6 +17,7 @@ import mod.azure.azurelib.common.internal.common.config.AzureLibConfig; import mod.azure.azurelib.common.internal.common.config.format.ConfigFormats; import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; +import mod.azure.azurelib.common.internal.common.network.packet.*; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; import mod.azure.azurelib.fabric.core2.example.armors.DoomArmor; import mod.azure.azurelib.fabric.core2.example.blocks.Stargate; @@ -43,7 +43,8 @@ public void onInitialize() { PayloadTypeRegistry.playS2C().register(BlockEntityAnimTriggerPacket.TYPE, BlockEntityAnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(BlockEntityAnimDataSyncPacket.TYPE, BlockEntityAnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(EntityAnimTriggerPacket.TYPE, EntityAnimTriggerPacket.CODEC); - PayloadTypeRegistry.playS2C().register(AzBlockEntityDispatchCommandPacket.TYPE, AzBlockEntityDispatchCommandPacket.CODEC); + PayloadTypeRegistry.playS2C() + .register(AzBlockEntityDispatchCommandPacket.TYPE, AzBlockEntityDispatchCommandPacket.CODEC); PayloadTypeRegistry.playS2C().register(AzEntityAnimTriggerPacket.TYPE, AzEntityAnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(AzEntityDispatchCommandPacket.TYPE, AzEntityDispatchCommandPacket.CODEC); PayloadTypeRegistry.playS2C() diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java index d935e899b..c48e6f8da 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java @@ -34,9 +34,9 @@ public Stargate(Properties properties) { @Override public BlockEntityTicker getTicker( - @NotNull Level level, - @NotNull BlockState state, - @NotNull BlockEntityType type + @NotNull Level level, + @NotNull BlockState state, + @NotNull BlockEntityType type ) { return createTickerHelper(type, ExampleEntityTypes.STARGATE, StargateBlockEntity::tick); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateAnimationDispatcher.java index 925333441..a522e5677 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateAnimationDispatcher.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateAnimationDispatcher.java @@ -1,10 +1,9 @@ package mod.azure.azurelib.fabric.core2.example.blocks; +import net.minecraft.world.level.block.entity.BlockEntity; + import mod.azure.azurelib.core2.animation.dispatch.AzDispatcher; import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; public class StargateAnimationDispatcher { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java index 402bab9c1..d17d1c5fd 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java @@ -1,18 +1,10 @@ package mod.azure.azurelib.fabric.core2.example.blocks; -import mod.azure.azurelib.core2.animation.AzAnimationDispatcher; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; -import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; -import mod.azure.azurelib.core.animation.AnimatableManager; -import mod.azure.azurelib.core.animation.AnimationController; -import mod.azure.azurelib.core.animation.RawAnimation; -import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; public class StargateBlockEntity extends BlockEntity { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntityAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntityAnimator.java index 1f0208c21..95e8a5d47 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntityAnimator.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntityAnimator.java @@ -1,18 +1,19 @@ package mod.azure.azurelib.fabric.core2.example.blocks; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.core2.animation.AzAnimatorConfig; import mod.azure.azurelib.core2.animation.controller.AzAnimationController; import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; import mod.azure.azurelib.core2.animation.impl.AzBlockAnimator; import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; public class StargateBlockEntityAnimator extends AzBlockAnimator { private static final ResourceLocation ANIMATIONS = AzureLib.modResource( - "animations/block/stargate.animation.json" + "animations/block/stargate.animation.json" ); private static final String SPIN_ANIMATION_NAME = "spinning"; @@ -26,9 +27,9 @@ protected StargateBlockEntityAnimator() { @Override public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { animationControllerContainer.add( - AzAnimationController.builder(this, "base_controller") - .triggerableAnim(SPIN_ANIMATION_NAME, SPIN_ANIMATION) - .build() + AzAnimationController.builder(this, "base_controller") + .triggerableAnim(SPIN_ANIMATION_NAME, SPIN_ANIMATION) + .build() ); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java index e1c021d92..f1e75a9f6 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java @@ -1,14 +1,10 @@ package mod.azure.azurelib.fabric.core2.example.blocks; +import net.minecraft.resources.ResourceLocation; + import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.animation.impl.AzBlockAnimator; -import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.AzBlockEntityRendererConfig; import mod.azure.azurelib.core2.render.block.AzBlockRenderer; -import mod.azure.azurelib.fabric.core2.example.entities.drone.Drone; -import mod.azure.azurelib.fabric.core2.example.entities.drone.DroneAnimator; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public class StargateRender extends AzBlockRenderer { @@ -17,21 +13,10 @@ public class StargateRender extends AzBlockRenderer { private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/block/stargate.png"); public StargateRender() { - super(); - } - - @Override - protected @Nullable AzBlockAnimator createAnimator() { - return new StargateBlockEntityAnimator(); - } - - @Override - protected @NotNull ResourceLocation getModelLocation(StargateBlockEntity entity) { - return MODEL; - } - - @Override - public @NotNull ResourceLocation getTextureLocation(StargateBlockEntity entity) { - return TEXTURE; + super( + AzBlockEntityRendererConfig.builder(MODEL, TEXTURE) + .setAnimatorProvider(StargateBlockEntityAnimator::new) + .build() + ); } } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java index 2dca17de0..86c770e30 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java @@ -74,9 +74,9 @@ public void registerMessages(RegisterPayloadHandlersEvent event) { (msg, ctx) -> msg.handle() ); registrar.playBidirectional( - AzBlockEntityDispatchCommandPacket.TYPE, - AzBlockEntityDispatchCommandPacket.CODEC, - (msg, ctx) -> msg.handle() + AzBlockEntityDispatchCommandPacket.TYPE, + AzBlockEntityDispatchCommandPacket.CODEC, + (msg, ctx) -> msg.handle() ); registrar.playBidirectional( EntityAnimDataSyncPacket.TYPE, From d7aba2d105e728965965bd7ae83a29cc9cf9c70e Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 09:55:44 -0500 Subject: [PATCH 149/224] Refactor. Signed-off-by: = --- .../render/{pipeline => }/AzLayerRenderer.java | 2 +- .../render/{pipeline => }/AzModelRenderer.java | 2 +- .../render/{pipeline => }/AzPhasedRenderer.java | 2 +- .../render/{pipeline => }/AzRendererPipeline.java | 3 +-- .../{pipeline => }/AzRendererPipelineContext.java | 2 +- .../block/AzBlockEntityModelRenderer.java | 8 ++++---- .../{ => block}/AzBlockEntityRendererConfig.java | 3 ++- .../block/AzBlockEntityRendererPipeline.java | 12 +++++------- .../block/AzBlockEntityRendererPipelineContext.java | 6 +++--- .../core2/render/block/AzBlockRenderer.java | 2 -- .../entity/AzEntityLayerRenderer.java | 6 +++--- .../entity/AzEntityModelRenderer.java | 8 ++++---- .../core2/render/entity/AzEntityRenderer.java | 2 -- .../render/{ => entity}/AzEntityRendererConfig.java | 3 ++- .../entity/AzEntityRendererPipeline.java | 13 +++++-------- .../entity/AzEntityRendererPipelineContext.java | 6 +++--- .../render/{ => entity}/AzItemRendererConfig.java | 3 ++- .../{pipeline => }/item/AzItemModelRenderer.java | 10 +++++----- .../azurelib/core2/render/item/AzItemRenderer.java | 3 +-- .../{pipeline => }/item/AzItemRendererPipeline.java | 11 +++++------ .../item/AzItemRendererPipelineContext.java | 6 +++--- .../azurelib/core2/render/layer/AzArmorLayer.java | 2 +- .../core2/render/layer/AzAutoGlowingLayer.java | 2 +- .../core2/render/layer/AzBlockAndItemLayer.java | 4 ++-- .../azurelib/core2/render/layer/AzRenderLayer.java | 4 ++-- .../fabric/core2/example/blocks/StargateRender.java | 2 +- .../entities/doomhunter/DoomHunterRenderer.java | 2 +- .../core2/example/entities/drone/DroneRenderer.java | 2 +- .../example/entities/marauder/MarauderRenderer.java | 2 +- .../core2/example/items/AzPistolRenderer.java | 2 +- 30 files changed, 63 insertions(+), 72 deletions(-) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/AzLayerRenderer.java (96%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/AzModelRenderer.java (99%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/AzPhasedRenderer.java (93%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/AzRendererPipeline.java (97%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/AzRendererPipelineContext.java (98%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/block/AzBlockEntityModelRenderer.java (95%) rename common/src/main/java/mod/azure/azurelib/core2/render/{ => block}/AzBlockEntityRendererConfig.java (96%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/block/AzBlockEntityRendererPipeline.java (86%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/block/AzBlockEntityRendererPipelineContext.java (80%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/entity/AzEntityLayerRenderer.java (79%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/entity/AzEntityModelRenderer.java (97%) rename common/src/main/java/mod/azure/azurelib/core2/render/{ => entity}/AzEntityRendererConfig.java (97%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/entity/AzEntityRendererPipeline.java (86%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/entity/AzEntityRendererPipelineContext.java (88%) rename common/src/main/java/mod/azure/azurelib/core2/render/{ => entity}/AzItemRendererConfig.java (97%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/item/AzItemModelRenderer.java (88%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/item/AzItemRendererPipeline.java (88%) rename common/src/main/java/mod/azure/azurelib/core2/render/{pipeline => }/item/AzItemRendererPipelineContext.java (81%) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzLayerRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzLayerRenderer.java similarity index 96% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzLayerRenderer.java rename to common/src/main/java/mod/azure/azurelib/core2/render/AzLayerRenderer.java index 746810a85..c45d31ddf 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzLayerRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzLayerRenderer.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline; +package mod.azure.azurelib.core2.render; import java.util.Collection; import java.util.function.Supplier; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzModelRenderer.java similarity index 99% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzModelRenderer.java rename to common/src/main/java/mod/azure/azurelib/core2/render/AzModelRenderer.java index ba592d225..3e1d21359 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzModelRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzModelRenderer.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline; +package mod.azure.azurelib.core2.render; import com.mojang.blaze3d.vertex.VertexConsumer; import org.joml.Matrix4f; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzPhasedRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzPhasedRenderer.java similarity index 93% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzPhasedRenderer.java rename to common/src/main/java/mod/azure/azurelib/core2/render/AzPhasedRenderer.java index 48ed55860..021bd5655 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzPhasedRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzPhasedRenderer.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline; +package mod.azure.azurelib.core2.render; import com.mojang.blaze3d.vertex.PoseStack; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipeline.java similarity index 97% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java rename to common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipeline.java index fcbeb2af7..bd83bea2a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipeline.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline; +package mod.azure.azurelib.core2.render; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; @@ -8,7 +8,6 @@ import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; import mod.azure.azurelib.core2.model.AzBakedModel; -import mod.azure.azurelib.core2.render.AzRendererConfig; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; public abstract class AzRendererPipeline implements AzPhasedRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipelineContext.java similarity index 98% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java rename to common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipelineContext.java index 4ccb00659..16a56b025 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/AzRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipelineContext.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline; +package mod.azure.azurelib.core2.render; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityModelRenderer.java similarity index 95% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityModelRenderer.java rename to common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityModelRenderer.java index 04283b7df..2cfb5ab37 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityModelRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityModelRenderer.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline.block; +package mod.azure.azurelib.core2.render.block; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.BufferBuilder; @@ -15,9 +15,9 @@ import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; public class AzBlockEntityModelRenderer extends AzModelRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzBlockEntityRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererConfig.java similarity index 96% rename from common/src/main/java/mod/azure/azurelib/core2/render/AzBlockEntityRendererConfig.java rename to common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererConfig.java index 9d4036515..1d33dc192 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzBlockEntityRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererConfig.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render; +package mod.azure.azurelib.core2.render.block; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.entity.BlockEntity; @@ -9,6 +9,7 @@ import java.util.function.Supplier; import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.render.AzRendererConfig; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; public class AzBlockEntityRendererConfig extends AzRendererConfig { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java similarity index 86% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipeline.java rename to common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java index cf52ab91d..797d1fd9e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline.block; +package mod.azure.azurelib.core2.render.block; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.resources.ResourceLocation; @@ -7,13 +7,11 @@ import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core2.render.AzBlockEntityRendererConfig; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; import mod.azure.azurelib.core2.render.AzRendererConfig; -import mod.azure.azurelib.core2.render.block.AzBlockRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; public class AzBlockEntityRendererPipeline extends AzRendererPipeline { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipelineContext.java similarity index 80% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipelineContext.java rename to common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipelineContext.java index c0dcd06c2..a6b027bd4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/block/AzBlockEntityRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipelineContext.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline.block; +package mod.azure.azurelib.core2.render.block; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; @@ -7,8 +7,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; public class AzBlockEntityRendererPipelineContext extends AzRendererPipelineContext { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java index 664e0a55a..45d20ad6b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java @@ -11,8 +11,6 @@ import mod.azure.azurelib.core2.animation.impl.AzBlockAnimator; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; -import mod.azure.azurelib.core2.render.AzBlockEntityRendererConfig; -import mod.azure.azurelib.core2.render.pipeline.block.AzBlockEntityRendererPipeline; public abstract class AzBlockRenderer implements BlockEntityRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityLayerRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLayerRenderer.java similarity index 79% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityLayerRenderer.java rename to common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLayerRenderer.java index e097ac1ab..06aef5d73 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityLayerRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLayerRenderer.java @@ -1,13 +1,13 @@ -package mod.azure.azurelib.core2.render.pipeline.entity; +package mod.azure.azurelib.core2.render.entity; import net.minecraft.world.entity.Entity; import java.util.Collection; import java.util.function.Supplier; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; -import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; public class AzEntityLayerRenderer extends AzLayerRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityModelRenderer.java similarity index 97% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java rename to common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityModelRenderer.java index b4d4ad661..8cb702de2 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityModelRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityModelRenderer.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline.entity; +package mod.azure.azurelib.core2.render.entity; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.PoseStack; @@ -14,9 +14,9 @@ import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; public class AzEntityModelRenderer extends AzModelRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index a882f8983..9ef260b32 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -14,8 +14,6 @@ import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; -import mod.azure.azurelib.core2.render.AzEntityRendererConfig; -import mod.azure.azurelib.core2.render.pipeline.entity.AzEntityRendererPipeline; public abstract class AzEntityRenderer extends EntityRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererConfig.java similarity index 97% rename from common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java rename to common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererConfig.java index b143917a7..9f11c065e 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzEntityRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererConfig.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render; +package mod.azure.azurelib.core2.render.entity; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; @@ -9,6 +9,7 @@ import java.util.function.Supplier; import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.render.AzRendererConfig; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; public class AzEntityRendererConfig extends AzRendererConfig { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipeline.java similarity index 86% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java rename to common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipeline.java index 3fd382042..f68fc6ea4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipeline.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline.entity; +package mod.azure.azurelib.core2.render.entity; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.resources.ResourceLocation; @@ -7,14 +7,11 @@ import org.joml.Matrix4f; import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core2.render.AzEntityRendererConfig; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; import mod.azure.azurelib.core2.render.AzRendererConfig; -import mod.azure.azurelib.core2.render.entity.AzEntityLeashRenderUtil; -import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; public class AzEntityRendererPipeline extends AzRendererPipeline { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipelineContext.java similarity index 88% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipelineContext.java rename to common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipelineContext.java index e4fd08a8b..6d91788c5 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/entity/AzEntityRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipelineContext.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline.entity; +package mod.azure.azurelib.core2.render.entity; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; @@ -9,8 +9,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; public class AzEntityRendererPipelineContext extends AzRendererPipelineContext { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzItemRendererConfig.java similarity index 97% rename from common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java rename to common/src/main/java/mod/azure/azurelib/core2/render/entity/AzItemRendererConfig.java index 55c507bcf..3b8497812 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/AzItemRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzItemRendererConfig.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render; +package mod.azure.azurelib.core2.render.entity; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; @@ -9,6 +9,7 @@ import java.util.function.Supplier; import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.render.AzRendererConfig; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; public class AzItemRendererConfig extends AzRendererConfig { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemModelRenderer.java similarity index 88% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemModelRenderer.java rename to common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemModelRenderer.java index 94c779707..33cd1843d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemModelRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemModelRenderer.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline.item; +package mod.azure.azurelib.core2.render.item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.Vec3; @@ -6,10 +6,10 @@ import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzModelRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzPhasedRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzPhasedRenderer; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; public class AzItemModelRenderer extends AzModelRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java index c64a8c574..2c0917352 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -23,9 +23,8 @@ import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; -import mod.azure.azurelib.core2.render.AzItemRendererConfig; +import mod.azure.azurelib.core2.render.entity.AzItemRendererConfig; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; -import mod.azure.azurelib.core2.render.pipeline.item.AzItemRendererPipeline; public abstract class AzItemRenderer extends BlockEntityWithoutLevelRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipeline.java similarity index 88% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java rename to common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipeline.java index 17bdc13f9..506e9d82a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipeline.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline.item; +package mod.azure.azurelib.core2.render.item; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.resources.ResourceLocation; @@ -8,12 +8,11 @@ import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core2.render.AzItemRendererConfig; +import mod.azure.azurelib.core2.render.AzLayerRenderer; import mod.azure.azurelib.core2.render.AzRendererConfig; -import mod.azure.azurelib.core2.render.item.AzItemRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzLayerRenderer; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.entity.AzItemRendererConfig; public class AzItemRendererPipeline extends AzRendererPipeline { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipelineContext.java similarity index 81% rename from common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipelineContext.java rename to common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipelineContext.java index c5541b9c8..2606822a8 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/pipeline/item/AzItemRendererPipelineContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipelineContext.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.pipeline.item; +package mod.azure.azurelib.core2.render.item; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; @@ -7,8 +7,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; public class AzItemRendererPipelineContext extends AzRendererPipelineContext { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java index 07814da7e..58449b127 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java @@ -26,7 +26,7 @@ import mod.azure.azurelib.common.internal.client.RenderProvider; import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; /** * Builtin class for handling dynamic armor rendering on AzureLib entities.
      diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java index 595f81de4..b46e3115b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java @@ -4,7 +4,7 @@ import mod.azure.azurelib.common.internal.common.cache.texture.AutoGlowingTexture; import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; /** * A {@link AzRenderLayer} dedicated to rendering the auto-generated glow layer functionality provided by AzureLib. This diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java index 250da7eab..a0c1f5360 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java @@ -11,8 +11,8 @@ import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; /** * A {@link AzRenderLayer} responsible for rendering {@link net.minecraft.world.level.block.state.BlockState diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java index 1d180b284..e180e7c27 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java @@ -4,8 +4,8 @@ import net.minecraft.client.renderer.MultiBufferSource; import mod.azure.azurelib.core2.model.AzBone; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipeline; -import mod.azure.azurelib.core2.render.pipeline.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; /** * Render layer base class for rendering additional layers of effects or textures over an existing model at runtime.
      diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java index f1e75a9f6..c95646dfe 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java @@ -3,7 +3,7 @@ import net.minecraft.resources.ResourceLocation; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.render.AzBlockEntityRendererConfig; +import mod.azure.azurelib.core2.render.block.AzBlockEntityRendererConfig; import mod.azure.azurelib.core2.render.block.AzBlockRenderer; public class StargateRender extends AzBlockRenderer { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java index 26e2b75e9..a98ac5b78 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java @@ -4,8 +4,8 @@ import net.minecraft.resources.ResourceLocation; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.render.AzEntityRendererConfig; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import mod.azure.azurelib.core2.render.entity.AzEntityRendererConfig; public class DoomHunterRenderer extends AzEntityRenderer { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneRenderer.java index 272590163..314b7f7ae 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/drone/DroneRenderer.java @@ -4,8 +4,8 @@ import net.minecraft.resources.ResourceLocation; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.render.AzEntityRendererConfig; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import mod.azure.azurelib.core2.render.entity.AzEntityRendererConfig; public class DroneRenderer extends AzEntityRenderer { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java index 33f6b5461..a47d06bcd 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java @@ -4,8 +4,8 @@ import net.minecraft.resources.ResourceLocation; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.render.AzEntityRendererConfig; import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import mod.azure.azurelib.core2.render.entity.AzEntityRendererConfig; import mod.azure.azurelib.core2.render.layer.AzAutoGlowingLayer; public class MarauderRenderer extends AzEntityRenderer { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java index 8e3242398..6b3159816 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java @@ -3,7 +3,7 @@ import net.minecraft.resources.ResourceLocation; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.render.AzItemRendererConfig; +import mod.azure.azurelib.core2.render.entity.AzItemRendererConfig; import mod.azure.azurelib.core2.render.item.AzItemRenderer; public class AzPistolRenderer extends AzItemRenderer { From 552bd5f2971e5e998d8b31759337d946a3e3d20f Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 10:07:36 -0500 Subject: [PATCH 150/224] AzRenderLayer is now an interface, type param cleanup. Signed-off-by: = --- .../core2/render/layer/AzArmorLayer.java | 24 +++++++++---------- .../render/layer/AzAutoGlowingLayer.java | 2 +- .../render/layer/AzBlockAndItemLayer.java | 12 +++++----- .../core2/render/layer/AzRenderLayer.java | 10 ++++---- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java index 58449b127..64d3eb8fa 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java @@ -33,7 +33,7 @@ * Supports both {@link GeoItem AzureLib} and {@link net.minecraft.world.item.ArmorItem Vanilla} armor models.
      * Unlike a traditional armor renderer, this renderer renders per-bone, giving much more flexible armor rendering. */ -public class AzArmorLayer extends AzRenderLayer { +public class AzArmorLayer implements AzRenderLayer { protected static final HumanoidModel INNER_ARMOR_MODEL = new HumanoidModel<>( Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR) @@ -62,7 +62,7 @@ public class AzArmorLayer extends AzRenderLayer { protected ItemStack bootsStack; @Override - public void preRender(AzRendererPipelineContext context) { + public void preRender(AzRendererPipelineContext context) { if (!(context.animatable() instanceof LivingEntity livingEntity)) return; this.mainHandStack = livingEntity.getItemBySlot(EquipmentSlot.MAINHAND); @@ -74,10 +74,10 @@ public void preRender(AzRendererPipelineContext context) { } @Override - public void render(AzRendererPipelineContext context) {} + public void render(AzRendererPipelineContext context) {} @Override - public void renderForBone(AzRendererPipelineContext context, AzBone bone) { + public void renderForBone(AzRendererPipelineContext context, AzBone bone) { ItemStack armorStack = getArmorItemForBone(context, bone); if (armorStack == null) @@ -153,7 +153,7 @@ protected EquipmentSlot getEquipmentSlotForBone(AzRendererPipelineContext contex * This is then transformed into position for the final render */ @NotNull - protected ModelPart getModelPartForBone(AzRendererPipelineContext context, HumanoidModel baseModel) { + protected ModelPart getModelPartForBone(AzRendererPipelineContext context, HumanoidModel baseModel) { return baseModel.body; } @@ -162,15 +162,15 @@ protected ModelPart getModelPartForBone(AzRendererPipelineContext context, Human * Return null if this bone should be ignored */ @Nullable - protected ItemStack getArmorItemForBone(AzRendererPipelineContext context, AzBone bone) { + protected ItemStack getArmorItemForBone(AzRendererPipelineContext context, AzBone bone) { return null; } /** * Renders an individual armor piece base on the given {@link AzBone} and {@link ItemStack} */ - protected void renderVanillaArmorPiece( - AzRendererPipelineContext context, + protected void renderVanillaArmorPiece( + AzRendererPipelineContext context, AzBone bone, EquipmentSlot slot, ItemStack armorStack, @@ -226,7 +226,7 @@ protected void renderVanillaArmorPiece( } protected VertexConsumer getVanillaArmorBuffer( - AzRendererPipelineContext context, + AzRendererPipelineContext context, ItemStack stack, EquipmentSlot slot, AzBone bone, @@ -246,7 +246,7 @@ protected VertexConsumer getVanillaArmorBuffer( */ @NotNull protected HumanoidModel getModelForItem( - AzRendererPipelineContext context, + AzRendererPipelineContext context, AzBone bone, EquipmentSlot slot, ItemStack stack @@ -261,7 +261,7 @@ protected HumanoidModel getModelForItem( * Render a given {@link AbstractSkullBlock} as a worn armor piece in relation to a given {@link AzBone} */ protected void renderSkullAsArmor( - AzRendererPipelineContext context, + AzRendererPipelineContext context, AzBone bone, ItemStack stack, AbstractSkullBlock skullBlock @@ -296,7 +296,7 @@ protected void renderSkullAsArmor( * @param bone The AzBone to base the translations on * @param sourcePart The ModelPart to translate */ - protected void prepModelPartForRender(AzRendererPipelineContext context, AzBone bone, ModelPart sourcePart) { + protected void prepModelPartForRender(AzRendererPipelineContext context, AzBone bone, ModelPart sourcePart) { final var firstCube = bone.getCubes().get(0); final var armorCube = sourcePart.cubes.get(0); final var armorBoneSizeX = firstCube.size().x(); diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java index b46e3115b..f68410ebc 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java @@ -10,7 +10,7 @@ * A {@link AzRenderLayer} dedicated to rendering the auto-generated glow layer functionality provided by AzureLib. This * utilizes texture files with the _glowing suffix to create glowing effects for models. */ -public class AzAutoGlowingLayer extends AzRenderLayer { +public class AzAutoGlowingLayer implements AzRenderLayer { @Override public void preRender(AzRendererPipelineContext context) {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java index a0c1f5360..99f5c0957 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java @@ -19,7 +19,7 @@ * BlockStates} or {@link net.minecraft.world.item.ItemStack ItemStacks} onto a specified {@link AzRendererPipeline}. * This layer handles the rendering of physical elements, such as blocks and items, associated with animation bones. */ -public class AzBlockAndItemLayer extends AzRenderLayer { +public class AzBlockAndItemLayer implements AzRenderLayer { protected final Function itemStackProvider; @@ -40,10 +40,10 @@ public AzBlockAndItemLayer( } @Override - public void preRender(AzRendererPipelineContext context) {} + public void preRender(AzRendererPipelineContext context) {} @Override - public void render(AzRendererPipelineContext context) {} + public void render(AzRendererPipelineContext context) {} /** * Renders an {@link ItemStack} or {@link BlockState} associated with the specified bone in the rendering context. @@ -57,7 +57,7 @@ public void render(AzRendererPipelineContext context) {} * @param bone the bone for which to render associated elements */ @Override - public void renderForBone(AzRendererPipelineContext context, AzBone bone) { + public void renderForBone(AzRendererPipelineContext context, AzBone bone) { var stack = itemStackForBone(bone); var blockState = blockStateForBone(bone); @@ -118,7 +118,7 @@ protected ItemDisplayContext getTransformTypeForStack(AzBone bone, ItemStack sta * @param bone the bone where the {@link ItemStack} will be rendered * @param itemStack the {@link ItemStack} to render */ - protected void renderItemForBone(AzRendererPipelineContext context, AzBone bone, ItemStack itemStack) { + protected void renderItemForBone(AzRendererPipelineContext context, AzBone bone, ItemStack itemStack) { if (context.animatable() instanceof LivingEntity livingEntity) { Minecraft.getInstance() .getItemRenderer() @@ -158,7 +158,7 @@ protected void renderItemForBone(AzRendererPipelineContext context, AzBone bone, * @param bone the bone where the {@link BlockState} will be rendered * @param blockState the {@link BlockState} to render */ - protected void renderBlockForBone(AzRendererPipelineContext context, AzBone bone, BlockState blockState) { + protected void renderBlockForBone(AzRendererPipelineContext context, AzBone bone, BlockState blockState) { context.poseStack().pushPose(); context.poseStack().translate(-0.25f, -0.25f, -0.25f); diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java index e180e7c27..d91580b3b 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java @@ -11,22 +11,20 @@ * Render layer base class for rendering additional layers of effects or textures over an existing model at runtime.
      * Contains the base boilerplate and helper code for various render layer features */ -public abstract class AzRenderLayer { - - public AzRenderLayer() {} +public interface AzRenderLayer { /** * This method is called by the {@link AzRendererPipeline} before rendering, immediately after * {@link AzRendererPipeline#preRender} has been called.
      * This allows for RenderLayers to perform pre-render manipulations such as hiding or showing bones */ - public abstract void preRender(AzRendererPipelineContext context); + void preRender(AzRendererPipelineContext context); /** * This is the method that is actually called by the render for your render layer to function.
      * This is called after the animatable has been rendered, but before supplementary rendering like nametags. */ - public abstract void render(AzRendererPipelineContext context); + void render(AzRendererPipelineContext context); /** * This method is called by the {@link AzRendererPipeline} for each bone being rendered.
      @@ -40,5 +38,5 @@ public AzRenderLayer() {} * If you do use it, and you render something that changes the {@link VertexConsumer buffer}, you need to * reset it back to the previous buffer using {@link MultiBufferSource#getBuffer} before ending the method */ - public abstract void renderForBone(AzRendererPipelineContext context, AzBone bone); + void renderForBone(AzRendererPipelineContext context, AzBone bone); } From c70742a47313991a6bed461f564c04d5a29e1686 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 10:10:07 -0500 Subject: [PATCH 151/224] How'd that get in there? lol Signed-off-by: = --- .../mod/azure/azurelib/core2/render/item/AzItemRenderer.java | 1 - .../core2/render/{entity => item}/AzItemRendererConfig.java | 2 +- .../azurelib/core2/render/item/AzItemRendererPipeline.java | 1 - .../azurelib/fabric/core2/example/items/AzPistolRenderer.java | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) rename common/src/main/java/mod/azure/azurelib/core2/render/{entity => item}/AzItemRendererConfig.java (98%) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java index 2c0917352..28d4109cd 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -23,7 +23,6 @@ import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; -import mod.azure.azurelib.core2.render.entity.AzItemRendererConfig; import mod.azure.azurelib.core2.render.layer.AzRenderLayer; public abstract class AzItemRenderer extends BlockEntityWithoutLevelRenderer { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzItemRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererConfig.java similarity index 98% rename from common/src/main/java/mod/azure/azurelib/core2/render/entity/AzItemRendererConfig.java rename to common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererConfig.java index 3b8497812..fcb15f2b4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzItemRendererConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererConfig.java @@ -1,4 +1,4 @@ -package mod.azure.azurelib.core2.render.entity; +package mod.azure.azurelib.core2.render.item; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipeline.java index 506e9d82a..8956ccfe2 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipeline.java @@ -12,7 +12,6 @@ import mod.azure.azurelib.core2.render.AzRendererConfig; import mod.azure.azurelib.core2.render.AzRendererPipeline; import mod.azure.azurelib.core2.render.AzRendererPipelineContext; -import mod.azure.azurelib.core2.render.entity.AzItemRendererConfig; public class AzItemRendererPipeline extends AzRendererPipeline { diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java index 6b3159816..2a00d63a5 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java @@ -3,8 +3,8 @@ import net.minecraft.resources.ResourceLocation; import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.core2.render.entity.AzItemRendererConfig; import mod.azure.azurelib.core2.render.item.AzItemRenderer; +import mod.azure.azurelib.core2.render.item.AzItemRendererConfig; public class AzPistolRenderer extends AzItemRenderer { From 3cb95a9fbdce4569122e748a0eed11e9b0de6760 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 10:10:50 -0500 Subject: [PATCH 152/224] AzBlockRenderer -> AzBlockEntityRenderer. Signed-off-by: = --- .../{AzBlockRenderer.java => AzBlockEntityRenderer.java} | 4 ++-- .../render/block/AzBlockEntityRendererPipeline.java | 9 ++++++--- .../fabric/core2/example/blocks/StargateRender.java | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) rename common/src/main/java/mod/azure/azurelib/core2/render/block/{AzBlockRenderer.java => AzBlockEntityRenderer.java} (94%) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java similarity index 94% rename from common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java rename to common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java index 45d20ad6b..5d8c71cf9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java @@ -12,7 +12,7 @@ import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; -public abstract class AzBlockRenderer implements BlockEntityRenderer { +public abstract class AzBlockEntityRenderer implements BlockEntityRenderer { private final AzBlockEntityRendererConfig config; @@ -21,7 +21,7 @@ public abstract class AzBlockRenderer implements BlockEnt @Nullable private AzBlockAnimator reusedAzBlockAnimator; - protected AzBlockRenderer(AzBlockEntityRendererConfig config) { + protected AzBlockEntityRenderer(AzBlockEntityRendererConfig config) { super(); this.config = config; this.rendererPipeline = new AzBlockEntityRendererPipeline<>(config, this); diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java index 797d1fd9e..75e024ef4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java @@ -15,13 +15,16 @@ public class AzBlockEntityRendererPipeline extends AzRendererPipeline { - private final AzBlockRenderer blockRenderer; + private final AzBlockEntityRenderer blockRenderer; protected Matrix4f entityRenderTranslations = new Matrix4f(); protected Matrix4f modelRenderTranslations = new Matrix4f(); - public AzBlockEntityRendererPipeline(AzBlockEntityRendererConfig config, AzBlockRenderer entityRenderer) { + public AzBlockEntityRendererPipeline( + AzBlockEntityRendererConfig config, + AzBlockEntityRenderer entityRenderer + ) { super(config); this.blockRenderer = entityRenderer; } @@ -75,7 +78,7 @@ public void preRender(AzRendererPipelineContext context, boolean isReRender) @Override public void postRender(AzRendererPipelineContext context, boolean isReRender) {} - public AzBlockRenderer getRenderer() { + public AzBlockEntityRenderer getRenderer() { return blockRenderer; } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java index c95646dfe..5c6be5dd1 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java @@ -3,10 +3,10 @@ import net.minecraft.resources.ResourceLocation; import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.render.block.AzBlockEntityRenderer; import mod.azure.azurelib.core2.render.block.AzBlockEntityRendererConfig; -import mod.azure.azurelib.core2.render.block.AzBlockRenderer; -public class StargateRender extends AzBlockRenderer { +public class StargateRender extends AzBlockEntityRenderer { private static final ResourceLocation MODEL = AzureLib.modResource("geo/block/stargate.geo.json"); From 63fed6f2e9bce89d96afa70708de80a1827ee462 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 10:41:14 -0500 Subject: [PATCH 153/224] Implemented AzProvider. Signed-off-by: = --- .../azurelib/core2/render/AzProvider.java | 56 +++++++ .../render/block/AzBlockEntityRenderer.java | 40 +---- .../core2/render/entity/AzEntityRenderer.java | 41 +---- .../render/item/AzItemGuiRenderUtil.java | 75 +++++++++ .../core2/render/item/AzItemRenderer.java | 150 +++--------------- 5 files changed, 164 insertions(+), 198 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/AzProvider.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemGuiRenderUtil.java diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzProvider.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzProvider.java new file mode 100644 index 000000000..483ea2235 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzProvider.java @@ -0,0 +1,56 @@ +package mod.azure.azurelib.core2.render; + +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; +import java.util.function.Supplier; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; + +public class AzProvider { + + private final Supplier> animatorSupplier; + + private final Function modelLocationProvider; + + public AzProvider( + Supplier> animatorSupplier, + Function modelLocationProvider + ) { + this.animatorSupplier = animatorSupplier; + this.modelLocationProvider = modelLocationProvider; + } + + public @Nullable AzBakedModel provideBakedModel(@NotNull T animatable) { + var modelResourceLocation = modelLocationProvider.apply(animatable); + return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); + } + + public @Nullable AzAnimator provideAnimator(T animatable) { + // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for the + // entity. + var accessor = AzAnimatorAccessor.cast(animatable); + var cachedAnimator = accessor.getAnimatorOrNull(); + + if (cachedAnimator == null) { + // If the cached animator is null, create a new one. We use a separate reference here just for some + cachedAnimator = animatorSupplier.get(); + + if (cachedAnimator != null) { + // If the new animator we created is not null, then register its controllers. + cachedAnimator.registerControllers( + cachedAnimator.getAnimationControllerContainer() + ); + // Also cache the animator so that the next time we fetch the animator, it's ready for us. + accessor.setAnimator(cachedAnimator); + } + } + + return cachedAnimator; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java index 5d8c71cf9..61d115a1c 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java @@ -7,14 +7,12 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.impl.AzBlockAnimator; -import mod.azure.azurelib.core2.model.AzBakedModel; -import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; +import mod.azure.azurelib.core2.render.AzProvider; public abstract class AzBlockEntityRenderer implements BlockEntityRenderer { - private final AzBlockEntityRendererConfig config; + private final AzProvider provider; private final AzBlockEntityRendererPipeline rendererPipeline; @@ -23,7 +21,7 @@ public abstract class AzBlockEntityRenderer implements Bl protected AzBlockEntityRenderer(AzBlockEntityRendererConfig config) { super(); - this.config = config; + this.provider = new AzProvider<>(config::createAnimator, config::modelLocation); this.rendererPipeline = new AzBlockEntityRendererPipeline<>(config, this); } @@ -36,8 +34,8 @@ public void render( int packedLight, int packedOverlay ) { - var cachedEntityAnimator = provideAnimator(entity); - var azBakedModel = provideBakedModel(entity); + var cachedEntityAnimator = (AzBlockAnimator) provider.provideAnimator(entity); + var azBakedModel = provider.provideBakedModel(entity); if (cachedEntityAnimator != null && azBakedModel != null) { cachedEntityAnimator.setActiveModel(azBakedModel); @@ -60,34 +58,6 @@ public void render( ); } - protected @Nullable AzBakedModel provideBakedModel(@NotNull T entity) { - var modelResourceLocation = config.modelLocation(entity); - return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); - } - - protected @Nullable AzBlockAnimator provideAnimator(T entity) { - // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for the - // entity. - var accessor = AzAnimatorAccessor.cast(entity); - var cachedBlockEntityAnimator = (AzBlockAnimator) accessor.getAnimatorOrNull(); - - if (cachedBlockEntityAnimator == null) { - // If the cached animator is null, create a new one. We use a separate reference here just for some - cachedBlockEntityAnimator = (AzBlockAnimator) config.createAnimator(); - - if (cachedBlockEntityAnimator != null) { - // If the new animator we created is not null, then register its controllers. - cachedBlockEntityAnimator.registerControllers( - cachedBlockEntityAnimator.getAnimationControllerContainer() - ); - // Also cache the animator so that the next time we fetch the animator, it's ready for us. - accessor.setAnimator(cachedBlockEntityAnimator); - } - } - - return cachedBlockEntityAnimator; - } - public AzBlockAnimator getAnimator() { return reusedAzBlockAnimator; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java index 9ef260b32..93d020b21 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -10,23 +10,24 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; -import mod.azure.azurelib.core2.model.AzBakedModel; -import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; +import mod.azure.azurelib.core2.render.AzProvider; public abstract class AzEntityRenderer extends EntityRenderer { - private final AzEntityRendererPipeline rendererPipeline; - private final AzEntityRendererConfig config; + private final AzProvider provider; + + private final AzEntityRendererPipeline rendererPipeline; + @Nullable private AzEntityAnimator reusedAzEntityAnimator; protected AzEntityRenderer(AzEntityRendererConfig config, EntityRendererProvider.Context context) { super(context); this.config = config; + this.provider = new AzProvider<>(config::createAnimator, config::modelLocation); this.rendererPipeline = new AzEntityRendererPipeline<>(config, this); } @@ -55,8 +56,8 @@ public void render( @NotNull MultiBufferSource bufferSource, int packedLight ) { - var cachedEntityAnimator = provideAnimator(entity); - var azBakedModel = provideBakedModel(entity); + var cachedEntityAnimator = (AzEntityAnimator) provider.provideAnimator(entity); + var azBakedModel = provider.provideBakedModel(entity); if (cachedEntityAnimator != null && azBakedModel != null) { cachedEntityAnimator.setActiveModel(azBakedModel); @@ -79,32 +80,6 @@ public void render( ); } - protected @Nullable AzBakedModel provideBakedModel(@NotNull T entity) { - var modelResourceLocation = config.modelLocation(entity); - return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); - } - - private @Nullable AzEntityAnimator provideAnimator(T entity) { - // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for the - // entity. - var accessor = AzAnimatorAccessor.cast(entity); - var cachedEntityAnimator = (AzEntityAnimator) accessor.getAnimatorOrNull(); - - if (cachedEntityAnimator == null) { - // If the cached animator is null, create a new one. We use a separate reference here just for some - cachedEntityAnimator = (AzEntityAnimator) config.createAnimator(); - - if (cachedEntityAnimator != null) { - // If the new animator we created is not null, then register its controllers. - cachedEntityAnimator.registerControllers(cachedEntityAnimator.getAnimationControllerContainer()); - // Also cache the animator so that the next time we fetch the animator, it's ready for us. - accessor.setAnimator(cachedEntityAnimator); - } - } - - return cachedEntityAnimator; - } - /** * Whether the entity's nametag should be rendered or not.
      * Pretty much exclusively used in {@link EntityRenderer#renderNameTag} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemGuiRenderUtil.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemGuiRenderUtil.java new file mode 100644 index 000000000..a38418e29 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemGuiRenderUtil.java @@ -0,0 +1,75 @@ +package mod.azure.azurelib.core2.render.item; + +import com.mojang.blaze3d.platform.Lighting; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; + +import mod.azure.azurelib.core2.model.AzBakedModel; + +public class AzItemGuiRenderUtil { + + /** + * Wrapper method to handle rendering the item in a GUI context (defined by + * {@link net.minecraft.world.item.ItemDisplayContext#GUI} normally).
      + * Just includes some additional required transformations and settings. + */ + public static void renderInGui( + AzItemRendererConfig config, + AzItemRendererPipeline rendererPipeline, + ItemStack animatable, + AzBakedModel azBakedModel, + ItemStack currentItemStack, + ItemDisplayContext transformType, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight, + int packedOverlay + ) { + if (config.useEntityGuiLighting()) { + Lighting.setupForEntityInInventory(); + } else { + Lighting.setupForFlatItems(); + } + MultiBufferSource.BufferSource defaultBufferSource = + bufferSource instanceof MultiBufferSource.BufferSource bufferSource2 + ? bufferSource2 + : Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); + RenderType renderType = rendererPipeline.context() + .getDefaultRenderType( + animatable, + config.textureLocation(animatable), + defaultBufferSource, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() + ); + VertexConsumer buffer = ItemRenderer.getFoilBufferDirect( + bufferSource, + renderType, + true, + currentItemStack != null && currentItemStack.hasFoil() + ); + + poseStack.pushPose(); + rendererPipeline.render( + poseStack, + azBakedModel, + animatable, + defaultBufferSource, + renderType, + buffer, + 0, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), + packedLight + ); + defaultBufferSource.endBatch(); + RenderSystem.enableDepthTest(); + Lighting.setupFor3DItems(); + poseStack.popPose(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java index 28d4109cd..f58aa62fb 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -1,15 +1,10 @@ package mod.azure.azurelib.core2.render.item; -import com.mojang.blaze3d.platform.Lighting; -import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.client.Minecraft; import net.minecraft.client.model.geom.EntityModelSet; import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.world.item.ItemDisplayContext; @@ -17,21 +12,16 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; - -import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; -import mod.azure.azurelib.core2.model.AzBakedModel; -import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; -import mod.azure.azurelib.core2.render.layer.AzRenderLayer; +import mod.azure.azurelib.core2.render.AzProvider; public abstract class AzItemRenderer extends BlockEntityWithoutLevelRenderer { - private final AzItemRendererPipeline rendererPipeline; + private final AzItemRendererConfig config; - private final List> renderLayers; + private final AzProvider provider; - private final AzItemRendererConfig config; + private final AzItemRendererPipeline rendererPipeline; @Nullable private AzItemAnimator reusedAzItemAnimator; @@ -51,7 +41,7 @@ protected AzItemRenderer( ) { super(dispatcher, modelSet); this.rendererPipeline = new AzItemRendererPipeline(config, this); - this.renderLayers = new ObjectArrayList<>(); + this.provider = new AzProvider<>(config::createAnimator, config::modelLocation); this.config = config; } @@ -64,25 +54,25 @@ public void renderByItem( int packedLight, int packedOverlay ) { - @SuppressWarnings("unchecked") - var animatable = stack; // TODO: What was this used for? var renderPerspective = transformType; - var cachedEntityAnimator = provideAnimator(stack, animatable); - var azBakedModel = provideBakedModel(animatable); + var cachedEntityAnimator = (AzItemAnimator) provider.provideAnimator(stack); + var model = provider.provideBakedModel(stack); - if (cachedEntityAnimator != null && azBakedModel != null) { - cachedEntityAnimator.setActiveModel(azBakedModel); + if (cachedEntityAnimator != null && model != null) { + cachedEntityAnimator.setActiveModel(model); } // Point the renderer's current animator reference to the cached entity animator before rendering. reusedAzItemAnimator = cachedEntityAnimator; if (transformType == ItemDisplayContext.GUI) { - renderInGui( - animatable, - azBakedModel, + AzItemGuiRenderUtil.renderInGui( + config, + rendererPipeline, + stack, + model, stack, transformType, poseStack, @@ -91,13 +81,10 @@ public void renderByItem( packedOverlay ); } else { + var partialTick = Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(); + var textureLocation = config.textureLocation(stack); var renderType = rendererPipeline.context() - .getDefaultRenderType( - animatable, - config.textureLocation(animatable), - bufferSource, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() - ); + .getDefaultRenderType(stack, textureLocation, bufferSource, partialTick); var buffer = ItemRenderer.getFoilBufferDirect( bufferSource, renderType, @@ -108,115 +95,18 @@ public void renderByItem( rendererPipeline.render( poseStack, - azBakedModel, - animatable, + model, + stack, bufferSource, renderType, buffer, 0, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), + partialTick, packedLight ); } } - /** - * Wrapper method to handle rendering the item in a GUI context (defined by - * {@link net.minecraft.world.item.ItemDisplayContext#GUI} normally).
      - * Just includes some additional required transformations and settings. - */ - protected void renderInGui( - ItemStack animatable, - AzBakedModel azBakedModel, - ItemStack currentItemStack, - ItemDisplayContext transformType, - PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight, - int packedOverlay - ) { - if (config.useEntityGuiLighting()) { - Lighting.setupForEntityInInventory(); - } else { - Lighting.setupForFlatItems(); - } - MultiBufferSource.BufferSource defaultBufferSource = - bufferSource instanceof MultiBufferSource.BufferSource bufferSource2 - ? bufferSource2 - : Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); - RenderType renderType = rendererPipeline.context() - .getDefaultRenderType( - animatable, - config.textureLocation(animatable), - defaultBufferSource, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() - ); - VertexConsumer buffer = ItemRenderer.getFoilBufferDirect( - bufferSource, - renderType, - true, - currentItemStack != null && currentItemStack.hasFoil() - ); - - poseStack.pushPose(); - rendererPipeline.render( - poseStack, - azBakedModel, - animatable, - defaultBufferSource, - renderType, - buffer, - 0, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), - packedLight - ); - defaultBufferSource.endBatch(); - RenderSystem.enableDepthTest(); - Lighting.setupFor3DItems(); - poseStack.popPose(); - } - - protected @Nullable AzBakedModel provideBakedModel(@NotNull ItemStack item) { - var modelResourceLocation = config.modelLocation(item); - return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); - } - - protected @Nullable AzItemAnimator provideAnimator(ItemStack itemStack, ItemStack item) { - // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for - // the item. - var accessor = AzAnimatorAccessor.cast(itemStack); - var cachedItemAnimator = (AzItemAnimator) accessor.getAnimatorOrNull(); - - if (cachedItemAnimator == null) { - // If the cached animator is null, create a new one. We use a separate reference here just for some - cachedItemAnimator = (AzItemAnimator) config.createAnimator(); - - if (cachedItemAnimator != null) { - // If the new animator we created is not null, then register its controllers. - cachedItemAnimator.registerControllers(cachedItemAnimator.getAnimationControllerContainer()); - // Also cache the animator so that the next time we fetch the animator, it's ready for us. - accessor.setAnimator(cachedItemAnimator); - } - } - - return cachedItemAnimator; - } - - /** - * Returns the list of registered {@link AzRenderLayer GeoRenderLayers} for this renderer - */ - public List> getRenderLayers() { - return renderLayers; - } - - /** - * Adds a {@link AzRenderLayer} to this renderer, to be called after the main model is rendered each frame - */ - public AzItemRenderer addRenderLayer(AzRenderLayer renderLayer) { - this.renderLayers.add(renderLayer); - return this; - } - public @Nullable AzItemAnimator getAnimator() { return reusedAzItemAnimator; } From 5c0c2a14dd76c05ee13e983e72597ba886a6c261 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Fri, 20 Dec 2024 11:04:54 -0500 Subject: [PATCH 154/224] Refactor. Signed-off-by: = --- .../internal/mixins/MixinItemRenderer.java | 5 +- .../render/item/AzItemGuiRenderUtil.java | 56 ++++------- .../core2/render/item/AzItemRenderer.java | 96 +++++++------------ 3 files changed, 55 insertions(+), 102 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java index 457fcd457..d51e59e8a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java @@ -54,7 +54,10 @@ public void itemModelHook( var renderer = AzItemRendererRegistry.getOrNull(item); if (renderer != null) { - renderer.renderByItem(itemStack, transformType, poseStack, multiBufferSource, i, j); + switch (transformType) { + case GUI -> renderer.renderByGui(itemStack, poseStack, multiBufferSource, i); + default -> renderer.renderByItem(itemStack, poseStack, multiBufferSource, i); + } } } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemGuiRenderUtil.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemGuiRenderUtil.java index a38418e29..701c910d4 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemGuiRenderUtil.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemGuiRenderUtil.java @@ -3,12 +3,9 @@ import com.mojang.blaze3d.platform.Lighting; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; import mod.azure.azurelib.core2.model.AzBakedModel; @@ -23,53 +20,38 @@ public class AzItemGuiRenderUtil { public static void renderInGui( AzItemRendererConfig config, AzItemRendererPipeline rendererPipeline, - ItemStack animatable, - AzBakedModel azBakedModel, + ItemStack stack, + AzBakedModel model, ItemStack currentItemStack, - ItemDisplayContext transformType, PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight, - int packedOverlay + MultiBufferSource source, + int packedLight ) { if (config.useEntityGuiLighting()) { Lighting.setupForEntityInInventory(); } else { Lighting.setupForFlatItems(); } - MultiBufferSource.BufferSource defaultBufferSource = - bufferSource instanceof MultiBufferSource.BufferSource bufferSource2 - ? bufferSource2 + + var partialTick = Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(); + var bSource = + source instanceof MultiBufferSource.BufferSource bufferSource + ? bufferSource : Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); - RenderType renderType = rendererPipeline.context() - .getDefaultRenderType( - animatable, - config.textureLocation(animatable), - defaultBufferSource, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() - ); - VertexConsumer buffer = ItemRenderer.getFoilBufferDirect( - bufferSource, - renderType, - true, - currentItemStack != null && currentItemStack.hasFoil() - ); + var textureLocation = config.textureLocation(stack); + var renderType = rendererPipeline.context() + .getDefaultRenderType(stack, textureLocation, bSource, partialTick); + var withGlint = currentItemStack != null && currentItemStack.hasFoil(); + var buffer = ItemRenderer.getFoilBufferDirect(source, renderType, true, withGlint); poseStack.pushPose(); - rendererPipeline.render( - poseStack, - azBakedModel, - animatable, - defaultBufferSource, - renderType, - buffer, - 0, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), - packedLight - ); - defaultBufferSource.endBatch(); + + rendererPipeline.render(poseStack, model, stack, bSource, renderType, buffer, 0, partialTick, packedLight); + + bSource.endBatch(); RenderSystem.enableDepthTest(); Lighting.setupFor3DItems(); + poseStack.popPose(); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java index f58aa62fb..2d778d8b0 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -2,20 +2,17 @@ import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.Minecraft; -import net.minecraft.client.model.geom.EntityModelSet; -import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; +import mod.azure.azurelib.core2.model.AzBakedModel; import mod.azure.azurelib.core2.render.AzProvider; -public abstract class AzItemRenderer extends BlockEntityWithoutLevelRenderer { +public abstract class AzItemRenderer { private final AzItemRendererConfig config; @@ -26,39 +23,49 @@ public abstract class AzItemRenderer extends BlockEntityWithoutLevelRenderer { @Nullable private AzItemAnimator reusedAzItemAnimator; - protected AzItemRenderer(AzItemRendererConfig config) { - this( - config, - Minecraft.getInstance().getBlockEntityRenderDispatcher(), - Minecraft.getInstance().getEntityModels() - ); - } - protected AzItemRenderer( - AzItemRendererConfig config, - BlockEntityRenderDispatcher dispatcher, - EntityModelSet modelSet + AzItemRendererConfig config ) { - super(dispatcher, modelSet); this.rendererPipeline = new AzItemRendererPipeline(config, this); this.provider = new AzProvider<>(config::createAnimator, config::modelLocation); this.config = config; } - @Override + public void renderByGui( + ItemStack stack, + @NotNull PoseStack poseStack, + @NotNull MultiBufferSource source, + int packedLight + ) { + var model = provider.provideBakedModel(stack); + + prepareAnimator(stack, model); + + AzItemGuiRenderUtil.renderInGui(config, rendererPipeline, stack, model, stack, poseStack, source, packedLight); + } + public void renderByItem( ItemStack stack, - @NotNull ItemDisplayContext transformType, @NotNull PoseStack poseStack, - @NotNull MultiBufferSource bufferSource, - int packedLight, - int packedOverlay + @NotNull MultiBufferSource source, + int packedLight ) { - // TODO: What was this used for? - var renderPerspective = transformType; + var model = provider.provideBakedModel(stack); + var partialTick = Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(); + var textureLocation = config.textureLocation(stack); + var renderType = rendererPipeline.context() + .getDefaultRenderType(stack, textureLocation, source, partialTick); + // TODO: Why the null check here? + var withGlint = stack != null && stack.hasFoil(); + var buffer = ItemRenderer.getFoilBufferDirect(source, renderType, false, withGlint); + + prepareAnimator(stack, model); + + rendererPipeline.render(poseStack, model, stack, source, renderType, buffer, 0, partialTick, packedLight); + } + private void prepareAnimator(ItemStack stack, AzBakedModel model) { var cachedEntityAnimator = (AzItemAnimator) provider.provideAnimator(stack); - var model = provider.provideBakedModel(stack); if (cachedEntityAnimator != null && model != null) { cachedEntityAnimator.setActiveModel(model); @@ -66,45 +73,6 @@ public void renderByItem( // Point the renderer's current animator reference to the cached entity animator before rendering. reusedAzItemAnimator = cachedEntityAnimator; - - if (transformType == ItemDisplayContext.GUI) { - AzItemGuiRenderUtil.renderInGui( - config, - rendererPipeline, - stack, - model, - stack, - transformType, - poseStack, - bufferSource, - packedLight, - packedOverlay - ); - } else { - var partialTick = Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(); - var textureLocation = config.textureLocation(stack); - var renderType = rendererPipeline.context() - .getDefaultRenderType(stack, textureLocation, bufferSource, partialTick); - var buffer = ItemRenderer.getFoilBufferDirect( - bufferSource, - renderType, - false, - // TODO: Why the null check here? - stack != null && stack.hasFoil() - ); - - rendererPipeline.render( - poseStack, - model, - stack, - bufferSource, - renderType, - buffer, - 0, - partialTick, - packedLight - ); - } } public @Nullable AzItemAnimator getAnimator() { From a02aa83ee7c00ed7bd4ff04f569ca0b0776158b8 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 21 Dec 2024 02:52:34 -0500 Subject: [PATCH 155/224] Prep for az doom armor. Signed-off-by: = --- .../azurelib/models/item/az_doomicorn_boots.json | 6 ++++++ .../models/item/az_doomicorn_chestplate.json | 6 ++++++ .../azurelib/models/item/az_doomicorn_helmet.json | 6 ++++++ .../models/item/az_doomicorn_leggings.json | 6 ++++++ .../azurelib/textures/item/az_doomicorn_boots.png | Bin 0 -> 136 bytes .../textures/item/az_doomicorn_chestplate.png | Bin 0 -> 338 bytes .../textures/item/az_doomicorn_helmet.png | Bin 0 -> 503 bytes .../textures/item/az_doomicorn_leggings.png | Bin 0 -> 139 bytes 8 files changed, 24 insertions(+) create mode 100644 common/src/main/resources/assets/azurelib/models/item/az_doomicorn_boots.json create mode 100644 common/src/main/resources/assets/azurelib/models/item/az_doomicorn_chestplate.json create mode 100644 common/src/main/resources/assets/azurelib/models/item/az_doomicorn_helmet.json create mode 100644 common/src/main/resources/assets/azurelib/models/item/az_doomicorn_leggings.json create mode 100644 common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_boots.png create mode 100644 common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_chestplate.png create mode 100644 common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_helmet.png create mode 100644 common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_leggings.png diff --git a/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_boots.json b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_boots.json new file mode 100644 index 000000000..befab1952 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_boots" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_chestplate.json b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_chestplate.json new file mode 100644 index 000000000..96425b55a --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_chestplate" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_helmet.json b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_helmet.json new file mode 100644 index 000000000..0229c662d --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_helmet.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_helmet" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_leggings.json b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_leggings.json new file mode 100644 index 000000000..1afbd089c --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_leggings" + } +} diff --git a/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_boots.png b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_boots.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb401b3b7c07bad70354a4b77649c2b840ccdc8 GIT binary patch literal 136 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9JOMr-u0ZL4Lsu|2a5La|ZYV`Rbl7jv*Ddk{y_PBxmvQ^cb!(P;wEOnZPT^n;-xr8in|J c6f=G?s@`Q!ymNKoe4rKvPgg&ebxsLQ0Q|5bX8-^I literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_chestplate.png b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_chestplate.png new file mode 100644 index 0000000000000000000000000000000000000000..45562d9718955c8fbd368a18f64dbc719074afb6 GIT binary patch literal 338 zcmV-Y0j>UtP)F1LIeVqV_tpJ<<|Nrgn>!kpXp#Y5h{QRB(g7ozA%FMu$1bOlD@Rb01q5z56*wFd; z__M8g3g+uYRm_x6wmaOCCS_xSeo^z)PedYS=! z^YikGiG`sMeaXqhq@m?B kYkHijVXVdqcf)|ECc-EPMph;4;Q#;t07*qoM6N<$f;p_C3IG5A literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_helmet.png b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_helmet.png new file mode 100644 index 0000000000000000000000000000000000000000..c969da1462109167051b4cf6bbb7a95d7f03d85a GIT binary patch literal 503 zcmVAcnK_+8dYQH}NJC5uGH6INpbI~Pm!)DzFfne8#`uvm!Ika|>Pk26L|j;d zX@ay?TCvcfH=&)GV{D8G(7Lek?4RFx^Iil)J~3pT{{uXE`bd?Edwkt0@MFIP2&B}R zn?KF%TlWrqdaQzHD-YFfd5iq}RXigEQliNaBhdu56~{{1+_--CPwo(~^5U_ob()k5 z>+F1dOW2Gf!(mVYO*iPqVvL>0GHGYIa%riTJpwGNcRL$wyA>upL8nn8@IAbCi^jJK zZD*P(XO8*AUw~Ji*Vu5&Oe8Io@1cT#An@@I4(N`K;8+>Xr=|v1@TQdGLv@po9wHKn zAf@b0S_pv`_&CvVE?B1q1MBV=a@(6!>n>)(#4rq$QV0YF8q@JKv&qb0pt@V8P_Ix_ z`zWEI34ubP0VfHQjg4a^(_FoLvwsuwtFQU)mWj@sBk)a>FA=(jCiiINb0i`uGG{Nc zaP3Zip!8{tx?5w^c4#)B+X1ZyH0inpVrHDN$yt^b9~=jMHS77yWz}kWl#2D=o7nD6 tTh|3MXVTbqjKzif{TJz94r}OR`U#`sxe@0ys=)vN002ovPDHLkV1o16=w|=` literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_leggings.png b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_leggings.png new file mode 100644 index 0000000000000000000000000000000000000000..5d252cff21c34684e7b62c949585c39b804dd715 GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`L7py-Ar-f-2D&mHFc9#zRucXg z@INjs$>)o-F>BrN_UnoU4gxHqVh<|g^xgCP=k-mrXsj0zn0tJ}ay5m_d0G#4)m46D mdzrq!K(1-YS`i+bRw>C?{(lv_eYOHkXYh3Ob6Mw<&;$U>X)TQa literal 0 HcmV?d00001 From 39bdc4828fd5af983a363fefc757101f08d87cf8 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 21 Dec 2024 02:58:46 -0500 Subject: [PATCH 156/224] Add TODO. Signed-off-by: = --- .../core2/animation/controller/AzAnimationController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java index 06cb0eac7..66e361f83 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -233,6 +233,7 @@ public void update(AzAnimationContext context) { // Run state machine updates. stateMachine.update(); + // TODO: Is this if-block necessary? if (currentAnimation == null) { if (animationQueue.isEmpty()) { // If there is no animation to play, stop. From ea61dd56fee2eb81765d934907dd8c27396bb9cc Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 21 Dec 2024 02:59:42 -0500 Subject: [PATCH 157/224] Cleaned up AzBlockEntityRenderer and AzBlockEntityRendererPipeline. Signed-off-by: = --- .../render/block/AzBlockEntityRenderer.java | 21 +++++-------------- .../block/AzBlockEntityRendererPipeline.java | 8 +++---- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java index 61d115a1c..d1260ff5d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java @@ -20,7 +20,6 @@ public abstract class AzBlockEntityRenderer implements Bl private AzBlockAnimator reusedAzBlockAnimator; protected AzBlockEntityRenderer(AzBlockEntityRendererConfig config) { - super(); this.provider = new AzProvider<>(config::createAnimator, config::modelLocation); this.rendererPipeline = new AzBlockEntityRendererPipeline<>(config, this); } @@ -30,32 +29,22 @@ public void render( @NotNull T entity, float partialTick, @NotNull PoseStack poseStack, - @NotNull MultiBufferSource multiBufferSource, + @NotNull MultiBufferSource source, int packedLight, int packedOverlay ) { var cachedEntityAnimator = (AzBlockAnimator) provider.provideAnimator(entity); - var azBakedModel = provider.provideBakedModel(entity); + var model = provider.provideBakedModel(entity); - if (cachedEntityAnimator != null && azBakedModel != null) { - cachedEntityAnimator.setActiveModel(azBakedModel); + if (cachedEntityAnimator != null && model != null) { + cachedEntityAnimator.setActiveModel(model); } // Point the renderer's current animator reference to the cached entity animator before rendering. reusedAzBlockAnimator = cachedEntityAnimator; // Execute the render pipeline. - rendererPipeline.render( - poseStack, - azBakedModel, - entity, - multiBufferSource, - null, - null, - 0, - partialTick, - packedLight - ); + rendererPipeline.render(poseStack, model, entity, source, null, null, 0, partialTick, packedLight); } public AzBlockAnimator getAnimator() { diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java index 75e024ef4..752b9562a 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java @@ -15,7 +15,7 @@ public class AzBlockEntityRendererPipeline extends AzRendererPipeline { - private final AzBlockEntityRenderer blockRenderer; + private final AzBlockEntityRenderer blockEntityRenderer; protected Matrix4f entityRenderTranslations = new Matrix4f(); @@ -23,10 +23,10 @@ public class AzBlockEntityRendererPipeline extends AzRend public AzBlockEntityRendererPipeline( AzBlockEntityRendererConfig config, - AzBlockEntityRenderer entityRenderer + AzBlockEntityRenderer blockEntityRenderer ) { super(config); - this.blockRenderer = entityRenderer; + this.blockEntityRenderer = blockEntityRenderer; } @Override @@ -79,6 +79,6 @@ public void preRender(AzRendererPipelineContext context, boolean isReRender) public void postRender(AzRendererPipelineContext context, boolean isReRender) {} public AzBlockEntityRenderer getRenderer() { - return blockRenderer; + return blockEntityRenderer; } } From 81dde7143af566619edd041dedda66ba5aea97b4 Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 21 Dec 2024 03:00:04 -0500 Subject: [PATCH 158/224] Cleaned up AzDispatchExecutor, added logs. Signed-off-by: = --- .../dispatch/AzDispatchExecutor.java | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java index cfa9a8470..ed47dcc28 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchExecutor.java @@ -24,7 +24,11 @@ public record AzDispatchExecutor( public void sendForEntity(Entity entity) { if (!canNotProceed(entity)) { - // TODO: Log here. + AzureLib.LOGGER.warn( + "Could not dispatch animation command for entity. Origin: {}, Entity: {}", + origin, + entity.getType().toShortString() + ); return; } @@ -36,7 +40,11 @@ public void sendForEntity(Entity entity) { public void sendForBlockEntity(BlockEntity entity) { if (!canNotProceed(entity)) { - // TODO: Log here. + AzureLib.LOGGER.warn( + "Could not dispatch animation command for block entity. Origin: {}, Block Entity: {}", + origin, + entity.getType() + ); return; } @@ -48,7 +56,12 @@ public void sendForBlockEntity(BlockEntity entity) { public void sendForItem(Entity entity, ItemStack itemStack) { if (!canNotProceed(entity)) { - // TODO: Log here. + AzureLib.LOGGER.warn( + "Could not dispatch animation command for item. Origin: {}, Entity: {}, Item: {}", + origin, + entity.getType().toShortString(), + itemStack.getItem() + ); return; } @@ -76,9 +89,7 @@ private void dispatchFromClient(T animatable) { var animator = AzAnimatorAccessor.getOrNull(animatable); if (animator != null) { - commands.forEach(command -> { - command.getActions().forEach(action -> action.handle(animator)); - }); + commands.forEach(command -> command.getActions().forEach(action -> action.handle(animator))); } } @@ -96,7 +107,7 @@ private void handleServerDispatchForBlockEntity(BlockEntity entity) { var entityBlockPos = entity.getBlockPos(); commands.forEach(command -> { - // TODO: Buffer commands together. + // TODO: Batch commands together. var packet = new AzBlockEntityDispatchCommandPacket(entityBlockPos, command, origin); Services.NETWORK.sendToEntitiesTrackingChunk(packet, (ServerLevel) entity.getLevel(), entityBlockPos); }); @@ -105,21 +116,21 @@ private void handleServerDispatchForBlockEntity(BlockEntity entity) { private void handleServerDispatchForItem(Entity entity, ItemStack itemStack) { var uuid = itemStack.get(AzureLib.AZ_ID.get()); commands.forEach(command -> { - // TODO: Buffer commands together. + // TODO: Batch commands together. var packet = new AzItemStackDispatchCommandPacket(uuid, command, origin); Services.NETWORK.sendToTrackingEntityAndSelf(packet, entity); }); } - private boolean isClientSide(T animatable) { - if (animatable instanceof Entity entity) { + private boolean isClientSide(T levelHolder) { + if (levelHolder instanceof Entity entity) { return entity.level().isClientSide(); } - if (animatable instanceof BlockEntity entity) { + if (levelHolder instanceof BlockEntity entity) { return entity.getLevel().isClientSide(); } - throw new IllegalArgumentException("Unhandled animatable type: " + animatable); + throw new IllegalArgumentException("Unhandled animatable type: " + levelHolder); } } From 90d6e01f69ca99a0523462cc9e105ac0819f013c Mon Sep 17 00:00:00 2001 From: Boston Vanseghi Date: Sat, 21 Dec 2024 03:17:11 -0500 Subject: [PATCH 159/224] Implemented armor rendering (animations broken). Signed-off-by: = --- .../mixins/MixinHumanoidArmorLayer.java | 47 +++-- .../core2/render/armor/AzArmorModel.java | 74 +++++++ .../render/armor/AzArmorModelRenderer.java | 80 +++++++ .../core2/render/armor/AzArmorRenderer.java | 77 +++++++ .../render/armor/AzArmorRendererConfig.java | 93 ++++++++ .../render/armor/AzArmorRendererPipeline.java | 131 ++++++++++++ .../armor/AzArmorRendererPipelineContext.java | 96 +++++++++ .../render/armor/AzArmorRendererRegistry.java | 28 +++ .../render/armor/bone/AzArmorBoneContext.java | 198 ++++++++++++++++++ .../armor/bone/AzArmorBoneProvider.java | 97 +++++++++ .../bone/AzDefaultArmorBoneProvider.java | 49 +++++ .../render/item/AzItemRendererRegistry.java | 14 +- .../core2/render/layer/AzArmorLayer.java | 179 +++++++++------- .../azure/azurelib/fabric/ClientListener.java | 7 +- .../azurelib/fabric/FabricAzureLibMod.java | 45 +++- .../core2/example/armors/AzDoomArmor.java | 44 ++++ .../AzDoomArmorAnimationDispatcher.java | 18 ++ .../example/armors/AzDoomArmorAnimator.java | 36 ++++ .../armors/AzDoomArmorBoneProvider.java | 30 +++ .../example/armors/AzDoomArmorRenderer.java | 23 ++ .../mixins/MixinHumanoidArmorLayer.java | 40 ++-- 21 files changed, 1285 insertions(+), 121 deletions(-) create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModel.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModelRenderer.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRenderer.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererConfig.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipeline.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipelineContext.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererRegistry.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneContext.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneProvider.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzDefaultArmorBoneProvider.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmor.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimationDispatcher.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimator.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorBoneProvider.java create mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorRenderer.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java index 010718698..35e25c696 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java @@ -10,7 +10,6 @@ import com.llamalad7.mixinextras.sugar.ref.LocalRef; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.model.HumanoidModel; -import net.minecraft.client.model.Model; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer; import net.minecraft.client.renderer.texture.OverlayTexture; @@ -28,6 +27,7 @@ import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; import mod.azure.azurelib.common.api.common.animatable.GeoItem; import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.core2.render.armor.AzArmorRendererRegistry; /** * @deprecated @@ -67,29 +67,38 @@ public abstract class MixinHumanoidArmorLayer itemBySlotRef ) { - final ItemStack stack = itemBySlotRef.get(); - final Model geckolibModel = RenderProvider.of(stack) - .getGenericArmorModel( - entity, - stack, - equipmentSlot, - (HumanoidModel) baseModel - ); + var stack = itemBySlotRef.get(); + var renderProvider = RenderProvider.of(stack); + @SuppressWarnings("unchecked") + var humanoidModel = (HumanoidModel) baseModel; + var geckolibModel = renderProvider + .getGenericArmorModel(entity, stack, equipmentSlot, humanoidModel); + var i2 = stack.is( + ItemTags.DYEABLE + ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(stack, -6265536)) : -1; if (geckolibModel != null && stack.getItem() instanceof GeoItem) { - if (geckolibModel instanceof GeoArmorRenderer geoArmorRenderer) + if (geckolibModel instanceof GeoArmorRenderer geoArmorRenderer) { geoArmorRenderer.prepForRender(entity, stack, equipmentSlot, baseModel); + } baseModel.copyPropertiesTo((A) geckolibModel); - geckolibModel.renderToBuffer( - poseStack, - null, - packedLight, - OverlayTexture.NO_OVERLAY, - stack.is( - ItemTags.DYEABLE - ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(stack, -6265536)) : -1 - ); + + geckolibModel.renderToBuffer(poseStack, null, packedLight, OverlayTexture.NO_OVERLAY, i2); + ci.cancel(); + } + + var renderer = AzArmorRendererRegistry.getOrNull(stack.getItem()); + + if (renderer != null) { + var rendererPipeline = renderer.rendererPipeline(); + var armorModel = rendererPipeline.armorModel(); + @SuppressWarnings("unchecked") + var typedHumanoidModel = (HumanoidModel) armorModel; + + renderer.prepForRender(entity, stack, equipmentSlot, baseModel); + baseModel.copyPropertiesTo(typedHumanoidModel); + armorModel.renderToBuffer(poseStack, null, packedLight, OverlayTexture.NO_OVERLAY, i2); ci.cancel(); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModel.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModel.java new file mode 100644 index 000000000..7aa7b60f6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModel.java @@ -0,0 +1,74 @@ +package mod.azure.azurelib.core2.render.armor; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.geom.ModelLayers; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.world.entity.LivingEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class AzArmorModel extends HumanoidModel { + + private final AzArmorRendererPipeline rendererPipeline; + + public AzArmorModel(AzArmorRendererPipeline rendererPipeline) { + super(Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR)); + this.rendererPipeline = rendererPipeline; + } + + @Override + public void renderToBuffer( + @NotNull PoseStack poseStack, + @Nullable VertexConsumer buffer, + int packedLight, + int packedOverlay, + int var5 + ) { + var mc = Minecraft.getInstance(); + var context = rendererPipeline.context(); + var currentEntity = context.currentEntity(); + var currentStack = context.currentStack(); + MultiBufferSource bufferSource = Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); + + var shouldOutline = Minecraft.getInstance().levelRenderer.shouldShowEntityOutlines() && mc + .shouldEntityAppearGlowing( + currentEntity + ); + + if (shouldOutline) { + bufferSource = Minecraft.getInstance().levelRenderer.renderBuffers.outlineBufferSource(); + } + + var config = rendererPipeline.config(); + var animatable = context.animatable(); + var partialTick = mc.getTimer().getGameTimeDeltaTicks(); + var textureLocation = config.textureLocation(animatable); + var renderType = context.getDefaultRenderType(animatable, textureLocation, bufferSource, partialTick); + buffer = ItemRenderer.getArmorFoilBuffer(bufferSource, renderType, currentStack.hasFoil()); + + var model = rendererPipeline.renderer().provider().provideBakedModel(animatable); + rendererPipeline.render(poseStack, model, animatable, bufferSource, null, buffer, 0, partialTick, packedLight); + } + + /** + * Applies settings and transformations pre-render based on the default model + */ + public void applyBaseModel(HumanoidModel baseModel) { + this.young = baseModel.young; + this.crouching = baseModel.crouching; + this.riding = baseModel.riding; + this.rightArmPose = baseModel.rightArmPose; + this.leftArmPose = baseModel.leftArmPose; + } + + @Override + public void setAllVisible(boolean pVisible) { + super.setAllVisible(pVisible); + var boneContext = rendererPipeline.context().boneContext(); + boneContext.setAllVisible(pVisible); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModelRenderer.java new file mode 100644 index 000000000..e979ca361 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModelRenderer.java @@ -0,0 +1,80 @@ +package mod.azure.azurelib.core2.render.armor; + +import net.minecraft.world.item.ItemStack; +import org.joml.Matrix4f; +import org.joml.Vector3f; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzPhasedRenderer; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +public class AzArmorModelRenderer extends AzModelRenderer { + + private final AzArmorRendererPipeline armorRendererPipeline; + + public AzArmorModelRenderer( + AzArmorRendererPipeline armorRendererPipeline, + AzLayerRenderer layerRenderer + ) { + super(armorRendererPipeline, layerRenderer); + this.armorRendererPipeline = armorRendererPipeline; + } + + /** + * The actual render method that subtype renderers should override to handle their specific rendering tasks.
      + * {@link AzPhasedRenderer#preRender} has already been called by this stage, and {@link AzPhasedRenderer#postRender} + * will be called directly after + */ + @Override + public void render(AzRendererPipelineContext context, boolean isReRender) { + var poseStack = context.poseStack(); + poseStack.pushPose(); + poseStack.translate(0, 24 / 16f, 0); + poseStack.scale(-1, -1, 1); + + if (!isReRender) { + var animatable = context.animatable(); + var animator = armorRendererPipeline.renderer().animator(); + + if (animator != null) { + animator.animate(animatable); + } + } + + armorRendererPipeline.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); + + super.render(context, isReRender); + poseStack.popPose(); + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + @Override + public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + var poseStack = context.poseStack(); + // TODO: This is dangerous. + var ctx = armorRendererPipeline.context(); + + if (bone.isTrackingMatrices()) { + Matrix4f poseState = new Matrix4f(poseStack.last().pose()); + Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices( + poseState, + armorRendererPipeline.entityRenderTranslations + ); + + bone.setModelSpaceMatrix( + RenderUtils.invertAndMultiplyMatrices(poseState, armorRendererPipeline.modelRenderTranslations) + ); + bone.setLocalSpaceMatrix(RenderUtils.translateMatrix(localMatrix, new Vector3f())); + bone.setWorldSpaceMatrix( + RenderUtils.translateMatrix(new Matrix4f(localMatrix), ctx.currentEntity().position().toVector3f()) + ); + } + + super.renderRecursively(context, bone, isReRender); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRenderer.java new file mode 100644 index 000000000..a1a06c3f6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRenderer.java @@ -0,0 +1,77 @@ +package mod.azure.azurelib.core2.render.armor; + +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.render.AzProvider; +import mod.azure.azurelib.core2.render.AzRendererConfig; + +public class AzArmorRenderer { + + private final AzProvider provider; + + private final AzArmorRendererPipeline rendererPipeline; + + @Nullable + private AzItemAnimator reusedAzItemAnimator; + + public AzArmorRenderer(AzRendererConfig config) { + this.provider = new AzProvider<>(config::createAnimator, config::modelLocation); + this.rendererPipeline = new AzArmorRendererPipeline(config, this); + } + + /** + * Prepare the renderer for the current render cycle.
      + * Must be called prior to render as the default HumanoidModel doesn't give render context.
      + * Params have been left nullable so that the renderer can be called for model/texture purposes safely. If you do + * grab the renderer using null parameters, you should not use it for actual rendering. + * + * @param entity The entity being rendered with the armor on + * @param stack The ItemStack being rendered + * @param slot The slot being rendered + * @param baseModel The default (vanilla) model that would have been rendered if this model hadn't replaced it + */ + public void prepForRender( + @Nullable Entity entity, + ItemStack stack, + @Nullable EquipmentSlot slot, + @Nullable HumanoidModel baseModel + ) { + if (entity == null || slot == null || baseModel == null) { + return; + } + + rendererPipeline.context().prepare(entity, stack, slot, baseModel); + + var model = provider.provideBakedModel(stack); + prepareAnimator(stack, model); + } + + private void prepareAnimator(ItemStack stack, AzBakedModel model) { + var cachedEntityAnimator = (AzItemAnimator) provider.provideAnimator(stack); + + if (cachedEntityAnimator != null && model != null) { + cachedEntityAnimator.setActiveModel(model); + } + + // Point the renderer's current animator reference to the cached entity animator before rendering. + reusedAzItemAnimator = cachedEntityAnimator; + } + + public @Nullable AzItemAnimator animator() { + return reusedAzItemAnimator; + } + + public AzProvider provider() { + return provider; + } + + public AzArmorRendererPipeline rendererPipeline() { + return rendererPipeline; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererConfig.java new file mode 100644 index 000000000..19f3d91d9 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererConfig.java @@ -0,0 +1,93 @@ +package mod.azure.azurelib.core2.render.armor; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.armor.bone.AzArmorBoneProvider; +import mod.azure.azurelib.core2.render.armor.bone.AzDefaultArmorBoneProvider; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +public class AzArmorRendererConfig extends AzRendererConfig { + + private final AzArmorBoneProvider boneProvider; + + private AzArmorRendererConfig( + Supplier> animatorProvider, + AzArmorBoneProvider boneProvider, + Function modelLocationProvider, + List> renderLayers, + Function textureLocationProvider, + float scaleHeight, + float scaleWidth + ) { + super(animatorProvider, modelLocationProvider, renderLayers, textureLocationProvider, scaleHeight, scaleWidth); + this.boneProvider = boneProvider; + } + + public AzArmorBoneProvider boneProvider() { + return boneProvider; + } + + public static Builder builder( + ResourceLocation modelLocation, + ResourceLocation textureLocation + ) { + return new Builder($ -> modelLocation, $ -> textureLocation); + } + + public static Builder builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + return new Builder(modelLocationProvider, textureLocationProvider); + } + + public static class Builder extends AzRendererConfig.Builder { + + private AzArmorBoneProvider boneProvider; + + protected Builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + super(modelLocationProvider, textureLocationProvider); + this.boneProvider = new AzDefaultArmorBoneProvider(); + } + + @Override + public Builder addRenderLayer(AzRenderLayer renderLayer) { + return (Builder) super.addRenderLayer(renderLayer); + } + + @Override + public Builder setAnimatorProvider(Supplier<@Nullable AzAnimator> animatorProvider) { + return (Builder) super.setAnimatorProvider(animatorProvider); + } + + public Builder setBoneProvider(AzArmorBoneProvider boneProvider) { + this.boneProvider = boneProvider; + return this; + } + + public AzArmorRendererConfig build() { + var baseConfig = super.build(); + + return new AzArmorRendererConfig( + baseConfig::createAnimator, + boneProvider, + baseConfig::modelLocation, + baseConfig.renderLayers(), + baseConfig::textureLocation, + baseConfig.scaleHeight(), + baseConfig.scaleWidth() + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipeline.java new file mode 100644 index 000000000..6d7148e5e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipeline.java @@ -0,0 +1,131 @@ +package mod.azure.azurelib.core2.render.armor; + +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; +import org.joml.Matrix4f; + +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +public class AzArmorRendererPipeline extends AzRendererPipeline { + + private final AzArmorModel armorModel; + + private final AzArmorRenderer armorRenderer; + + protected Matrix4f entityRenderTranslations = new Matrix4f(); + + protected Matrix4f modelRenderTranslations = new Matrix4f(); + + public AzArmorRendererPipeline(AzRendererConfig config, AzArmorRenderer armorRenderer) { + super(config); + this.armorModel = new AzArmorModel<>(this); + this.armorRenderer = armorRenderer; + } + + @Override + protected AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { + return new AzArmorRendererPipelineContext(rendererPipeline); + } + + @Override + protected AzModelRenderer createModelRenderer(AzLayerRenderer layerRenderer) { + return new AzArmorModelRenderer(this, layerRenderer); + } + + @Override + protected AzLayerRenderer createLayerRenderer(AzRendererConfig config) { + return new AzLayerRenderer<>(config::renderLayers); + } + + @Override + protected void updateAnimatedTextureFrame(ItemStack animatable) { + var currentEntity = context().currentEntity(); + + if (currentEntity != null) { + var textureLocation = config().textureLocation(animatable); + var frameTick = currentEntity.getId() + currentEntity.tickCount; + + AnimatableTexture.setAndUpdate(textureLocation, frameTick); + } + } + + @Override + public void preRender(AzRendererPipelineContext context, boolean isReRender) { + var armorContext = (AzArmorRendererPipelineContext) context; + var baseModel = armorContext.baseModel(); + var boneContext = armorContext.boneContext(); + var config = config(); + var currentSlot = armorContext.currentSlot(); + var scaleWidth = config.scaleWidth(); + var scaleHeight = config.scaleHeight(); + + var animatable = armorContext.animatable(); + var model = armorRenderer.provider().provideBakedModel(animatable); + var poseStack = armorContext.poseStack(); + + this.entityRenderTranslations = new Matrix4f(poseStack.last().pose()); + + armorModel.applyBaseModel(baseModel); + boneContext.grabRelevantBones(model, config.boneProvider()); + boneContext.applyBaseTransformations(baseModel); + scaleModelForBaby(armorContext, isReRender); + scaleModelForRender(context, scaleWidth, scaleHeight, isReRender); + + boneContext.applyBoneVisibilityBySlot(currentSlot); + } + + @Override + public void postRender(AzRendererPipelineContext context, boolean isReRender) {} + + /** + * Apply custom scaling to account for {@link net.minecraft.client.model.AgeableListModel AgeableListModel} baby + * models + */ + public void scaleModelForBaby(AzArmorRendererPipelineContext context, boolean isReRender) { + if (!armorModel.young || isReRender) { + return; + } + + var baseModel = context.baseModel(); + var currentSlot = context.currentSlot(); + var poseStack = context.poseStack(); + + if (currentSlot == EquipmentSlot.HEAD) { + if (baseModel.scaleHead) { + float headScale = 1.5f / baseModel.babyHeadScale; + + poseStack.scale(headScale, headScale, headScale); + } + + poseStack.translate(0, baseModel.babyYHeadOffset / 16f, baseModel.babyZHeadOffset / 16f); + } else { + float bodyScale = 1 / baseModel.babyBodyScale; + + poseStack.scale(bodyScale, bodyScale, bodyScale); + poseStack.translate(0, baseModel.bodyYOffset / 16f, 0); + } + } + + public AzArmorModel armorModel() { + return armorModel; + } + + @Override + public AzArmorRendererConfig config() { + return (AzArmorRendererConfig) super.config(); + } + + @Override + public AzArmorRendererPipelineContext context() { + return (AzArmorRendererPipelineContext) super.context(); + } + + public AzArmorRenderer renderer() { + return armorRenderer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipelineContext.java new file mode 100644 index 000000000..1fd24e752 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipelineContext.java @@ -0,0 +1,96 @@ +package mod.azure.azurelib.core2.render.armor; + +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.DyedItemColor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core.object.Color; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.armor.bone.AzArmorBoneContext; + +public class AzArmorRendererPipelineContext extends AzRendererPipelineContext { + + private final AzArmorBoneContext boneContext; + + private HumanoidModel baseModel; + + private Entity currentEntity; + + private EquipmentSlot currentSlot; + + private ItemStack currentStack; + + public AzArmorRendererPipelineContext(AzRendererPipeline rendererPipeline) { + super(rendererPipeline); + this.baseModel = null; + this.boneContext = new AzArmorBoneContext(); + this.currentEntity = null; + this.currentSlot = null; + this.currentStack = null; + } + + @Override + public @NotNull RenderType getDefaultRenderType( + ItemStack animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ) { + return RenderType.armorCutoutNoCull(texture); + } + + public void prepare( + @Nullable Entity entity, + ItemStack stack, + @Nullable EquipmentSlot slot, + @Nullable HumanoidModel baseModel + ) { + this.baseModel = baseModel; + this.currentEntity = entity; + this.currentStack = stack; + this.currentSlot = slot; + } + + /** + * Gets a tint-applying color to render the given animatable with + *

      + * Returns {@link Color#WHITE} by default + */ + @Override + public Color getRenderColor(ItemStack animatable, float partialTick, int packedLight) { + return this.currentStack.is(ItemTags.DYEABLE) + ? Color.ofOpaque( + DyedItemColor.getOrDefault(this.currentStack, -6265536) + ) + : Color.WHITE; + } + + public HumanoidModel baseModel() { + return baseModel; + } + + public AzArmorBoneContext boneContext() { + return boneContext; + } + + public Entity currentEntity() { + return currentEntity; + } + + public EquipmentSlot currentSlot() { + return currentSlot; + } + + public ItemStack currentStack() { + return currentStack; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererRegistry.java new file mode 100644 index 000000000..9b7debbe0 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererRegistry.java @@ -0,0 +1,28 @@ +package mod.azure.azurelib.core2.render.armor; + +import net.minecraft.world.item.Item; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +public class AzArmorRendererRegistry { + + private static final Map ITEM_TO_RENDERER = new HashMap<>(); + + private static final Map, Supplier> ITEM_CLASS_TO_RENDERER_SUPPLIER = + new HashMap<>(); + + public static void register(Class itemClass, Supplier armorRendererSupplier) { + ITEM_CLASS_TO_RENDERER_SUPPLIER.put(itemClass, armorRendererSupplier); + } + + public static @Nullable AzArmorRenderer getOrNull(Item item) { + return ITEM_TO_RENDERER.computeIfAbsent(item, ($) -> { + var itemClass = item.getClass(); + var rendererSupplier = ITEM_CLASS_TO_RENDERER_SUPPLIER.get(itemClass); + return rendererSupplier == null ? null : rendererSupplier.get(); + }); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneContext.java new file mode 100644 index 000000000..9dd0790e8 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneContext.java @@ -0,0 +1,198 @@ +package mod.azure.azurelib.core2.render.armor.bone; + +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.world.entity.EquipmentSlot; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; + +public class AzArmorBoneContext { + + private AzBakedModel lastModel; + + private AzBone head; + + private AzBone body; + + private AzBone rightArm; + + private AzBone leftArm; + + private AzBone rightLeg; + + private AzBone leftLeg; + + private AzBone rightBoot; + + private AzBone leftBoot; + + public AzArmorBoneContext() { + this.head = null; + this.body = null; + this.rightArm = null; + this.leftArm = null; + this.rightLeg = null; + this.leftLeg = null; + this.rightBoot = null; + this.leftBoot = null; + } + + public void setAllVisible(boolean pVisible) { + setBoneVisible(this.head, pVisible); + setBoneVisible(this.body, pVisible); + setBoneVisible(this.rightArm, pVisible); + setBoneVisible(this.leftArm, pVisible); + setBoneVisible(this.rightLeg, pVisible); + setBoneVisible(this.leftLeg, pVisible); + setBoneVisible(this.rightBoot, pVisible); + setBoneVisible(this.leftBoot, pVisible); + } + + /** + * Gets and caches the relevant armor model bones for this baked model if it hasn't been done already + */ + public void grabRelevantBones(AzBakedModel model, AzArmorBoneProvider boneProvider) { + if (this.lastModel == model) { + return; + } + + this.lastModel = model; + this.head = boneProvider.getHeadBone(model); + this.body = boneProvider.getBodyBone(model); + this.rightArm = boneProvider.getRightArmBone(model); + this.leftArm = boneProvider.getLeftArmBone(model); + this.rightLeg = boneProvider.getRightLegBone(model); + this.leftLeg = boneProvider.getLeftLegBone(model); + this.rightBoot = boneProvider.getRightBootBone(model); + this.leftBoot = boneProvider.getLeftBootBone(model); + } + + /** + * Transform the currently rendering {@link AzBakedModel} to match the positions and rotations of the base model + */ + public void applyBaseTransformations(HumanoidModel baseModel) { + if (this.head != null) { + ModelPart headPart = baseModel.head; + + RenderUtils.matchModelPartRot(headPart, this.head); + this.head.updatePosition(headPart.x, -headPart.y, headPart.z); + } + + if (this.body != null) { + ModelPart bodyPart = baseModel.body; + + RenderUtils.matchModelPartRot(bodyPart, this.body); + this.body.updatePosition(bodyPart.x, -bodyPart.y, bodyPart.z); + } + + if (this.rightArm != null) { + ModelPart rightArmPart = baseModel.rightArm; + + RenderUtils.matchModelPartRot(rightArmPart, this.rightArm); + this.rightArm.updatePosition(rightArmPart.x + 5, 2 - rightArmPart.y, rightArmPart.z); + } + + if (this.leftArm != null) { + ModelPart leftArmPart = baseModel.leftArm; + + RenderUtils.matchModelPartRot(leftArmPart, this.leftArm); + this.leftArm.updatePosition(leftArmPart.x - 5f, 2f - leftArmPart.y, leftArmPart.z); + } + + if (this.rightLeg != null) { + ModelPart rightLegPart = baseModel.rightLeg; + + RenderUtils.matchModelPartRot(rightLegPart, this.rightLeg); + this.rightLeg.updatePosition(rightLegPart.x + 2, 12 - rightLegPart.y, rightLegPart.z); + + if (this.rightBoot != null) { + RenderUtils.matchModelPartRot(rightLegPart, this.rightBoot); + this.rightBoot.updatePosition(rightLegPart.x + 2, 12 - rightLegPart.y, rightLegPart.z); + } + } + + if (this.leftLeg != null) { + ModelPart leftLegPart = baseModel.leftLeg; + + RenderUtils.matchModelPartRot(leftLegPart, this.leftLeg); + this.leftLeg.updatePosition(leftLegPart.x - 2, 12 - leftLegPart.y, leftLegPart.z); + + if (this.leftBoot != null) { + RenderUtils.matchModelPartRot(leftLegPart, this.leftBoot); + this.leftBoot.updatePosition(leftLegPart.x - 2, 12 - leftLegPart.y, leftLegPart.z); + } + } + } + + /** + * Resets the bone visibility for the model based on the current {@link ModelPart} and {@link EquipmentSlot}, and + * then sets the bones relevant to the current part as visible for rendering.
      + *
      + * If you are rendering a geo entity with armor, you should probably be calling this prior to rendering + */ + public void applyBoneVisibilityByPart(EquipmentSlot currentSlot, ModelPart currentPart, HumanoidModel model) { + setAllVisible(false); + + currentPart.visible = true; + AzBone bone = null; + + if (currentPart == model.hat || currentPart == model.head) { + bone = this.head; + } else if (currentPart == model.body) { + bone = this.body; + } else if (currentPart == model.leftArm) { + bone = this.leftArm; + } else if (currentPart == model.rightArm) { + bone = this.rightArm; + } else if (currentPart == model.leftLeg) { + bone = currentSlot == EquipmentSlot.FEET ? this.leftBoot : this.leftLeg; + } else if (currentPart == model.rightLeg) { + bone = currentSlot == EquipmentSlot.FEET ? this.rightBoot : this.rightLeg; + } + + if (bone != null) { + bone.setHidden(false); + } + } + + /** + * Resets the bone visibility for the model based on the currently rendering slot, and then sets bones relevant to + * the current slot as visible for rendering.
      + *
      + * This is only called by default for non-geo entities (I.E. players or vanilla mobs) + */ + public void applyBoneVisibilityBySlot(EquipmentSlot currentSlot) { + setAllVisible(false); + + switch (currentSlot) { + case HEAD -> setBoneVisible(this.head, true); + case CHEST -> { + setBoneVisible(this.body, true); + setBoneVisible(this.rightArm, true); + setBoneVisible(this.leftArm, true); + } + case LEGS -> { + setBoneVisible(this.rightLeg, true); + setBoneVisible(this.leftLeg, true); + } + case FEET -> { + setBoneVisible(this.rightBoot, true); + setBoneVisible(this.leftBoot, true); + } + case MAINHAND, OFFHAND -> { /* NO-OP */ } + } + } + + /** + * Sets a bone as visible or hidden, with nullability + */ + protected void setBoneVisible(@Nullable AzBone bone, boolean visible) { + if (bone == null) + return; + + bone.setHidden(!visible); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneProvider.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneProvider.java new file mode 100644 index 000000000..4a65ad61a --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneProvider.java @@ -0,0 +1,97 @@ +package mod.azure.azurelib.core2.render.armor.bone; + +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; + +public interface AzArmorBoneProvider { + + String BONE_ARMOR_BODY_NAME = "armorBody"; + + String BONE_ARMOR_HEAD_NAME = "armorHead"; + + String BONE_ARMOR_LEFT_ARM_NAME = "armorLeftArm"; + + String BONE_ARMOR_RIGHT_ARM_NAME = "armorRightArm"; + + String BONE_ARMOR_LEFT_BOOT_NAME = "armorLeftBoot"; + + String BONE_ARMOR_RIGHT_BOOT_NAME = "armorRightBoot"; + + String BONE_ARMOR_LEFT_LEG_NAME = "armorLeftLeg"; + + String BONE_ARMOR_RIGHT_LEG_NAME = "armorRightLeg"; + + /** + * Returns the 'head' GeoBone from this model.
      + * Override if your geo model has different bone names for these bones + * + * @return The bone for the head model piece, or null if not using it + */ + @Nullable + AzBone getHeadBone(AzBakedModel model); + + /** + * Returns the 'body' GeoBone from this model.
      + * Override if your geo model has different bone names for these bones + * + * @return The bone for the body model piece, or null if not using it + */ + @Nullable + AzBone getBodyBone(AzBakedModel model); + + /** + * Returns the 'right arm' GeoBone from this model.
      + * Override if your geo model has different bone names for these bones + * + * @return The bone for the right arm model piece, or null if not using it + */ + @Nullable + AzBone getRightArmBone(AzBakedModel model); + + /** + * Returns the 'left arm' GeoBone from this model.
      + * Override if your geo model has different bone names for these bones + * + * @return The bone for the left arm model piece, or null if not using it + */ + @Nullable + AzBone getLeftArmBone(AzBakedModel model); + + /** + * Returns the 'right leg' GeoBone from this model.
      + * Override if your geo model has different bone names for these bones + * + * @return The bone for the right leg model piece, or null if not using it + */ + @Nullable + AzBone getRightLegBone(AzBakedModel model); + + /** + * Returns the 'left leg' GeoBone from this model.
      + * Override if your geo model has different bone names for these bones + * + * @return The bone for the left leg model piece, or null if not using it + */ + @Nullable + AzBone getLeftLegBone(AzBakedModel model); + + /** + * Returns the 'right boot' GeoBone from this model.
      + * Override if your geo model has different bone names for these bones + * + * @return The bone for the right boot model piece, or null if not using it + */ + @Nullable + AzBone getRightBootBone(AzBakedModel model); + + /** + * Returns the 'left boot' GeoBone from this model.
      + * Override if your geo model has different bone names for these bones + * + * @return The bone for the left boot model piece, or null if not using it + */ + @Nullable + AzBone getLeftBootBone(AzBakedModel model); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzDefaultArmorBoneProvider.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzDefaultArmorBoneProvider.java new file mode 100644 index 000000000..43b416c19 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzDefaultArmorBoneProvider.java @@ -0,0 +1,49 @@ +package mod.azure.azurelib.core2.render.armor.bone; + +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; + +public class AzDefaultArmorBoneProvider implements AzArmorBoneProvider { + + @Nullable + public AzBone getHeadBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_HEAD_NAME); + } + + @Nullable + public AzBone getBodyBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_BODY_NAME); + } + + @Nullable + public AzBone getRightArmBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_RIGHT_ARM_NAME); + } + + @Nullable + public AzBone getLeftArmBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_LEFT_ARM_NAME); + } + + @Nullable + public AzBone getRightLegBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_RIGHT_LEG_NAME); + } + + @Nullable + public AzBone getLeftLegBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_LEFT_LEG_NAME); + } + + @Nullable + public AzBone getRightBootBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_RIGHT_BOOT_NAME); + } + + @Nullable + public AzBone getLeftBootBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_LEFT_BOOT_NAME); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererRegistry.java index ac2fee7ec..b7d1e58c7 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererRegistry.java @@ -5,16 +5,24 @@ import java.util.HashMap; import java.util.Map; +import java.util.function.Supplier; public class AzItemRendererRegistry { private static final Map ITEM_TO_RENDERER = new HashMap<>(); - public static void register(Item item, AzItemRenderer itemRenderer) { - ITEM_TO_RENDERER.put(item, itemRenderer); + private static final Map, Supplier> ITEM_CLASS_TO_RENDERER_SUPPLIER = + new HashMap<>(); + + public static void register(Class itemClass, Supplier itemRendererSupplier) { + ITEM_CLASS_TO_RENDERER_SUPPLIER.put(itemClass, itemRendererSupplier); } public static @Nullable AzItemRenderer getOrNull(Item item) { - return ITEM_TO_RENDERER.get(item); + return ITEM_TO_RENDERER.computeIfAbsent(item, ($) -> { + var itemClass = item.getClass(); + var rendererSupplier = ITEM_CLASS_TO_RENDERER_SUPPLIER.get(itemClass); + return rendererSupplier == null ? null : rendererSupplier.get(); + }); } } diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java index 64d3eb8fa..c29d5ab5d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java @@ -1,5 +1,6 @@ package mod.azure.azurelib.core2.render.layer; +import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.Minecraft; import net.minecraft.client.model.HumanoidModel; @@ -8,7 +9,6 @@ import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.Sheets; import net.minecraft.client.renderer.blockentity.SkullBlockRenderer; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.component.DataComponents; import net.minecraft.tags.ItemTags; import net.minecraft.util.FastColor; @@ -21,16 +21,15 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.core2.model.AzBone; import mod.azure.azurelib.core2.render.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.armor.AzArmorRenderer; +import mod.azure.azurelib.core2.render.armor.AzArmorRendererRegistry; /** * Builtin class for handling dynamic armor rendering on AzureLib entities.
      - * Supports both {@link GeoItem AzureLib} and {@link net.minecraft.world.item.ArmorItem Vanilla} armor models.
      + * Supports {@link net.minecraft.world.item.ArmorItem Vanilla} armor models.
      * Unlike a traditional armor renderer, this renderer renders per-bone, giving much more flexible armor rendering. */ public class AzArmorLayer implements AzRenderLayer { @@ -63,8 +62,10 @@ public class AzArmorLayer implements AzRenderLayer { @Override public void preRender(AzRendererPipelineContext context) { - if (!(context.animatable() instanceof LivingEntity livingEntity)) + if (!(context.animatable() instanceof LivingEntity livingEntity)) { return; + } + this.mainHandStack = livingEntity.getItemBySlot(EquipmentSlot.MAINHAND); this.offhandStack = livingEntity.getItemBySlot(EquipmentSlot.OFFHAND); this.helmetStack = livingEntity.getItemBySlot(EquipmentSlot.HEAD); @@ -78,10 +79,12 @@ public void render(AzRendererPipelineContext context) {} @Override public void renderForBone(AzRendererPipelineContext context, AzBone bone) { - ItemStack armorStack = getArmorItemForBone(context, bone); + var poseStack = context.poseStack(); + var armorStack = getArmorItemForBone(context, bone); - if (armorStack == null) + if (armorStack == null) { return; + } if ( armorStack.getItem() instanceof BlockItem blockItem && blockItem @@ -89,43 +92,52 @@ public void renderForBone(AzRendererPipelineContext context, AzBone bone) { ) { renderSkullAsArmor(context, bone, armorStack, skullBlock); } else { - EquipmentSlot slot = getEquipmentSlotForBone(context, bone, armorStack); - HumanoidModel model = getModelForItem(context, bone, slot, armorStack); - ModelPart modelPart = getModelPartForBone(context, model); - - if (!modelPart.cubes.isEmpty()) { - context.poseStack().pushPose(); - context.poseStack().scale(-1, -1, 1); - - if ( - model instanceof GeoArmorRenderer geoArmorRenderer && context - .animatable() instanceof Entity entity - ) { - prepModelPartForRender(context, bone, modelPart); - geoArmorRenderer.prepForRender(entity, armorStack, slot, model); - geoArmorRenderer.applyBoneVisibilityByPart(slot, modelPart, model); - geoArmorRenderer.renderToBuffer( - context.poseStack(), - null, - context.packedLight(), - context.packedOverlay(), - armorStack.is( - ItemTags.DYEABLE - ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(armorStack, -6265536)) : -1 - ); - } else if (armorStack.getItem() instanceof ArmorItem) { - prepModelPartForRender(context, bone, modelPart); - renderVanillaArmorPiece( - context, - bone, - slot, - armorStack, - modelPart - ); - } + renderArmor(context, bone, armorStack, poseStack); + } + } - context.poseStack().popPose(); + private void renderArmor( + AzRendererPipelineContext context, + AzBone bone, + ItemStack armorStack, + PoseStack poseStack + ) { + var slot = getEquipmentSlotForBone(context, bone, armorStack); + var renderer = getRendererForItem(armorStack); + var model = getModelForItem(armorStack, slot); + var modelPart = getModelPartForBone(context, model); + + if (!modelPart.cubes.isEmpty()) { + poseStack.pushPose(); + poseStack.scale(-1, -1, 1); + + if (renderer != null && context.animatable() instanceof Entity entity) { + var boneContext = renderer.rendererPipeline().context().boneContext(); + + prepModelPartForRender(context, bone, modelPart); + renderer.prepForRender(entity, armorStack, slot, model); + boneContext.applyBoneVisibilityByPart(slot, modelPart, model); + model.renderToBuffer( + poseStack, + null, + context.packedLight(), + context.packedOverlay(), + armorStack.is( + ItemTags.DYEABLE + ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(armorStack, -6265536)) : -1 + ); + } else if (armorStack.getItem() instanceof ArmorItem) { + prepModelPartForRender(context, bone, modelPart); + renderVanillaArmorPiece( + context, + bone, + slot, + armorStack, + modelPart + ); } + + poseStack.popPose(); } } @@ -133,15 +145,20 @@ public void renderForBone(AzRendererPipelineContext context, AzBone bone) { * Return an EquipmentSlot for a given {@link ItemStack} and animatable instance.
      * This is what determines the base model to use for rendering a particular stack */ - @NotNull - protected EquipmentSlot getEquipmentSlotForBone(AzRendererPipelineContext context, AzBone bone, ItemStack stack) { - for (EquipmentSlot slot : EquipmentSlot.values()) { - if ( - slot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR && context - .animatable() instanceof LivingEntity livingEntity - ) { - if (stack == livingEntity.getItemBySlot(slot)) + protected @NotNull EquipmentSlot getEquipmentSlotForBone( + AzRendererPipelineContext context, + AzBone bone, + ItemStack stack + ) { + var animatable = context.animatable(); + + if (animatable instanceof LivingEntity livingEntity) { + for (var slot : EquipmentSlot.values()) { + var isHumanoidArmorSlotType = slot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR; + + if (isHumanoidArmorSlotType && stack == livingEntity.getItemBySlot(slot)) { return slot; + } } } @@ -178,7 +195,7 @@ protected void renderVanillaArmorPiece( ) { var material = ((ArmorItem) armorStack.getItem()).getMaterial(); - for (ArmorMaterial.Layer layer : material.value().layers()) { + for (var layer : material.value().layers()) { var buffer = getVanillaArmorBuffer( context, armorStack, @@ -194,17 +211,14 @@ protected void renderVanillaArmorPiece( var trim = armorStack.get(DataComponents.TRIM); if (trim != null) { - TextureAtlasSprite sprite = Minecraft.getInstance() + var spriteLocation = slot == EquipmentSlot.LEGS ? trim.innerTexture(material) : trim.outerTexture(material); + var consumer = context.multiBufferSource() + .getBuffer(Sheets.armorTrimsSheet(trim.pattern().value().decal())); + var sprite = Minecraft.getInstance() .getModelManager() - .getAtlas( - Sheets.ARMOR_TRIMS_SHEET - ) - .getSprite( - slot == EquipmentSlot.LEGS ? trim.innerTexture(material) : trim.outerTexture(material) - ); - VertexConsumer buffer = sprite.wrap( - context.multiBufferSource().getBuffer(Sheets.armorTrimsSheet(trim.pattern().value().decal())) - ); + .getAtlas(Sheets.ARMOR_TRIMS_SHEET) + .getSprite(spriteLocation); + var buffer = sprite.wrap(consumer); modelPart.render(context.poseStack(), buffer, context.packedLight(), context.packedOverlay()); } @@ -233,28 +247,31 @@ protected VertexConsumer getVanillaArmorBuffer( @Nullable ArmorMaterial.Layer layer, boolean forGlint ) { - if (forGlint) + if (forGlint) { return context.multiBufferSource().getBuffer(RenderType.armorEntityGlint()); + } return context.multiBufferSource() .getBuffer(RenderType.armorCutoutNoCull(layer.texture(slot == EquipmentSlot.LEGS))); } + protected @Nullable AzArmorRenderer getRendererForItem(ItemStack stack) { + var item = stack.getItem(); + return AzArmorRendererRegistry.getOrNull(item); + } + /** * Returns a cached instance of a base HumanoidModel that is used for rendering/modelling the provided * {@link ItemStack} */ - @NotNull - protected HumanoidModel getModelForItem( - AzRendererPipelineContext context, - AzBone bone, - EquipmentSlot slot, - ItemStack stack - ) { - var defaultModel = slot == EquipmentSlot.LEGS ? INNER_ARMOR_MODEL : OUTER_ARMOR_MODEL; - var livingEntity = (LivingEntity) context.animatable(); + protected HumanoidModel getModelForItem(ItemStack stack, EquipmentSlot slot) { + var renderer = getRendererForItem(stack); + + if (renderer == null) { + return slot == EquipmentSlot.LEGS ? INNER_ARMOR_MODEL : OUTER_ARMOR_MODEL; + } - return RenderProvider.of(stack).getHumanoidArmorModel(livingEntity, stack, slot, defaultModel); + return renderer.rendererPipeline().armorModel(); } /** @@ -297,14 +314,14 @@ protected void renderSkullAsArmor( * @param sourcePart The ModelPart to translate */ protected void prepModelPartForRender(AzRendererPipelineContext context, AzBone bone, ModelPart sourcePart) { - final var firstCube = bone.getCubes().get(0); - final var armorCube = sourcePart.cubes.get(0); - final var armorBoneSizeX = firstCube.size().x(); - final var armorBoneSizeY = firstCube.size().y(); - final var armorBoneSizeZ = firstCube.size().z(); - final var actualArmorSizeX = Math.abs(armorCube.maxX - armorCube.minX); - final var actualArmorSizeY = Math.abs(armorCube.maxY - armorCube.minY); - final var actualArmorSizeZ = Math.abs(armorCube.maxZ - armorCube.minZ); + var firstCube = bone.getCubes().get(0); + var armorCube = sourcePart.cubes.get(0); + var armorBoneSizeX = firstCube.size().x(); + var armorBoneSizeY = firstCube.size().y(); + var armorBoneSizeZ = firstCube.size().z(); + var actualArmorSizeX = Math.abs(armorCube.maxX - armorCube.minX); + var actualArmorSizeY = Math.abs(armorCube.maxY - armorCube.minY); + var actualArmorSizeZ = Math.abs(armorCube.maxZ - armorCube.minZ); var scaleX = (float) (armorBoneSizeX / actualArmorSizeX); var scaleY = (float) (armorBoneSizeY / actualArmorSizeY); var scaleZ = (float) (armorBoneSizeZ / actualArmorSizeZ); diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index 3cf9c28ce..9b3315df3 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -15,12 +15,16 @@ import mod.azure.azurelib.common.api.client.helper.ClientUtils; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.network.packet.*; +import mod.azure.azurelib.core2.render.armor.AzArmorRendererRegistry; import mod.azure.azurelib.core2.render.item.AzItemRendererRegistry; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; +import mod.azure.azurelib.fabric.core2.example.armors.AzDoomArmor; +import mod.azure.azurelib.fabric.core2.example.armors.AzDoomArmorRenderer; import mod.azure.azurelib.fabric.core2.example.blocks.StargateRender; import mod.azure.azurelib.fabric.core2.example.entities.doomhunter.DoomHunterRenderer; import mod.azure.azurelib.fabric.core2.example.entities.drone.DroneRenderer; import mod.azure.azurelib.fabric.core2.example.entities.marauder.MarauderRenderer; +import mod.azure.azurelib.fabric.core2.example.items.AzPistol; import mod.azure.azurelib.fabric.core2.example.items.AzPistolRenderer; public final class ClientListener implements ClientModInitializer { @@ -83,7 +87,8 @@ public void onInitializeClient() { ClientPlayNetworking.registerGlobalReceiver(AnimDataSyncPacket.TYPE, (packet, context) -> packet.handle()); ClientPlayNetworking.registerGlobalReceiver(SendConfigDataPacket.TYPE, (packet, context) -> packet.handle()); - AzItemRendererRegistry.register(FabricAzureLibMod.AZ_PISTOL, new AzPistolRenderer()); + AzItemRendererRegistry.register(AzPistol.class, AzPistolRenderer::new); + AzArmorRendererRegistry.register(AzDoomArmor.class, AzDoomArmorRenderer::new); EntityRendererRegistry.register(ExampleEntityTypes.DRONE, DroneRenderer::new); EntityRendererRegistry.register(ExampleEntityTypes.DOOMHUNTER, DoomHunterRenderer::new); EntityRendererRegistry.register(ExampleEntityTypes.MARAUDER, MarauderRenderer::new); diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 9c3a67f24..916439d98 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -19,6 +19,7 @@ import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; import mod.azure.azurelib.common.internal.common.network.packet.*; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; +import mod.azure.azurelib.fabric.core2.example.armors.AzDoomArmor; import mod.azure.azurelib.fabric.core2.example.armors.DoomArmor; import mod.azure.azurelib.fabric.core2.example.blocks.Stargate; import mod.azure.azurelib.fabric.core2.example.items.AzPistol; @@ -32,6 +33,22 @@ public final class FabricAzureLibMod implements ModInitializer { public static final Item AZ_PISTOL = new AzPistol(); + public static final Item AZ_DOOM_HELMET = new AzDoomArmor(ArmorItem.Type.HELMET); + + public static final Item AZ_DOOM_CHESTPLATE = new AzDoomArmor(ArmorItem.Type.CHESTPLATE); + + public static final Item AZ_DOOM_LEGGINGS = new AzDoomArmor(ArmorItem.Type.LEGGINGS); + + public static final Item AZ_DOOM_BOOTS = new AzDoomArmor(ArmorItem.Type.BOOTS); + + public static final Item DOOM_HELMET = new DoomArmor(ArmorItem.Type.HELMET); + + public static final Item DOOM_CHESTPLATE = new DoomArmor(ArmorItem.Type.CHESTPLATE); + + public static final Item DOOM_LEGGINGS = new DoomArmor(ArmorItem.Type.LEGGINGS); + + public static final Item DOOM_BOOTS = new DoomArmor(ArmorItem.Type.BOOTS); + @Override public void onInitialize() { ConfigIO.FILE_WATCH_MANAGER.startService(); @@ -64,25 +81,45 @@ public void onInitialize() { AzureLib.modResource("az_pistol"), AZ_PISTOL ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("az_doomicorn_helmet"), + AZ_DOOM_HELMET + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("az_doomicorn_chestplate"), + AZ_DOOM_CHESTPLATE + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("az_doomicorn_leggings"), + AZ_DOOM_LEGGINGS + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("az_doomicorn_boots"), + AZ_DOOM_BOOTS + ); Registry.register( BuiltInRegistries.ITEM, AzureLib.modResource("doomicorn_helmet"), - new DoomArmor(ArmorItem.Type.HELMET) + DOOM_HELMET ); Registry.register( BuiltInRegistries.ITEM, AzureLib.modResource("doomicorn_chestplate"), - new DoomArmor(ArmorItem.Type.CHESTPLATE) + DOOM_CHESTPLATE ); Registry.register( BuiltInRegistries.ITEM, AzureLib.modResource("doomicorn_leggings"), - new DoomArmor(ArmorItem.Type.LEGGINGS) + DOOM_LEGGINGS ); Registry.register( BuiltInRegistries.ITEM, AzureLib.modResource("doomicorn_boots"), - new DoomArmor(ArmorItem.Type.BOOTS) + DOOM_BOOTS ); ExampleEntityTypes.initialize(); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmor.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmor.java new file mode 100644 index 000000000..40fe4407d --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmor.java @@ -0,0 +1,44 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArmorMaterials; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +public class AzDoomArmor extends ArmorItem { + + private final AzDoomArmorAnimationDispatcher dispatcher; + + public AzDoomArmor(Type type) { + super(ArmorMaterials.NETHERITE, type, new Properties()); + this.dispatcher = new AzDoomArmorAnimationDispatcher(); + } + + @Override + public @NotNull InteractionResultHolder swapWithEquipmentSlot( + Item item, + Level level, + Player player, + InteractionHand hand + ) { + var result = super.swapWithEquipmentSlot(item, level, player, hand); + var itemStack = result.getObject(); + + if (!level.isClientSide) { + // TODO: This dispatch does not work. + // The reason it doesn't work is because this function finishes before the armor even starts to render. + // The armor stack recreated on equip, which means the animator associated with it is also destroyed + // and recreated on equip. To fix this, we need the animators to remain stable even as item stacks change. + // Item stack references are transient, but their data components are not. So we can map animators + // by the UUID of the item stack. + dispatcher.serverEquipHelmet(player, itemStack); + } + + return result; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimationDispatcher.java new file mode 100644 index 000000000..849636c7c --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimationDispatcher.java @@ -0,0 +1,18 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; + +import mod.azure.azurelib.core2.animation.dispatch.AzDispatcher; +import mod.azure.azurelib.core2.animation.dispatch.command.AzDispatchCommand; + +public class AzDoomArmorAnimationDispatcher { + + private static final AzDispatchCommand EQUIP = AzDispatchCommand.builder() + .playAnimation("base_controller", "equipping") + .build(); + + public void serverEquipHelmet(Entity entity, ItemStack itemStack) { + AzDispatcher.fromServer(EQUIP).sendForItem(entity, itemStack); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimator.java new file mode 100644 index 000000000..102af7aa7 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimator.java @@ -0,0 +1,36 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; +import mod.azure.azurelib.core2.animation.primitive.AzRawAnimation; + +public class AzDoomArmorAnimator extends AzItemAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource( + "animations/item/doomicorn.animation.json" + ); + + private static final String EQUIP_ANIMATION_NAME = "equipping"; + + private static final AzRawAnimation EQUIP_ANIMATION = AzRawAnimation.begin().thenLoop(EQUIP_ANIMATION_NAME); + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + AzAnimationController.builder(this, "base_controller") + .triggerableAnim(EQUIP_ANIMATION_NAME, EQUIP_ANIMATION) + .build() + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(ItemStack animatable) { + return ANIMATIONS; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorBoneProvider.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorBoneProvider.java new file mode 100644 index 000000000..21d4542f7 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorBoneProvider.java @@ -0,0 +1,30 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.armor.bone.AzDefaultArmorBoneProvider; + +public class AzDoomArmorBoneProvider extends AzDefaultArmorBoneProvider { + + // Only models I have on for armors with animations, the arm/legs are named wrong and i just didnt want to load it + // in bb again to rename, this should be a feature kept though + @Override + public AzBone getLeftBootBone(AzBakedModel model) { + return model.getBone("armorRightBoot").orElse(null); + } + + @Override + public AzBone getLeftLegBone(AzBakedModel model) { + return model.getBone("armorRightLeg").orElse(null); + } + + @Override + public AzBone getRightBootBone(AzBakedModel model) { + return model.getBone("armorLeftBoot").orElse(null); + } + + @Override + public AzBone getRightLegBone(AzBakedModel model) { + return model.getBone("armorLeftLeg").orElse(null); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorRenderer.java new file mode 100644 index 000000000..0dea20fb1 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorRenderer.java @@ -0,0 +1,23 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.render.armor.AzArmorRenderer; +import mod.azure.azurelib.core2.render.armor.AzArmorRendererConfig; + +public class AzDoomArmorRenderer extends AzArmorRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/item/doomicorn.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/item/doomicorn.png"); + + public AzDoomArmorRenderer() { + super( + AzArmorRendererConfig.builder(MODEL, TEXTURE) + .setAnimatorProvider(AzDoomArmorAnimator::new) + .setBoneProvider(new AzDoomArmorBoneProvider()) + .build() + ); + } +} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java b/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java index aebd6dd60..9fb2e2a8b 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java @@ -10,7 +10,6 @@ import com.llamalad7.mixinextras.sugar.ref.LocalRef; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.model.HumanoidModel; -import net.minecraft.client.model.Model; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer; import net.minecraft.client.renderer.texture.OverlayTexture; @@ -28,6 +27,7 @@ import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; import mod.azure.azurelib.common.api.common.animatable.GeoItem; import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.core2.render.armor.AzArmorRendererRegistry; @Mixin(HumanoidArmorLayer.class) public abstract class MixinHumanoidArmorLayer> { @@ -70,18 +70,20 @@ public abstract class MixinHumanoidArmorLayer itemBySlotRef ) { - final ItemStack stack = itemBySlotRef.get(); - final Model azurelibModel = RenderProvider.of(stack) - .getGenericArmorModel( - entity, - stack, - equipmentSlot, - (HumanoidModel) baseModel - ); + var stack = itemBySlotRef.get(); + var renderProvider = RenderProvider.of(stack); + @SuppressWarnings("unchecked") + var humanoidModel = (HumanoidModel) baseModel; + var azurelibModel = renderProvider + .getGenericArmorModel(entity, stack, equipmentSlot, humanoidModel); + var i2 = stack.is( + ItemTags.DYEABLE + ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(stack, -6265536)) : -1; if (azurelibModel != null && stack.getItem() instanceof GeoItem) { - if (azurelibModel instanceof GeoArmorRenderer geoArmorRenderer) + if (azurelibModel instanceof GeoArmorRenderer geoArmorRenderer) { geoArmorRenderer.prepForRender(entity, stack, equipmentSlot, baseModel); + } baseModel.copyPropertiesTo((A) azurelibModel); azurelibModel.renderToBuffer( @@ -89,11 +91,23 @@ public abstract class MixinHumanoidArmorLayer) armorModel; + + renderer.prepForRender(entity, stack, equipmentSlot, baseModel); + baseModel.copyPropertiesTo(typedHumanoidModel); + armorModel.renderToBuffer(poseStack, null, packedLight, OverlayTexture.NO_OVERLAY, i2); + ci.cancel(); + } } } From 4151242548ee46e5d6e6fbd3eeec473de738961b Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 21 Dec 2024 15:37:13 -0500 Subject: [PATCH 160/224] Remove old armor --- .../azurelib/fabric/FabricAzureLibMod.java | 29 -------- .../core2/example/armors/ArmorRenderer.java | 37 ---------- .../core2/example/armors/DoomArmor.java | 69 ------------------- 3 files changed, 135 deletions(-) delete mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/ArmorRenderer.java delete mode 100644 fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/DoomArmor.java diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 916439d98..102e4f100 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -20,7 +20,6 @@ import mod.azure.azurelib.common.internal.common.network.packet.*; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; import mod.azure.azurelib.fabric.core2.example.armors.AzDoomArmor; -import mod.azure.azurelib.fabric.core2.example.armors.DoomArmor; import mod.azure.azurelib.fabric.core2.example.blocks.Stargate; import mod.azure.azurelib.fabric.core2.example.items.AzPistol; import mod.azure.azurelib.fabric.platform.FabricAzureLibNetwork; @@ -41,14 +40,6 @@ public final class FabricAzureLibMod implements ModInitializer { public static final Item AZ_DOOM_BOOTS = new AzDoomArmor(ArmorItem.Type.BOOTS); - public static final Item DOOM_HELMET = new DoomArmor(ArmorItem.Type.HELMET); - - public static final Item DOOM_CHESTPLATE = new DoomArmor(ArmorItem.Type.CHESTPLATE); - - public static final Item DOOM_LEGGINGS = new DoomArmor(ArmorItem.Type.LEGGINGS); - - public static final Item DOOM_BOOTS = new DoomArmor(ArmorItem.Type.BOOTS); - @Override public void onInitialize() { ConfigIO.FILE_WATCH_MANAGER.startService(); @@ -101,26 +92,6 @@ public void onInitialize() { AzureLib.modResource("az_doomicorn_boots"), AZ_DOOM_BOOTS ); - Registry.register( - BuiltInRegistries.ITEM, - AzureLib.modResource("doomicorn_helmet"), - DOOM_HELMET - ); - Registry.register( - BuiltInRegistries.ITEM, - AzureLib.modResource("doomicorn_chestplate"), - DOOM_CHESTPLATE - ); - Registry.register( - BuiltInRegistries.ITEM, - AzureLib.modResource("doomicorn_leggings"), - DOOM_LEGGINGS - ); - Registry.register( - BuiltInRegistries.ITEM, - AzureLib.modResource("doomicorn_boots"), - DOOM_BOOTS - ); ExampleEntityTypes.initialize(); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/ArmorRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/ArmorRenderer.java deleted file mode 100644 index e06c578a9..000000000 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/ArmorRenderer.java +++ /dev/null @@ -1,37 +0,0 @@ -package mod.azure.azurelib.fabric.core2.example.armors; - -import net.minecraft.world.item.ArmorItem; - -import mod.azure.azurelib.common.api.client.model.DefaultedItemGeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; - -public class ArmorRenderer extends GeoArmorRenderer { - - public ArmorRenderer() { - super(new DefaultedItemGeoModel<>(AzureLib.modResource("doomicorn"))); - } - - // Only models I have on for armors with animations, the arm/legs are named wrong and i just didnt want to load it - // in bb again to rename, this should be a feature kept though - @Override - public GeoBone getLeftBootBone() { - return this.model.getBone("armorRightBoot").orElse(null); - } - - @Override - public GeoBone getLeftLegBone() { - return this.model.getBone("armorRightLeg").orElse(null); - } - - @Override - public GeoBone getRightBootBone() { - return this.model.getBone("armorLeftBoot").orElse(null); - } - - @Override - public GeoBone getRightLegBone() { - return this.model.getBone("armorLeftLeg").orElse(null); - } -} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/DoomArmor.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/DoomArmor.java deleted file mode 100644 index bbb0704bd..000000000 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/DoomArmor.java +++ /dev/null @@ -1,69 +0,0 @@ -package mod.azure.azurelib.fabric.core2.example.armors; - -import net.minecraft.client.model.HumanoidModel; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ArmorItem; -import net.minecraft.world.item.ArmorMaterials; -import net.minecraft.world.item.ItemStack; - -import java.util.function.Consumer; - -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; -import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; -import mod.azure.azurelib.core.animation.AnimatableManager; -import mod.azure.azurelib.core.animation.AnimationController; -import mod.azure.azurelib.core.animation.RawAnimation; -import mod.azure.azurelib.core.object.PlayState; - -public class DoomArmor extends ArmorItem implements GeoItem { - - private final AnimatableInstanceCache cache = AzureLibUtil.createInstanceCache(this); - - private static final String EQUIP_ANIMATION_NAME = "equipping"; - - private static final RawAnimation EQUIP_ANIMATION = RawAnimation.begin().thenLoop(EQUIP_ANIMATION_NAME); - - public DoomArmor(Type type) { - super(ArmorMaterials.NETHERITE, type, new Properties()); - } - - @Override - public void createRenderer(Consumer consumer) { - consumer.accept(new RenderProvider() { - - private ArmorRenderer renderer; - - @Override - public HumanoidModel getHumanoidArmorModel( - LivingEntity livingEntity, - ItemStack itemStack, - EquipmentSlot equipmentSlot, - HumanoidModel original - ) { - if (renderer == null) { - renderer = new ArmorRenderer(); - } - renderer.prepForRender(livingEntity, itemStack, equipmentSlot, original); - return this.renderer; - } - }); - } - - @Override - public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { - controllers.add( - new AnimationController<>(this, "base_controller", 0, state -> PlayState.CONTINUE).triggerableAnim( - EQUIP_ANIMATION_NAME, - EQUIP_ANIMATION - ) - ); - } - - @Override - public AnimatableInstanceCache getAnimatableInstanceCache() { - return cache; - } -} From d5f9213a71781ba459281756d3aad5d0981a6dec Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 21 Dec 2024 16:03:57 -0500 Subject: [PATCH 161/224] makes pistols not stack --- .../mod/azure/azurelib/fabric/core2/example/items/AzPistol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java index 57511efc7..55314e1b4 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java @@ -14,7 +14,7 @@ public class AzPistol extends Item { private final AzPistolAnimationDispatcher dispatcher; public AzPistol() { - super(new Properties()); + super(new Properties().stacksTo(1)); this.dispatcher = new AzPistolAnimationDispatcher(); } From 81313a42221c14ede62f3ae32328247fd7147e7b Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 21 Dec 2024 16:04:20 -0500 Subject: [PATCH 162/224] Pushing WIP Item progress --- ...tackMixin_AzItemStackIdentityRegistry.java | 28 +++++++++++++++++++ .../animation/cache/AzIdentityRegistry.java | 19 +++++++++++++ .../azurelib/fabric/FabricAzureLibMod.java | 2 ++ 3 files changed, 49 insertions(+) create mode 100644 common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java create mode 100644 common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentityRegistry.java diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java new file mode 100644 index 000000000..80059d8a7 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java @@ -0,0 +1,28 @@ +package mod.azure.azurelib.common.internal.mixins; + +import net.minecraft.core.component.PatchedDataComponentMap; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; + +import java.util.UUID; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.core2.animation.cache.AzIdentityRegistry; + +@Mixin(ItemStack.class) +public class ItemStackMixin_AzItemStackIdentityRegistry { + + @Inject(method = "", at = @At("TAIL")) + public void addIdentity() { + var self = AzureLibUtil.self(this); + if ( + AzIdentityRegistry.hasIdentity(self.getItem()) && self + .getComponents() instanceof PatchedDataComponentMap components && !components.has(AzureLib.AZ_ID.get()) + ) { + components.set(AzureLib.AZ_ID.get(), UUID.randomUUID()); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentityRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentityRegistry.java new file mode 100644 index 000000000..93fa060f1 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentityRegistry.java @@ -0,0 +1,19 @@ +package mod.azure.azurelib.core2.animation.cache; + +import net.minecraft.world.item.Item; + +import java.util.HashSet; +import java.util.Set; + +public class AzIdentityRegistry { + + private static final Set IDENTITY_OF_ITEMS = new HashSet<>(); + + public static void register(Item item) { + IDENTITY_OF_ITEMS.add(item); + } + + public static boolean hasIdentity(Item item) { + return IDENTITY_OF_ITEMS.contains(item); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 102e4f100..085265447 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -18,6 +18,7 @@ import mod.azure.azurelib.common.internal.common.config.format.ConfigFormats; import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; import mod.azure.azurelib.common.internal.common.network.packet.*; +import mod.azure.azurelib.core2.animation.cache.AzIdentityRegistry; import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; import mod.azure.azurelib.fabric.core2.example.armors.AzDoomArmor; import mod.azure.azurelib.fabric.core2.example.blocks.Stargate; @@ -93,5 +94,6 @@ public void onInitialize() { AZ_DOOM_BOOTS ); ExampleEntityTypes.initialize(); + AzIdentityRegistry.register(AZ_PISTOL); } } From 3b4858829042cd8327ede407ee6cb7f35f07d132 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 21 Dec 2024 17:40:57 -0500 Subject: [PATCH 163/224] Hey lookie, the mixin works now that's it's registered and using the right method --- ...ItemStackMixin_AzItemStackIdentityRegistry.java | 14 ++++++++------ .../src/main/resources/azurelib.fabric.mixins.json | 1 + neo/src/main/resources/azurelib.neo.mixins.json | 1 + 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java index 80059d8a7..8ea5ff1b5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java @@ -2,9 +2,11 @@ import net.minecraft.core.component.PatchedDataComponentMap; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.UUID; @@ -15,13 +17,13 @@ @Mixin(ItemStack.class) public class ItemStackMixin_AzItemStackIdentityRegistry { - @Inject(method = "", at = @At("TAIL")) - public void addIdentity() { + @Inject( + method = "(Lnet/minecraft/world/level/ItemLike;ILnet/minecraft/core/component/PatchedDataComponentMap;)V", + at = @At("TAIL") + ) + public void az_addIdentityComponent(ItemLike item, int count, PatchedDataComponentMap components, CallbackInfo ci) { var self = AzureLibUtil.self(this); - if ( - AzIdentityRegistry.hasIdentity(self.getItem()) && self - .getComponents() instanceof PatchedDataComponentMap components && !components.has(AzureLib.AZ_ID.get()) - ) { + if (AzIdentityRegistry.hasIdentity(self.getItem()) && !components.has(AzureLib.AZ_ID.get())) { components.set(AzureLib.AZ_ID.get(), UUID.randomUUID()); } } diff --git a/fabric/src/main/resources/azurelib.fabric.mixins.json b/fabric/src/main/resources/azurelib.fabric.mixins.json index 737e7cfeb..63ba44150 100644 --- a/fabric/src/main/resources/azurelib.fabric.mixins.json +++ b/fabric/src/main/resources/azurelib.fabric.mixins.json @@ -6,6 +6,7 @@ "defaultRequire": 1 }, "mixins": [ + "ItemStackMixin_AzItemStackIdentityRegistry", "PlayerListMixin" ], "client": [ diff --git a/neo/src/main/resources/azurelib.neo.mixins.json b/neo/src/main/resources/azurelib.neo.mixins.json index 59d0887da..35b62353b 100644 --- a/neo/src/main/resources/azurelib.neo.mixins.json +++ b/neo/src/main/resources/azurelib.neo.mixins.json @@ -6,6 +6,7 @@ "defaultRequire": 1 }, "mixins": [ + "ItemStackMixin_AzItemStackIdentityRegistry", "PlayerListMixin" ], "client": [ From 101db9ed48deb0c30e94fa0b4bb5e11349f96d28 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 21 Dec 2024 18:25:01 -0500 Subject: [PATCH 164/224] Update AzIdentityRegistry#register to take 1 item plus more if multiple items need to be registered. --- .../azurelib/core2/animation/cache/AzIdentityRegistry.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentityRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentityRegistry.java index 93fa060f1..8f94f62e2 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentityRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentityRegistry.java @@ -1,7 +1,9 @@ package mod.azure.azurelib.core2.animation.cache; import net.minecraft.world.item.Item; +import org.jetbrains.annotations.NotNull; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -9,8 +11,9 @@ public class AzIdentityRegistry { private static final Set IDENTITY_OF_ITEMS = new HashSet<>(); - public static void register(Item item) { - IDENTITY_OF_ITEMS.add(item); + public static void register(@NotNull Item first, Item... rest) { + IDENTITY_OF_ITEMS.add(first); + IDENTITY_OF_ITEMS.addAll(Arrays.asList(rest)); } public static boolean hasIdentity(Item item) { From c4c1d2db1fe24fc58602bb03425391dfd3166ef1 Mon Sep 17 00:00:00 2001 From: AzureZhen <7415711+AzureDoom@users.noreply.github.com> Date: Sat, 21 Dec 2024 20:10:57 -0500 Subject: [PATCH 165/224] Yo dawg, I heard you like Java Docs --- ...ntityMixin_AzBlockEntityAnimatorCache.java | 6 ++ .../EntityMixin_AzEntityAnimatorCache.java | 6 ++ ...tackMixin_AzItemStackIdentityRegistry.java | 10 +++ .../azure/azurelib/core2/AzResourceCache.java | 4 + .../core2/animation/AzAnimationContext.java | 30 +++++++ .../animation/AzAnimationDispatcher.java | 17 ++++ .../core2/animation/AzAnimationTimer.java | 38 ++++++++ .../azurelib/core2/animation/AzAnimator.java | 7 ++ .../core2/animation/AzAnimatorAccessor.java | 7 ++ .../core2/animation/AzAnimatorConfig.java | 55 ++++++++++-- .../animation/AzBoneAnimationUpdateUtil.java | 30 +++++++ .../animation/AzCachedBoneUpdateUtil.java | 27 ++++++ .../cache/AzBakedAnimationCache.java | 13 +++ .../core2/animation/cache/AzBoneCache.java | 5 ++ .../AzIdentifiableItemStackAnimatorCache.java | 5 ++ .../animation/cache/AzIdentityRegistry.java | 17 ++++ .../AzAnimationControllerBuilder.java | 7 ++ .../AzAnimationControllerContainer.java | 6 ++ .../AzAnimationControllerTimer.java | 6 ++ .../controller/AzAnimationQueue.java | 9 ++ .../controller/AzBoneAnimationQueueCache.java | 6 ++ .../controller/AzBoneSnapshotCache.java | 9 ++ .../keyframe/AzAbstractKeyFrameExecutor.java | 5 ++ .../keyframe/AzKeyFrameCallbackHandler.java | 12 +++ .../keyframe/AzKeyFrameCallbacks.java | 7 ++ .../keyframe/AzKeyFrameExecutor.java | 11 +++ .../keyframe/AzKeyFrameManager.java | 7 ++ .../keyframe/AzKeyFrameTransitioner.java | 8 ++ .../controller/state/AzAnimationState.java | 14 +++ .../state/impl/AzAnimationPauseState.java | 6 ++ .../state/impl/AzAnimationPlayState.java | 9 ++ .../state/impl/AzAnimationStopState.java | 11 +++ .../impl/AzAnimationTransitionState.java | 9 ++ .../AzAnimationControllerStateMachine.java | 6 ++ .../dispatch/AzDispatchExecutor.java | 33 ++++--- .../animation/dispatch/AzDispatchSide.java | 8 ++ .../animation/dispatch/AzDispatcher.java | 43 +++++++++ .../dispatch/command/AzDispatchCommand.java | 23 +++++ .../command/action/AzDispatchAction.java | 6 ++ .../action/codec/AzDispatchActionCodec.java | 14 +++ .../action/codec/AzDispatchCommandCodec.java | 15 ++++ .../action/impl/root/AzRootCancelAction.java | 36 ++++++++ .../impl/root/AzRootCancelAllAction.java | 8 ++ .../impl/root/AzRootPlayAnimationAction.java | 11 +++ .../AzRootSetTransitionInSpeedAction.java | 8 ++ .../registry/AzDispatchActionRegistry.java | 13 +++ .../core2/animation/impl/AzBlockAnimator.java | 7 ++ .../animation/impl/AzEntityAnimator.java | 17 ++++ .../core2/animation/impl/AzItemAnimator.java | 9 ++ .../parse/AzBakedAnimationsAdapter.java | 88 +++++++++++++++++++ .../animation/parse/AzKeyFramesAdapter.java | 38 ++++++++ .../animation/primitive/AzAnimation.java | 7 ++ .../primitive/AzBakedAnimations.java | 12 ++- .../animation/primitive/AzKeyframes.java | 12 +++ .../core2/animation/primitive/AzLoopType.java | 39 ++++++++ .../primitive/AzQueuedAnimation.java | 14 ++- .../animation/primitive/AzRawAnimation.java | 5 ++ .../azurelib/core2/model/AzBakedModel.java | 5 ++ .../azurelib/core2/model/AzBoneMetadata.java | 5 ++ .../core2/model/cache/AzBakedModelCache.java | 5 ++ .../model/factory/AzBakedModelFactory.java | 7 ++ .../impl/AzBuiltinBakedModelFactory.java | 6 ++ .../registry/AzBakedModelFactoryRegistry.java | 10 +++ .../core2/render/AzLayerRenderer.java | 7 ++ .../core2/render/AzModelRenderer.java | 8 ++ .../core2/render/AzPhasedRenderer.java | 14 +++ .../azurelib/core2/render/AzProvider.java | 27 ++++++ .../core2/render/AzRendererConfig.java | 35 ++++++++ .../core2/render/AzRendererPipeline.java | 47 ++++++++++ .../render/AzRendererPipelineContext.java | 21 +++++ .../block/AzBlockEntityModelRenderer.java | 7 ++ .../render/block/AzBlockEntityRenderer.java | 7 ++ .../block/AzBlockEntityRendererConfig.java | 7 ++ .../block/AzBlockEntityRendererPipeline.java | 7 ++ .../AzBlockEntityRendererPipelineContext.java | 7 ++ .../render/entity/AzEntityLayerRenderer.java | 6 ++ .../entity/AzEntityLeashRenderUtil.java | 9 ++ .../render/entity/AzEntityModelRenderer.java | 8 ++ .../core2/render/entity/AzEntityRenderer.java | 19 ++++ .../render/entity/AzEntityRendererConfig.java | 7 ++ .../entity/AzEntityRendererPipeline.java | 13 +++ .../AzEntityRendererPipelineContext.java | 8 ++ .../render/item/AzItemModelRenderer.java | 4 + .../core2/render/item/AzItemRenderer.java | 10 +++ .../render/item/AzItemRendererConfig.java | 5 ++ .../render/item/AzItemRendererPipeline.java | 5 ++ .../item/AzItemRendererPipelineContext.java | 8 ++ .../render/item/AzItemRendererRegistry.java | 6 ++ .../core2/render/layer/AzArmorLayer.java | 44 ++++++++++ .../azurelib/core2/util/state/State.java | 11 +++ .../core2/util/state/StateMachine.java | 7 ++ .../core2/util/state/StateMachineContext.java | 13 +++ 92 files changed, 1286 insertions(+), 20 deletions(-) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java index 0ce31ada2..e47d1b8a3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java @@ -8,6 +8,12 @@ import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +/** + * Mixin class that implements the {@code AzAnimatorAccessor} interface to enable managing and associating + * an {@link AzAnimator} instance with a {@link BlockEntity}. This allows for caching and retrieval of the animator + * associated with specific block entities. This mixin modifies the behavior of {@link BlockEntity} by adding an + * animator cache that can be used to store and retrieve {@link AzAnimator} instances for animation handling. + */ @Mixin(BlockEntity.class) public abstract class BlockEntityMixin_AzBlockEntityAnimatorCache implements AzAnimatorAccessor { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java index c060df5b8..e1382d938 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java @@ -8,6 +8,12 @@ import mod.azure.azurelib.core2.animation.AzAnimator; import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +/** + * A Mixin class designed to integrate an animation cache mechanism into the {@link Entity} class through the use of the + * {@link AzAnimatorAccessor} interface. This allows entities to store an instance of {@link AzAnimator} for managing + * animations. Implements methods to set and retrieve the {@link AzAnimator} instance, enabling animation control and + * association to the entity. + */ @Mixin(Entity.class) public abstract class EntityMixin_AzEntityAnimatorCache implements AzAnimatorAccessor { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java index 8ea5ff1b5..db744d71d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java @@ -14,6 +14,16 @@ import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; import mod.azure.azurelib.core2.animation.cache.AzIdentityRegistry; +/** + * A mixin class for modifying the initialization behavior of the {@link ItemStack} class. This mixin specifically + * ensures that a unique identity component is added to an {@link ItemStack} upon creation, provided that the associated + * item has been registered in the {@link AzIdentityRegistry}. When an {@link ItemStack} is instantiated, the mixin + * checks if: - The item has an identity registered in {@link AzIdentityRegistry}. - The provided + * {@link PatchedDataComponentMap} does not already contain an `az_id` component. If both conditions are met, the mixin + * assigns a universally unique identifier (UUID) as the `az_id` component to the associated + * {@link PatchedDataComponentMap}. This mechanism enables unique identification and tracking of specific item stacks in + * the game. + */ @Mixin(ItemStack.class) public class ItemStackMixin_AzItemStackIdentityRegistry { diff --git a/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java b/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java index d9a35b9a4..79e7d127d 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java @@ -12,6 +12,10 @@ import java.util.function.BiConsumer; import java.util.function.Function; +/** + * AzResourceCache is an abstract base class designed for managing and loading mod resources asynchronously. This class + * provides helper functions for loading and processing resource files of a specific type and storing them in a cache. + */ public abstract class AzResourceCache { private static final Set EXCLUDED_NAMESPACES = ObjectOpenHashSet.of( diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationContext.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationContext.java index ea3fab18f..c98ab4493 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationContext.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationContext.java @@ -2,6 +2,13 @@ import mod.azure.azurelib.core2.animation.cache.AzBoneCache; +/** + * The {@code AzAnimationContext} class provides a context for managing animation-related state and behaviors for + * animatable objects of type {@code T}. It serves as the central point of interaction between the animation system, + * configuration settings, and the animated object itself. + * + * @param The type of the animatable object that this context operates on. + */ public class AzAnimationContext { private final AzBoneCache boneCache; @@ -23,18 +30,41 @@ public AzAnimationContext( this.timer = timer; } + /** + * Returns the current animatable instance associated with this animation context. + * + * @return The animatable instance of type {@code T}. + */ public T animatable() { return animatable; } + /** + * Returns the bone cache associated with the animation context. The bone cache is responsible for storing and + * managing bone-related data and transformations used during animations. + * + * @return The {@link AzBoneCache} instance managing bone data and transformations for animations. + */ public AzBoneCache boneCache() { return boneCache; } + /** + * Returns the animation configuration associated with this animation context. The configuration defines behavior + * such as bone reset speed, handling of missing bones, and whether animations should play while the game is paused. + * + * @return The {@link AzAnimatorConfig} instance containing the animation settings for this context. + */ public AzAnimatorConfig config() { return config; } + /** + * Returns the animation timer associated with the animation context. The timer is used to track animation progress + * over time and manage timing adjustments based on game state, such as pausing and resuming. + * + * @return The {@link AzAnimationTimer} instance responsible for animation timing. + */ public AzAnimationTimer timer() { return timer; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java index 6c8ade291..9535b6d95 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationDispatcher.java @@ -15,6 +15,15 @@ public AzAnimationDispatcher(Entity entity) { this.entity = entity; } + /** + * Dispatches an animation from the client side to the specified animation controller and triggers the animation. + * Logs a warning if the method is called from the server side, as the action is intended for client-side execution + * only. + * + * @param controllerName The name of the animation controller to target. Can be null if no specific controller is + * required. + * @param animationName The name of the animation to trigger. Must not be null. + */ public void dispatchFromClient(@Nullable String controllerName, String animationName) { if (!entity.level().isClientSide) { AzureLib.LOGGER.warn( @@ -31,6 +40,14 @@ public void dispatchFromClient(@Nullable String controllerName, String animation .ifPresent(controller -> controller.tryTriggerAnimation(animationName)); } + /** + * Dispatches an animation from the server to the specified animation controller and triggers the animation for the + * given entity. If called from the client side, will log a warning and take no action. + * + * @param controllerName The name of the animation controller to target. Can be null if no specific controller is + * required. + * @param animationName The name of the animation to trigger. Must not be null. + */ public void dispatchFromServer(@Nullable String controllerName, String animationName) { if (entity.level().isClientSide) { AzureLib.LOGGER.warn( diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java index 673adf315..3887d5a43 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java @@ -4,6 +4,14 @@ import mod.azure.azurelib.common.internal.client.util.RenderUtils; +/** + * AzAnimationTimer is responsible for managing animation progression based on game events and time deltas. It keeps + * track of the current animation time and ensures smooth transitions during various game states, such as pausing and + * resuming.
      + *
      + * The class relies on the provided {@link AzAnimatorConfig} for configurable behaviors, such as whether animations + * continue during game pauses or specific error handling preferences. + */ public class AzAnimationTimer { private final AzAnimatorConfig config; @@ -15,10 +23,34 @@ public class AzAnimationTimer { private boolean wasPausedLastFrame; + /** + * Constructs a new instance of AzAnimationTimer with the given configuration. + * + * @param config The configuration settings used to configure the animation timer. It includes parameters such as + * bone reset time, behavior during game pause, and whether to crash if a bone is missing. + */ public AzAnimationTimer(AzAnimatorConfig config) { this.config = config; } + /** + * Updates the animation timer by calculating the time delta since the last frame and applying it to the internal + * animation time. This method handles game pause states and adjusts the time calculations accordingly.
      + *
      + * Behavior:
      + * If the game is paused: + *

        + *
      • Sets an internal flag to indicate the paused state.
      • + *
      • Returns immediately if animations should not play while paused.
      • + *
      + *
      + * If transitioning from paused to unpaused: + *
        + *
      • Resets the frame delta to prevent large time skips in animations.
      • + *
      + *
      + * Accumulates the computed time delta into the animation time tracker to control the progression of animations. + */ public void tick() { var minecraft = Minecraft.getInstance(); var currentRenderTick = RenderUtils.getCurrentTick(); @@ -53,6 +85,12 @@ public void tick() { this.lastGameTickTime = currentRenderTick; } + /** + * Retrieves the current animation time. + * + * @return The current animation time as a double value, representing the accumulated time used for the progression + * of animations. + */ public double getAnimTime() { return animTime; } diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java index 47de3255c..b6a0f9148 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -15,6 +15,13 @@ import mod.azure.azurelib.core2.animation.primitive.AzAnimation; import mod.azure.azurelib.core2.model.AzBakedModel; +/** + * The {@code AzAnimator} class is an abstract base class for managing animations for various types of objects such as + * entities, blocks, or items. It provides a reusable structure for animating objects, allowing the integration of a + * variety of animation controllers and custom animations. + * + * @param The type of object this animator will animate (e.g., an entity, block entity, or item stack). + */ public abstract class AzAnimator { private final AzAnimationContext reusableContext; diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java index 5644403df..dd5f2ec05 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java @@ -4,6 +4,13 @@ import java.util.Optional; +/** + * The {@code AzAnimatorAccessor} interface provides a mechanism to associate and manage an {@link AzAnimator} instance + * with a target object. This enables retrieval and manipulation of animator instances that are specific to the target + * object. + * + * @param The type of the target object that the animator applies to. + */ public interface AzAnimatorAccessor { @Nullable diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorConfig.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorConfig.java index 572bfd1af..d059a34d9 100644 --- a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorConfig.java +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorConfig.java @@ -1,11 +1,18 @@ package mod.azure.azurelib.core2.animation; /** - * @param boneResetTime The speed with which bones lacking animation should reset back to their - * default position. 1 by default. - * @param crashIfBoneMissing Crash when a bone cannot be found while animating. False by default. - * @param shouldPlayAnimationsWhileGamePaused Whether animations should continue playing in the background when the game - * is paused. False by default. + * The {@code AzAnimatorConfig} record encapsulates configuration settings related to the animation system of the + * AzureLib framework. It provides customizable options for controlling animation behavior and error handling. This + * configuration is used to determine runtime behaviors such as whether animations should continue while the game is + * paused, whether the system should throw an error if a bone in the animation structure is missing, and the duration it + * takes to reset bone transformations. + * + * @param boneResetTime The specified time duration (in ticks or seconds) for resetting bones to + * their default transformations when animations are interrupted. + * @param crashIfBoneMissing Specifies whether the system will throw an exception if an expected bone + * in the animation is not found during runtime. + * @param shouldPlayAnimationsWhileGamePaused Indicates whether animations should continue playing when the game is + * paused. */ public record AzAnimatorConfig( double boneResetTime, @@ -13,10 +20,24 @@ public record AzAnimatorConfig( boolean shouldPlayAnimationsWhileGamePaused ) { + /** + * Creates a new instance of the {@link Builder} to configure and build an {@code AzAnimatorConfig}. + * + * @return A new {@code Builder} instance for constructing an {@code AzAnimatorConfig}. + */ public static Builder builder() { return new Builder(); } + /** + * Returns a default {@link AzAnimatorConfig} instance with predefined settings. The default configuration typically + * includes settings such as: + *

    - * This is a quick algorithm based on Andy Hall's voxel-aabb-sweep - * - * @param traversalVector The vector that represents the angle and length of traversal to cover - * @param minBoundsPos The negative-most position representing the minimum corner of the bounds - * @param leadingEdgePos The positive-most position representing the maximum corner of the bounds - * @return Whether the given traversal is free from collisions - */ - default boolean isCollisionFreeTraversal(Vec3 traversalVector, Vec3 minBoundsPos, Vec3 leadingEdgePos) { - final float traversalDistance = (float) traversalVector.length(); - - if (traversalDistance < EPSILON) - return true; - - final VoxelRayDetails ray = new VoxelRayDetails(); - - for (Direction.Axis axis : Direction.Axis.values()) { - final int index = axis.ordinal(); - final float axisLength = lengthForAxis(traversalVector, axis); - final boolean isPositive = axisLength >= 0; - final float maxPos = lengthForAxis(isPositive ? leadingEdgePos : minBoundsPos, axis); - - ray.absStep[index] = isPositive ? 1 : -1; - ray.minPos[index] = lengthForAxis(isPositive ? minBoundsPos : leadingEdgePos, axis); - ray.leadingEdgeBound[index] = Mth.floor(maxPos - ray.absStep[index] * EPSILON); - ray.trailingEdgeBound[index] = Mth.floor(ray.minPos[index] + ray.absStep[index] * EPSILON); - ray.axisLengthNormalised[index] = axisLength / traversalDistance; - ray.axisSteps[index] = Mth.abs(traversalDistance / axisLength); - final float dist = isPositive - ? (ray.leadingEdgeBound[index] + 1 - maxPos) - : (maxPos - ray.leadingEdgeBound[index]); - ray.rayTargetLength[index] = ray.axisSteps[index] < Float.POSITIVE_INFINITY - ? ray.axisSteps[index] * dist - : Float.POSITIVE_INFINITY; - } - - return collidesWhileTraversing(ray, traversalDistance); - } - - /** - * @param ray The details container for the ray traversal - * @param traversalDistance The direct length of the traversal vector - * @return Whether the given bounds would collide for the given trajectory - */ - default boolean collidesWhileTraversing(VoxelRayDetails ray, float traversalDistance) { - final Mob mob = getMob(); - final Level level = mob.level(); - - try (BulkSectionAccess sectionAccess = new BulkSectionAccess(level)) { - final NodeEvaluator nodeEvaluator = mob.getNavigation().getNodeEvaluator(); - final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); - float target = 0; - - do { - final Direction.Axis longestEdge = ray.rayTargetLength[0] < ray.rayTargetLength[1] - ? ray.rayTargetLength[0] < ray.rayTargetLength[2] ? Direction.Axis.X : Direction.Axis.Z - : ray.rayTargetLength[1] < ray.rayTargetLength[2] ? Direction.Axis.Y : Direction.Axis.Z; - final int index = longestEdge.ordinal(); - final float rayDelta = ray.rayTargetLength[index] - target; - target = ray.rayTargetLength[index]; - ray.leadingEdgeBound[index] += ray.absStep[index]; - ray.rayTargetLength[index] += ray.axisSteps[index]; - - for (Direction.Axis axis : Direction.Axis.values()) { - final int index2 = axis.ordinal(); - ray.minPos[index2] += rayDelta * ray.axisLengthNormalised[index2]; - ray.trailingEdgeBound[index2] = Mth.floor(ray.minPos[index2] + ray.absStep[index2] * EPSILON); - } - - final int xStep = ray.absStep[0]; - final int yStep = ray.absStep[1]; - final int zStep = ray.absStep[2]; - final int xBound = longestEdge == Direction.Axis.X ? ray.leadingEdgeBound[0] : ray.trailingEdgeBound[0]; - final int yBound = longestEdge == Direction.Axis.Y ? ray.leadingEdgeBound[1] : ray.trailingEdgeBound[1]; - final int zBound = longestEdge == Direction.Axis.Z ? ray.leadingEdgeBound[2] : ray.trailingEdgeBound[2]; - final int xStepBound = ray.leadingEdgeBound[0] + xStep; - final int yStepBound = ray.leadingEdgeBound[1] + yStep; - final int zStepBound = ray.leadingEdgeBound[2] + zStep; - - for (int x = xBound; x != xStepBound; x += xStep) { - for (int z = zBound; z != zStepBound; z += zStep) { - for (int y = yBound; y != yStepBound; y += yStep) { - if (!sectionAccess.getBlockState(pos.set(x, y, z)).isPathfindable(PathComputationType.LAND)) - return false; - } - - if ( - !canPathOnto( - nodeEvaluator.getPathType(new PathfindingContext(level, mob), x, yBound - 1, z) - ) - ) - return false; - - final PathType insidePathType = nodeEvaluator.getPathType( - new PathfindingContext(level, mob), - x, - yBound, - z - ); - final float pathMalus = mob.getPathfindingMalus(insidePathType); - - if (pathMalus < 0 || pathMalus >= 8) - return false; - - if (canPathInto(insidePathType)) - return false; - } - } - } while (target <= traversalDistance); - } - - return true; - } - - /** - * Container object for voxel ray traversal details - *