From b034184f8a3e28c1f4a7e22d4b8ad53cde81bb17 Mon Sep 17 00:00:00 2001 From: NotEvil Date: Wed, 22 Apr 2026 02:45:18 +0200 Subject: [PATCH] WIP: fork patch/collider/codec stubs, 464->135 compile errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 0 compile progress (70% reduction). Core data model compile : Refs yesman.epicfight strippées (hors 4 javadocs) : - AnimationProperty : combat properties EXTRA_DAMAGE, STUN_TYPE, PARTICLE - ClientAnimator : playAnimationAt(..., AnimatorControlPacket.Layer, Priority) - ClothSimulator : OBBCollider -> fork geometry-only dans rig/collider/ - InstantiateInvoker : Collider, ColliderPreset, Armatures, DatapackEditScreen - MoveCoordFunctions : GrapplingAttackAnimation - SimulationTypes : InverseKinematicsSimulator (path rewrite) Stubs patch/ : - EntityPatch abstract — getOriginal, isLogicalClient, getMatrix, getAngleTo - LivingEntityPatch abstract — getAnimator, getArmature, getTarget, getYRot* - MobPatch — instanceof check only - item/CapabilityItem — type marker Forks utilitaires : - rig/collider/OBBCollider — geometry only (strip Entity collision, drawInternal) - anim/types/StateSpectrum — identique EF, imports rewrités - util/PacketBufferCodec — StreamCodec backport - util/TimePairList — identique EF - util/HitEntityList — shell pour Priority enum uniquement - util/ExtendableEnum + ExtendableEnumManager — register/assign enum Fix package declarations : - armature/Joint.java + JointTransform.java : package rig.anim -> rig.armature - Imports JointTransform ajoutés dans anim/{Pose,Keyframe,TransformSheet} Residu 135 errors = cluster rendering (Phase 2) : - render/TiedUpRenderTypes (17) : CompositeState package-private MC - event/PatchedRenderersEvent (11) : missing PatchedEntityRenderer - mesh/SkinnedMesh (13) : VanillaMeshPartDefinition, compute shader fields - asset/JsonAssetLoader (6), anim/LivingMotion (5) --- .../remake/rig/anim/AnimationManager.java | 95 +-- .../rig/anim/AnimationVariablePacket.java | 31 + .../remake/rig/anim/AnimationVariables.java | 2 +- .../com/tiedup/remake/rig/anim/Keyframe.java | 2 + .../java/com/tiedup/remake/rig/anim/Pose.java | 2 + .../rig/anim/SynchedAnimationVariableKey.java | 15 +- .../remake/rig/anim/TransformSheet.java | 1 + .../rig/anim/client/ClientAnimator.java | 14 +- .../rig/anim/property/AnimationProperty.java | 18 +- .../rig/anim/property/MoveCoordFunctions.java | 2 +- .../rig/anim/types/ActionAnimation.java | 404 +----------- .../rig/anim/types/AttackAnimation.java | 582 +----------------- .../rig/anim/types/MainFrameAnimation.java | 93 +-- .../remake/rig/anim/types/StateSpectrum.java | 288 +++++++++ .../rig/anim/types/StaticAnimation.java | 72 +-- .../com/tiedup/remake/rig/armature/Joint.java | 2 +- .../remake/rig/armature/JointTransform.java | 2 +- .../remake/rig/cloth/AbstractSimulator.java | 8 +- .../remake/rig/cloth/ClothSimulatable.java | 2 +- .../remake/rig/cloth/ClothSimulator.java | 4 +- .../remake/rig/collider/OBBCollider.java | 81 +++ .../tiedup/remake/rig/mesh/SkinnedMesh.java | 4 +- .../remake/rig/mesh/SoftBodyTranslatable.java | 2 +- .../remake/rig/patch/ClientPlayerPatch.java | 479 -------------- .../tiedup/remake/rig/patch/EntityPatch.java | 83 +++ .../remake/rig/patch/LivingEntityPatch.java | 96 +++ .../remake/rig/patch/LocalPlayerPatch.java | 579 ----------------- .../com/tiedup/remake/rig/patch/MobPatch.java | 17 + .../remake/rig/patch/item/CapabilityItem.java | 15 + .../remake/rig/physics/PhysicsSimulator.java | 28 + .../remake/rig/physics/SimulatableObject.java | 13 + .../remake/rig/physics/SimulationObject.java | 17 + .../rig/physics/SimulationProvider.java | 15 + .../remake/rig/physics/SimulationTypes.java | 24 + .../physics/ik/InverseKinematicsProvider.java | 35 ++ .../ik/InverseKinematicsSimulatable.java | 15 + .../ik/InverseKinematicsSimulator.java | 47 ++ .../render/compute/ComputeShaderProvider.java | 27 + .../render/compute/ComputeShaderSetup.java | 43 ++ .../remake/rig/util/ExtendableEnum.java | 11 + .../rig/util/ExtendableEnumManager.java | 116 ++++ .../tiedup/remake/rig/util/HitEntityList.java | 19 + .../remake/rig/util/InstantiateInvoker.java | 254 ++++++++ .../remake/rig/util/MutableBoolean.java | 48 ++ .../remake/rig/util/PacketBufferCodec.java | 78 +++ .../tiedup/remake/rig/util/TimePairList.java | 49 ++ 46 files changed, 1574 insertions(+), 2260 deletions(-) create mode 100644 src/main/java/com/tiedup/remake/rig/anim/AnimationVariablePacket.java create mode 100644 src/main/java/com/tiedup/remake/rig/anim/types/StateSpectrum.java create mode 100644 src/main/java/com/tiedup/remake/rig/collider/OBBCollider.java delete mode 100644 src/main/java/com/tiedup/remake/rig/patch/ClientPlayerPatch.java create mode 100644 src/main/java/com/tiedup/remake/rig/patch/EntityPatch.java create mode 100644 src/main/java/com/tiedup/remake/rig/patch/LivingEntityPatch.java delete mode 100644 src/main/java/com/tiedup/remake/rig/patch/LocalPlayerPatch.java create mode 100644 src/main/java/com/tiedup/remake/rig/patch/MobPatch.java create mode 100644 src/main/java/com/tiedup/remake/rig/patch/item/CapabilityItem.java create mode 100644 src/main/java/com/tiedup/remake/rig/physics/PhysicsSimulator.java create mode 100644 src/main/java/com/tiedup/remake/rig/physics/SimulatableObject.java create mode 100644 src/main/java/com/tiedup/remake/rig/physics/SimulationObject.java create mode 100644 src/main/java/com/tiedup/remake/rig/physics/SimulationProvider.java create mode 100644 src/main/java/com/tiedup/remake/rig/physics/SimulationTypes.java create mode 100644 src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsProvider.java create mode 100644 src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsSimulatable.java create mode 100644 src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsSimulator.java create mode 100644 src/main/java/com/tiedup/remake/rig/render/compute/ComputeShaderProvider.java create mode 100644 src/main/java/com/tiedup/remake/rig/render/compute/ComputeShaderSetup.java create mode 100644 src/main/java/com/tiedup/remake/rig/util/ExtendableEnum.java create mode 100644 src/main/java/com/tiedup/remake/rig/util/ExtendableEnumManager.java create mode 100644 src/main/java/com/tiedup/remake/rig/util/HitEntityList.java create mode 100644 src/main/java/com/tiedup/remake/rig/util/InstantiateInvoker.java create mode 100644 src/main/java/com/tiedup/remake/rig/util/MutableBoolean.java create mode 100644 src/main/java/com/tiedup/remake/rig/util/PacketBufferCodec.java create mode 100644 src/main/java/com/tiedup/remake/rig/util/TimePairList.java diff --git a/src/main/java/com/tiedup/remake/rig/anim/AnimationManager.java b/src/main/java/com/tiedup/remake/rig/anim/AnimationManager.java index 34c06da..1f81340 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/AnimationManager.java +++ b/src/main/java/com/tiedup/remake/rig/anim/AnimationManager.java @@ -56,15 +56,11 @@ import com.tiedup.remake.rig.anim.types.StaticAnimation; import com.tiedup.remake.rig.asset.AssetAccessor; import com.tiedup.remake.rig.asset.JsonAssetLoader; import com.tiedup.remake.rig.anim.client.AnimationSubFileReader; -import yesman.epicfight.api.data.reloader.SkillManager; import com.tiedup.remake.rig.exception.AssetLoadingException; import com.tiedup.remake.rig.util.InstantiateInvoker; import com.tiedup.remake.rig.util.MutableBoolean; import com.tiedup.remake.rig.TiedUpRigRegistry; import com.tiedup.remake.rig.TiedUpRigConstants; -import yesman.epicfight.network.EpicFightNetworkManager; -import yesman.epicfight.network.client.CPCheckAnimationRegistryMatches; -import yesman.epicfight.network.server.SPDatapackSync; @SuppressWarnings("unchecked") public class AnimationManager extends SimplePreparableReloadListener> { @@ -212,7 +208,7 @@ public class AnimationManager extends SimplePreparableReloadListener accessor = AnimationAccessorImpl.create(registryName, getResourcepackAnimationCount(), false, (accessor$2) -> { - try { - return InstantiateInvoker.invoke(invocationCommand, StaticAnimation.class).getResult(); - } catch (Exception e) { - TiedUpRigConstants.LOGGER.warn("Failed at creating animation from server resource pack"); - e.printStackTrace(); - return TiedUpRigRegistry.EMPTY_ANIMATION; - } - }); - - this.animationById.put(id, accessor); - this.animationByName.put(registryName, accessor); - } - } - - int animationCount = this.animations.size(); - String[] registryNames = new String[animationCount]; - - for (int i = 0; i < animationCount; i++) { - String registryName = this.animationById.get(i + 1).registryName().toString(); - registryNames[i] = registryName; - } - - CPCheckAnimationRegistryMatches registrySyncPacket = new CPCheckAnimationRegistryMatches(animationCount, registryNames); - EpicFightNetworkManager.sendToServer(registrySyncPacket); - } - - public void validateClientAnimationRegistry(CPCheckAnimationRegistryMatches msg, ServerGamePacketListenerImpl connection) { - StringBuilder messageBuilder = new StringBuilder(); - int count = 0; - - Set clientAnimationRegistry = new HashSet<> (Set.of(msg.registryNames)); - - for (String registryName : this.animations.keySet().stream().map((rl) -> rl.toString()).toList()) { - if (!clientAnimationRegistry.contains(registryName)) { - // Animations that don't exist in client - if (count < 10) { - messageBuilder.append(registryName); - messageBuilder.append("\n"); - } - - count++; - } else { - clientAnimationRegistry.remove(registryName); - } - } - - // Animations that don't exist in server - for (String registryName : clientAnimationRegistry) { - if (registryName.equals("empty")) { - continue; - } - - if (count < 10) { - messageBuilder.append(registryName); - messageBuilder.append("\n"); - } - - count++; - } - - if (count >= 10) { - messageBuilder.append(Component.translatable("gui.epicfight.warn.animation_unsync.etc", (count - 9)).getString()); - messageBuilder.append("\n"); - } - - if (!messageBuilder.isEmpty()) { - connection.disconnect(Component.translatable("gui.epicfight.warn.animation_unsync", messageBuilder.toString())); - } - } + // RIG : processServerPacket + validateClientAnimationRegistry strippés. + // C'était le protocole datapack-sync EF pour valider que le client a les + // mêmes animations que le serveur au login (important pour les animations + // combat stockées en data/). TiedUp utilise resource pack uniquement + // (assets/) côté client, pas de sync datapack nécessaire. + // Ré-introduire Phase 2+ si on veut un warning quand un pack d'animations + // custom diverge. private static final Set NO_WARNING_MODID = Sets.newHashSet(); diff --git a/src/main/java/com/tiedup/remake/rig/anim/AnimationVariablePacket.java b/src/main/java/com/tiedup/remake/rig/anim/AnimationVariablePacket.java new file mode 100644 index 0000000..ef65cdf --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/anim/AnimationVariablePacket.java @@ -0,0 +1,31 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.anim; + +/** + * RIG stub. Upstream EF : packet commun client/serveur pour sync des + * animation variables (variables partagées entre deux sides pendant une + * animation combat). + * + *

TiedUp Phase 0 : la classe est conservée en stub juste pour l'enum + * {@link Action} utilisé par {@code AnimationVariables.put/remove} et + * {@code SynchedAnimationVariableKey.sync}. Le vrai packet réseau n'est + * pas implémenté — les `sync()` calls sont no-ops côté runtime pour + * l'instant (cf. {@code SynchedAnimationVariableKey.sync}).

+ * + *

Phase 2+ : si on a besoin de sync d'animation variables entre + * serveur et client (cas d'usage non identifié en TiedUp), implémenter + * un vrai packet. Sinon garder le stub et stripper {@code sync()} plus + * tard.

+ */ +public class AnimationVariablePacket { + + public enum Action { + PUT, + REMOVE, + } +} diff --git a/src/main/java/com/tiedup/remake/rig/anim/AnimationVariables.java b/src/main/java/com/tiedup/remake/rig/anim/AnimationVariables.java index 23236c0..cbb9666 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/AnimationVariables.java +++ b/src/main/java/com/tiedup/remake/rig/anim/AnimationVariables.java @@ -22,7 +22,7 @@ import com.tiedup.remake.rig.util.ParseUtil; import com.tiedup.remake.rig.util.datastruct.TypeFlexibleHashMap; import com.tiedup.remake.rig.util.datastruct.TypeFlexibleHashMap.TypeKey; import com.tiedup.remake.rig.TiedUpRigRegistry; -import yesman.epicfight.network.common.AnimationVariablePacket; +import com.tiedup.remake.rig.anim.AnimationVariablePacket; public class AnimationVariables { protected final Animator animator; diff --git a/src/main/java/com/tiedup/remake/rig/anim/Keyframe.java b/src/main/java/com/tiedup/remake/rig/anim/Keyframe.java index afe17cc..84e64ce 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/Keyframe.java +++ b/src/main/java/com/tiedup/remake/rig/anim/Keyframe.java @@ -6,6 +6,8 @@ package com.tiedup.remake.rig.anim; +import com.tiedup.remake.rig.armature.JointTransform; + public class Keyframe { private float timeStamp; private final JointTransform transform; diff --git a/src/main/java/com/tiedup/remake/rig/anim/Pose.java b/src/main/java/com/tiedup/remake/rig/anim/Pose.java index a05bb6b..52945cd 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/Pose.java +++ b/src/main/java/com/tiedup/remake/rig/anim/Pose.java @@ -14,6 +14,8 @@ import java.util.function.BiConsumer; import com.google.common.base.Predicate; import com.google.common.collect.Maps; +import com.tiedup.remake.rig.armature.JointTransform; + public class Pose { public static final Pose EMPTY_POSE = new Pose(); diff --git a/src/main/java/com/tiedup/remake/rig/anim/SynchedAnimationVariableKey.java b/src/main/java/com/tiedup/remake/rig/anim/SynchedAnimationVariableKey.java index 8c8e38b..10bd1d1 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/SynchedAnimationVariableKey.java +++ b/src/main/java/com/tiedup/remake/rig/anim/SynchedAnimationVariableKey.java @@ -22,10 +22,9 @@ import com.tiedup.remake.rig.asset.AssetAccessor; import com.tiedup.remake.rig.util.PacketBufferCodec; import com.tiedup.remake.rig.util.datastruct.ClearableIdMapper; import com.tiedup.remake.rig.TiedUpRigConstants; -import yesman.epicfight.network.EpicFightNetworkManager; -import yesman.epicfight.network.client.CPAnimationVariablePacket; -import yesman.epicfight.network.common.AnimationVariablePacket; -import yesman.epicfight.network.server.SPAnimationVariablePacket; +import com.tiedup.remake.rig.anim.AnimationVariablePacket; +import com.tiedup.remake.rig.anim.AnimationVariablePacket; +import com.tiedup.remake.rig.anim.AnimationVariablePacket; import com.tiedup.remake.rig.patch.LivingEntityPatch; public interface SynchedAnimationVariableKey { @@ -83,11 +82,9 @@ public interface SynchedAnimationVariableKey { } default void sync(LivingEntityPatch entitypatch, @Nullable AssetAccessor animation, T value, AnimationVariablePacket.Action action) { - if (entitypatch.isLogicalClient()) { - EpicFightNetworkManager.sendToServer(new CPAnimationVariablePacket<> (this, animation, value, action)); - } else { - entitypatch.sendToAllPlayersTrackingMe(new SPAnimationVariablePacket<> (entitypatch, this, animation, value, action)); - } + // RIG : sync réseau des animation variables strippé. + // Pas d'usage bondage identifié — ré-implémenter Phase 2 avec packet + // dédié si besoin. Voir AnimationVariablePacket stub. } public static class SynchedSharedAnimationVariableKey extends SharedAnimationVariableKey implements SynchedAnimationVariableKey { diff --git a/src/main/java/com/tiedup/remake/rig/anim/TransformSheet.java b/src/main/java/com/tiedup/remake/rig/anim/TransformSheet.java index 17a792c..30ed3f4 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/TransformSheet.java +++ b/src/main/java/com/tiedup/remake/rig/anim/TransformSheet.java @@ -14,6 +14,7 @@ import org.joml.Quaternionf; import net.minecraft.util.Mth; import net.minecraft.world.phys.Vec3; +import com.tiedup.remake.rig.armature.JointTransform; import com.tiedup.remake.rig.math.MathUtils; import com.tiedup.remake.rig.math.OpenMatrix4f; import com.tiedup.remake.rig.math.Vec3f; diff --git a/src/main/java/com/tiedup/remake/rig/anim/client/ClientAnimator.java b/src/main/java/com/tiedup/remake/rig/anim/client/ClientAnimator.java index 7ef1fa8..102d52a 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/client/ClientAnimator.java +++ b/src/main/java/com/tiedup/remake/rig/anim/client/ClientAnimator.java @@ -15,7 +15,6 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; -import org.jetbrains.annotations.ApiStatus; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -46,7 +45,6 @@ import com.tiedup.remake.rig.anim.client.property.JointMaskEntry; import com.tiedup.remake.rig.util.datastruct.TypeFlexibleHashMap; import com.tiedup.remake.rig.TiedUpRigRegistry; import com.tiedup.remake.rig.TiedUpRigConstants; -import yesman.epicfight.network.common.AnimatorControlPacket; import com.tiedup.remake.rig.patch.LivingEntityPatch; public class ClientAnimator extends Animator { @@ -85,14 +83,10 @@ public class ClientAnimator extends Animator { layer.playAnimation(nextAnimation, this.entitypatch, transitionTimeModifier); } - /** Play an animation with specifying layer and priority **/ - @ApiStatus.Internal - public void playAnimationAt(AssetAccessor nextAnimation, float transitionTimeModifier, AnimatorControlPacket.Layer layerType, AnimatorControlPacket.Priority priority) { - Layer layer = layerType == AnimatorControlPacket.Layer.BASE_LAYER ? this.baseLayer : this.baseLayer.compositeLayers.get(AnimatorControlPacket.getPriority(priority)); - layer.paused = false; - layer.playAnimation(nextAnimation, this.entitypatch, transitionTimeModifier); - } - + // RIG : playAnimationAt(..., AnimatorControlPacket.Layer, AnimatorControlPacket.Priority) + // strippé — re-implem Phase 2 avec packet dédié. Voir AnimationVariablePacket. + + @Override public void playAnimationInstantly(AssetAccessor nextAnimation) { Layer layer = nextAnimation.get().getLayerType() == Layer.LayerType.BASE_LAYER ? this.baseLayer : this.baseLayer.compositeLayers.get(nextAnimation.get().getPriority()); diff --git a/src/main/java/com/tiedup/remake/rig/anim/property/AnimationProperty.java b/src/main/java/com/tiedup/remake/rig/anim/property/AnimationProperty.java index f52c26e..8ce2a7b 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/property/AnimationProperty.java +++ b/src/main/java/com/tiedup/remake/rig/anim/property/AnimationProperty.java @@ -24,7 +24,6 @@ import net.minecraft.sounds.SoundEvent; import net.minecraft.tags.TagKey; import net.minecraft.world.damagesource.DamageType; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.registries.RegistryObject; import com.tiedup.remake.rig.anim.AnimationManager.AnimationAccessor; import com.tiedup.remake.rig.anim.LivingMotion; import com.tiedup.remake.rig.anim.Pose; @@ -36,18 +35,14 @@ import com.tiedup.remake.rig.anim.types.ActionAnimation; import com.tiedup.remake.rig.anim.types.DynamicAnimation; import com.tiedup.remake.rig.anim.types.LinkAnimation; import com.tiedup.remake.rig.anim.types.StaticAnimation; -import yesman.epicfight.api.physics.ik.InverseKinematicsSimulator.BakedInverseKinematicsDefinition; -import yesman.epicfight.api.physics.ik.InverseKinematicsSimulator.InverseKinematicsDefinition; +import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator.BakedInverseKinematicsDefinition; +import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator.InverseKinematicsDefinition; import com.tiedup.remake.rig.util.HitEntityList.Priority; import com.tiedup.remake.rig.util.TimePairList; import com.tiedup.remake.rig.math.ValueModifier; import com.tiedup.remake.rig.TiedUpRigConstants; -import yesman.epicfight.particle.HitParticleType; -import yesman.epicfight.skill.BasicAttack; import com.tiedup.remake.rig.patch.LivingEntityPatch; import com.tiedup.remake.rig.patch.item.CapabilityItem; -import yesman.epicfight.world.damagesource.ExtraDamageInstance; -import yesman.epicfight.world.damagesource.StunType; public abstract class AnimationProperty { private static final Map> SERIALIZABLE_ANIMATION_PROPERTY_KEYS = Maps.newHashMap(); @@ -250,10 +245,11 @@ public abstract class AnimationProperty { public static final ActionAnimationProperty COORD_UPDATE_TIME = new ActionAnimationProperty (); /** - * This property determines if it reset the player basic attack combo counter or not {@link BasicAttack} + * This property determines if it reset the player basic attack combo counter or not. + * RIG : BasicAttack strippé, flag conservé pour compat JSON. */ public static final ActionAnimationProperty RESET_PLAYER_COMBO_COUNTER = new ActionAnimationProperty ("reset_combo_attack_counter", Codec.BOOL); - + /** * Provide destination of action animation {@link MoveCoordFunctions} */ @@ -333,11 +329,9 @@ public abstract class AnimationProperty { public static final AttackPhaseProperty DAMAGE_MODIFIER = new AttackPhaseProperty ("damage", ValueModifier.CODEC); public static final AttackPhaseProperty ARMOR_NEGATION_MODIFIER = new AttackPhaseProperty ("armor_negation", ValueModifier.CODEC); public static final AttackPhaseProperty IMPACT_MODIFIER = new AttackPhaseProperty ("impact", ValueModifier.CODEC); - public static final AttackPhaseProperty> EXTRA_DAMAGE = new AttackPhaseProperty> (); - public static final AttackPhaseProperty STUN_TYPE = new AttackPhaseProperty (); + // RIG : EXTRA_DAMAGE, STUN_TYPE, PARTICLE strippés (combat). public static final AttackPhaseProperty SWING_SOUND = new AttackPhaseProperty (); public static final AttackPhaseProperty HIT_SOUND = new AttackPhaseProperty (); - public static final AttackPhaseProperty> PARTICLE = new AttackPhaseProperty> (); public static final AttackPhaseProperty HIT_PRIORITY = new AttackPhaseProperty (); public static final AttackPhaseProperty>> SOURCE_TAG = new AttackPhaseProperty>> (); public static final AttackPhaseProperty, Vec3>> SOURCE_LOCATION_PROVIDER = new AttackPhaseProperty, Vec3>> (); diff --git a/src/main/java/com/tiedup/remake/rig/anim/property/MoveCoordFunctions.java b/src/main/java/com/tiedup/remake/rig/anim/property/MoveCoordFunctions.java index 0d068cf..e24f6ee 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/property/MoveCoordFunctions.java +++ b/src/main/java/com/tiedup/remake/rig/anim/property/MoveCoordFunctions.java @@ -33,7 +33,7 @@ import com.tiedup.remake.rig.anim.types.AttackAnimation; import com.tiedup.remake.rig.anim.types.AttackAnimation.Phase; import com.tiedup.remake.rig.anim.types.DynamicAnimation; import com.tiedup.remake.rig.anim.types.EntityState; -import com.tiedup.remake.rig.anim.types.grappling.GrapplingAttackAnimation; +// RIG : GrapplingAttackAnimation strippé (combat grappling hook), ref javadoc conservée import com.tiedup.remake.rig.math.MathUtils; import com.tiedup.remake.rig.math.OpenMatrix4f; import com.tiedup.remake.rig.math.Vec3f; diff --git a/src/main/java/com/tiedup/remake/rig/anim/types/ActionAnimation.java b/src/main/java/com/tiedup/remake/rig/anim/types/ActionAnimation.java index e1b613c..1062f09 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/types/ActionAnimation.java +++ b/src/main/java/com/tiedup/remake/rig/anim/types/ActionAnimation.java @@ -6,400 +6,32 @@ package com.tiedup.remake.rig.anim.types; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import net.minecraft.util.Mth; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.MoverType; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.ForgeMod; -import com.tiedup.remake.rig.anim.AnimationManager.AnimationAccessor; -import com.tiedup.remake.rig.anim.AnimationPlayer; -import com.tiedup.remake.rig.anim.AnimationVariables; -import com.tiedup.remake.rig.anim.AnimationVariables.IndependentAnimationVariableKey; -import com.tiedup.remake.rig.anim.AnimationVariables.SharedAnimationVariableKey; -import com.tiedup.remake.rig.armature.JointTransform; -import com.tiedup.remake.rig.anim.Keyframe; -import com.tiedup.remake.rig.anim.Pose; -import com.tiedup.remake.rig.anim.TransformSheet; import com.tiedup.remake.rig.anim.property.AnimationProperty.ActionAnimationProperty; -import com.tiedup.remake.rig.anim.property.AnimationProperty.AttackAnimationProperty; -import com.tiedup.remake.rig.anim.property.AnimationProperty.PlaybackSpeedModifier; -import com.tiedup.remake.rig.anim.property.AnimationProperty.StaticAnimationProperty; -import com.tiedup.remake.rig.anim.property.MoveCoordFunctions; -import com.tiedup.remake.rig.anim.property.MoveCoordFunctions.MoveCoordGetter; -import com.tiedup.remake.rig.anim.property.MoveCoordFunctions.MoveCoordSetter; -import com.tiedup.remake.rig.asset.AssetAccessor; -import com.tiedup.remake.rig.anim.client.Layer; -import com.tiedup.remake.rig.anim.client.property.ClientAnimationProperties; -import com.tiedup.remake.rig.anim.client.property.JointMaskEntry; import com.tiedup.remake.rig.armature.Armature; -import com.tiedup.remake.rig.util.TimePairList; -import com.tiedup.remake.rig.math.MathUtils; -import com.tiedup.remake.rig.math.OpenMatrix4f; -import com.tiedup.remake.rig.math.Vec3f; -import com.tiedup.remake.rig.patch.LocalPlayerPatch; -import com.tiedup.remake.rig.TiedUpRigConstants; -import yesman.epicfight.network.EpicFightNetworkManager; -import yesman.epicfight.network.client.CPSyncPlayerAnimationPosition; -import yesman.epicfight.network.server.SPSyncAnimationPosition; -import com.tiedup.remake.rig.patch.LivingEntityPatch; +import com.tiedup.remake.rig.asset.AssetAccessor; +/** + * RIG stub. Upstream EF : ActionAnimation ajoute un système de COORD + * TransformSheet pour les mouvements d'attaque en espace monde + des + * packets sync serveur/client via {@code CPSyncPlayerAnimationPosition}. + * Strippé pour TiedUp — garde juste l'API {@code addProperty} utilisée par + * {@link com.tiedup.remake.rig.asset.JsonAssetLoader} (ligne 621). + */ public class ActionAnimation extends MainFrameAnimation { - public static final SharedAnimationVariableKey ACTION_ANIMATION_COORD = AnimationVariables.shared((animator) -> new TransformSheet(), false); - public static final IndependentAnimationVariableKey BEGINNING_LOCATION = AnimationVariables.independent((animator) -> animator.getEntityPatch().getOriginal().position(), true); - public static final IndependentAnimationVariableKey INITIAL_LOOK_VEC_DOT = AnimationVariables.independent((animator) -> 1.0F, true); - - public ActionAnimation(float transitionTime, AnimationAccessor accessor, AssetAccessor armature) { - this(transitionTime, Float.MAX_VALUE, accessor, armature); - } - - public ActionAnimation(float transitionTime, float postDelay, AnimationAccessor accessor, AssetAccessor armature) { - super(transitionTime, accessor, armature); - - this.stateSpectrumBlueprint.clear() - .newTimePair(0.0F, postDelay) - .addState(EntityState.MOVEMENT_LOCKED, true) - .addState(EntityState.UPDATE_LIVING_MOTION, false) - .addState(EntityState.CAN_BASIC_ATTACK, false) - .addState(EntityState.CAN_SKILL_EXECUTION, false) - .addState(EntityState.TURNING_LOCKED, true) - .newTimePair(0.0F, Float.MAX_VALUE) - .addState(EntityState.INACTION, true); - - this.addProperty(StaticAnimationProperty.FIXED_HEAD_ROTATION, true); - } - - /** - * For resourcepack animations - */ - public ActionAnimation(float transitionTime, float postDelay, String path, AssetAccessor armature) { - super(transitionTime, path, armature); - - this.stateSpectrumBlueprint.clear() - .newTimePair(0.0F, postDelay) - .addState(EntityState.MOVEMENT_LOCKED, true) - .addState(EntityState.UPDATE_LIVING_MOTION, false) - .addState(EntityState.CAN_BASIC_ATTACK, false) - .addState(EntityState.CAN_SKILL_EXECUTION, false) - .addState(EntityState.TURNING_LOCKED, true) - .newTimePair(0.0F, Float.MAX_VALUE) - .addState(EntityState.INACTION, true); - - this.addProperty(StaticAnimationProperty.FIXED_HEAD_ROTATION, true); - } - - @Override - public void putOnPlayer(AnimationPlayer animationPlayer, LivingEntityPatch entitypatch) { - if (entitypatch.shouldMoveOnCurrentSide(this)) { - MoveCoordSetter moveCoordSetter = this.getProperty(ActionAnimationProperty.COORD_SET_BEGIN).orElse(MoveCoordFunctions.RAW_COORD); - moveCoordSetter.set(this, entitypatch, entitypatch.getAnimator().getVariables().getOrDefaultSharedVariable(ACTION_ANIMATION_COORD)); - } - - super.putOnPlayer(animationPlayer, entitypatch); - } - - protected void initCoordVariables(LivingEntityPatch entitypatch) { - Vec3 start = entitypatch.getOriginal().position(); - - if (entitypatch.getTarget() != null) { - Vec3 targetTracePosition = entitypatch.getTarget().position(); - Vec3 toDestWorld = targetTracePosition.subtract(start); - float dot = Mth.clamp((float)toDestWorld.normalize().dot(MathUtils.getVectorForRotation(0.0F, entitypatch.getYRot())), 0.0F, 1.0F); - entitypatch.getAnimator().getVariables().put(INITIAL_LOOK_VEC_DOT, this.getAccessor(), dot); - } - - entitypatch.getAnimator().getVariables().put(BEGINNING_LOCATION, this.getAccessor(), start); - } - - @Override - public void begin(LivingEntityPatch entitypatch) { - entitypatch.cancelItemUse(); - - super.begin(entitypatch); - - if (entitypatch.shouldMoveOnCurrentSide(this)) { - entitypatch.beginAction(this); - - this.initCoordVariables(entitypatch); - - if (this.getProperty(ActionAnimationProperty.STOP_MOVEMENT).orElse(false)) { - entitypatch.getOriginal().setDeltaMovement(0.0D, entitypatch.getOriginal().getDeltaMovement().y, 0.0D); - entitypatch.getOriginal().xxa = 0.0F; - entitypatch.getOriginal().yya = 0.0F; - entitypatch.getOriginal().zza = 0.0F; - } - } - } - - @Override - public void tick(LivingEntityPatch entitypatch) { - super.tick(entitypatch); - - if (this.getProperty(ActionAnimationProperty.REMOVE_DELTA_MOVEMENT).orElse(false)) { - double gravity = this.getProperty(ActionAnimationProperty.MOVE_VERTICAL).orElse(false) ? 0.0D : entitypatch.getOriginal().getDeltaMovement().y; - entitypatch.getOriginal().setDeltaMovement(0.0D, gravity, 0.0D); - } - - this.move(entitypatch, this.getAccessor()); - } - - @Override - public void linkTick(LivingEntityPatch entitypatch, AssetAccessor linkAnimation) { - if (this.getProperty(ActionAnimationProperty.REMOVE_DELTA_MOVEMENT).orElse(false)) { - double gravity = this.getProperty(ActionAnimationProperty.MOVE_VERTICAL).orElse(false) ? 0.0D : entitypatch.getOriginal().getDeltaMovement().y; - entitypatch.getOriginal().setDeltaMovement(0.0D, gravity, 0.0D); - } - - this.move(entitypatch, linkAnimation); + + public ActionAnimation(float transitionTime, boolean isRepeat, String registryName, AssetAccessor armature) { + super(transitionTime, isRepeat, registryName, armature); } - protected void move(LivingEntityPatch entitypatch, AssetAccessor animation) { - if (!this.validateMovement(entitypatch, animation)) { - return; - } - - float elapsedTime = entitypatch.getAnimator().getPlayerFor(this.getAccessor()).getElapsedTime(); - - if (this.getState(EntityState.INACTION, entitypatch, elapsedTime)) { - LivingEntity livingentity = entitypatch.getOriginal(); - Vec3 vec3 = this.getCoordVector(entitypatch, animation); - livingentity.move(MoverType.SELF, vec3); - - if (entitypatch.isLogicalClient()) { - EpicFightNetworkManager.sendToServer(new CPSyncPlayerAnimationPosition(livingentity.getId(), elapsedTime, livingentity.position(), animation.get().isLinkAnimation() ? 2 : 1)); - } else { - EpicFightNetworkManager.sendToAllPlayerTrackingThisEntity(new SPSyncAnimationPosition(livingentity.getId(), elapsedTime, livingentity.position(), animation.get().isLinkAnimation() ? 2 : 1), livingentity); - } - } + public ActionAnimation(boolean isRepeat, String registryName, AssetAccessor armature) { + super(isRepeat, registryName, armature); } - - protected boolean validateMovement(LivingEntityPatch entitypatch, AssetAccessor animation) { - if (!entitypatch.shouldMoveOnCurrentSide(this)) { - return false; - } - - if (animation.get().isLinkAnimation()) { - if (!this.getProperty(ActionAnimationProperty.MOVE_ON_LINK).orElse(true)) { - return false; - } else { - return this.shouldMove(0.0F); - } - } else { - return this.shouldMove(entitypatch.getAnimator().getPlayerFor(animation).getElapsedTime()); - } - } - - protected boolean shouldMove(float currentTime) { - if (this.properties.containsKey(ActionAnimationProperty.MOVE_TIME)) { - TimePairList moveTimes = this.getProperty(ActionAnimationProperty.MOVE_TIME).get(); - return moveTimes.isTimeInPairs(currentTime); - } else { - return true; - } - } - - @Override - public void modifyPose(DynamicAnimation animation, Pose pose, LivingEntityPatch entitypatch, float time, float partialTicks) { - if (this.getProperty(ActionAnimationProperty.COORD).isEmpty()) { - this.correctRootJoint(animation, pose, entitypatch, time, partialTicks); - } - - super.modifyPose(animation, pose, entitypatch, time, partialTicks); - } - - public void correctRootJoint(DynamicAnimation animation, Pose pose, LivingEntityPatch entitypatch, float time, float partialTicks) { - JointTransform jt = pose.orElseEmpty("Root"); - Vec3f jointPosition = jt.translation(); - OpenMatrix4f toRootTransformApplied = entitypatch.getArmature().searchJointByName("Root").getLocalTransform().removeTranslation(); - OpenMatrix4f toOrigin = OpenMatrix4f.invert(toRootTransformApplied, null); - Vec3f worldPosition = OpenMatrix4f.transform3v(toRootTransformApplied, jointPosition, null); - worldPosition.x = 0.0F; - worldPosition.y = (this.getProperty(ActionAnimationProperty.MOVE_VERTICAL).orElse(false) && worldPosition.y > 0.0F) ? 0.0F : worldPosition.y; - worldPosition.z = 0.0F; - OpenMatrix4f.transform3v(toOrigin, worldPosition, worldPosition); - jointPosition.x = worldPosition.x; - jointPosition.y = worldPosition.y; - jointPosition.z = worldPosition.z; - } - - @Override - public void setLinkAnimation(AssetAccessor fromAnimation, Pose startPose, boolean isOnSameLayer, float transitionTimeModifier, LivingEntityPatch entitypatch, LinkAnimation dest) { - dest.resetNextStartTime(); - float playTime = this.getPlaySpeed(entitypatch, dest); - PlaybackSpeedModifier playSpeedModifier = this.getRealAnimation().get().getProperty(StaticAnimationProperty.PLAY_SPEED_MODIFIER).orElse(null); - - if (playSpeedModifier != null) { - playTime = playSpeedModifier.modify(this, entitypatch, playTime, 0.0F, playTime); - } - - playTime = Math.abs(playTime) * TiedUpRigConstants.A_TICK; - - float linkTime = (transitionTimeModifier > 0.0F) ? transitionTimeModifier + this.transitionTime : this.transitionTime; - float totalTime = playTime * (int)Math.ceil(linkTime / playTime); - float nextStartTime = Math.max(0.0F, -transitionTimeModifier); - nextStartTime += totalTime - linkTime; - - dest.setNextStartTime(nextStartTime); - dest.getAnimationClip().reset(); - dest.setTotalTime(totalTime); - dest.setConnectedAnimations(fromAnimation, this.getAccessor()); - - Pose nextStartPose = this.getPoseByTime(entitypatch, nextStartTime, 1.0F); - - if (entitypatch.shouldMoveOnCurrentSide(this) && this.getProperty(ActionAnimationProperty.MOVE_ON_LINK).orElse(true)) { - this.correctRawZCoord(entitypatch, nextStartPose, nextStartTime); - } - - Map data1 = startPose.getJointTransformData(); - Map data2 = nextStartPose.getJointTransformData(); - Set joint1 = new HashSet<> (isOnSameLayer ? data1.keySet() : Set.of()); - Set joint2 = new HashSet<> (data2.keySet()); - - if (entitypatch.isLogicalClient()) { - JointMaskEntry entry = fromAnimation.get().getJointMaskEntry(entitypatch, false).orElse(null); - JointMaskEntry entry2 = this.getJointMaskEntry(entitypatch, true).orElse(null); - - if (entry != null && entitypatch.isLogicalClient()) { - joint1.removeIf((jointName) -> entry.isMasked(fromAnimation.get().getProperty(ClientAnimationProperties.LAYER_TYPE).orElse(Layer.LayerType.BASE_LAYER) == Layer.LayerType.BASE_LAYER ? - entitypatch.getClientAnimator().currentMotion() : entitypatch.getClientAnimator().currentCompositeMotion(), jointName)); - } - - if (entry2 != null && entitypatch.isLogicalClient()) { - joint2.removeIf((jointName) -> entry2.isMasked(this.getProperty(ClientAnimationProperties.LAYER_TYPE).orElse(Layer.LayerType.BASE_LAYER) == Layer.LayerType.BASE_LAYER ? - entitypatch.getCurrentLivingMotion() : entitypatch.currentCompositeMotion, jointName)); - } - } - - joint1.addAll(joint2); - - if (linkTime != totalTime) { - Pose pose = this.getPoseByTime(entitypatch, 0.0F, 0.0F); - Map poseData = pose.getJointTransformData(); - - if (entitypatch.shouldMoveOnCurrentSide(this) && this.getProperty(ActionAnimationProperty.MOVE_ON_LINK).orElse(true)) { - this.correctRawZCoord(entitypatch, pose, 0.0F); - } - - for (String jointName : joint1) { - Keyframe[] keyframes = new Keyframe[3]; - keyframes[0] = new Keyframe(0.0F, data1.getOrDefault(jointName, JointTransform.empty())); - keyframes[1] = new Keyframe(linkTime, poseData.getOrDefault(jointName, JointTransform.empty())); - keyframes[2] = new Keyframe(totalTime, data2.getOrDefault(jointName, JointTransform.empty())); - - TransformSheet sheet = new TransformSheet(keyframes); - dest.getAnimationClip().addJointTransform(jointName, sheet); - } - } else { - for (String jointName : joint1) { - Keyframe[] keyframes = new Keyframe[2]; - keyframes[0] = new Keyframe(0.0F, data1.getOrDefault(jointName, JointTransform.empty())); - keyframes[1] = new Keyframe(totalTime, data2.getOrDefault(jointName, JointTransform.empty())); - - TransformSheet sheet = new TransformSheet(keyframes); - dest.getAnimationClip().addJointTransform(jointName, sheet); - } - } - - dest.loadCoord(null); - - this.getProperty(ActionAnimationProperty.COORD).ifPresent((coord) -> { - Keyframe[] keyframes = new Keyframe[2]; - keyframes[0] = new Keyframe(0.0F, JointTransform.empty()); - keyframes[1] = new Keyframe(totalTime, coord.getKeyframes()[0].transform()); - - TransformSheet sheet = new TransformSheet(keyframes); - dest.loadCoord(sheet); - }); - - if (entitypatch.shouldMoveOnCurrentSide(this)) { - MoveCoordSetter moveCoordSetter = this.getProperty(ActionAnimationProperty.COORD_SET_BEGIN).orElse(MoveCoordFunctions.RAW_COORD); - moveCoordSetter.set(dest, entitypatch, entitypatch.getAnimator().getVariables().getOrDefaultSharedVariable(ACTION_ANIMATION_COORD)); - } - } - - public void correctRawZCoord(LivingEntityPatch entitypatch, Pose pose, float poseTime) { - JointTransform jt = pose.orElseEmpty("Root"); - - if (this.getProperty(ActionAnimationProperty.COORD).isEmpty()) { - TransformSheet coordTransform = this.getTransfroms().get("Root"); - jt.translation().add(0.0F, 0.0F, coordTransform.getInterpolatedTranslation(poseTime).z); - } - } - + /** - * Get an expected movement vector in specific time - * - * @param entitypatch - * @param elapseTime - * @return + * Ajoute une propriété action-specific (COORD TransformSheet typiquement). + * Version stub : no-op, juste pour que les refs JsonAssetLoader compilent. */ - public Vec3 getExpectedMovement(LivingEntityPatch entitypatch, float elapseTime) { - this.initCoordVariables(entitypatch); - - TransformSheet coordTransform = new TransformSheet(); - MoveCoordSetter moveCoordSetter = this.getProperty(ActionAnimationProperty.COORD_SET_BEGIN).orElse(MoveCoordFunctions.RAW_COORD); - moveCoordSetter.set(this, entitypatch, coordTransform); - - MoveCoordGetter moveGetter = this.getProperty(ActionAnimationProperty.COORD_GET).orElse(MoveCoordFunctions.MODEL_COORD); - Vec3f move = moveGetter.get(this, entitypatch, coordTransform, 0.0F, elapseTime); - - return move.toDoubleVector(); - } - - protected Vec3 getCoordVector(LivingEntityPatch entitypatch, AssetAccessor animation) { - AnimationPlayer player = entitypatch.getAnimator().getPlayerFor(animation); - TimePairList coordUpdateTime = this.getProperty(ActionAnimationProperty.COORD_UPDATE_TIME).orElse(null); - boolean inUpdateTime = coordUpdateTime == null || coordUpdateTime.isTimeInPairs(player.getElapsedTime()); - boolean getRawCoord = this.getProperty(AttackAnimationProperty.FIXED_MOVE_DISTANCE).orElse(!inUpdateTime); - TransformSheet transformSheet = entitypatch.getAnimator().getVariables().getOrDefaultSharedVariable(ACTION_ANIMATION_COORD); - MoveCoordSetter moveCoordsetter = getRawCoord ? MoveCoordFunctions.RAW_COORD : this.getProperty(ActionAnimationProperty.COORD_SET_TICK).orElse(null); - - if (moveCoordsetter != null) { - moveCoordsetter.set(animation.get(), entitypatch, transformSheet); - } - - boolean hasNoGravity = entitypatch.getOriginal().isNoGravity(); - boolean moveVertical = this.getProperty(ActionAnimationProperty.MOVE_VERTICAL).orElse(this.getProperty(ActionAnimationProperty.COORD).isPresent()); - MoveCoordGetter moveGetter = getRawCoord ? MoveCoordFunctions.MODEL_COORD : this.getProperty(ActionAnimationProperty.COORD_GET).orElse(MoveCoordFunctions.MODEL_COORD); - - Vec3f move = moveGetter.get(animation.get(), entitypatch, transformSheet, player.getPrevElapsedTime(), player.getElapsedTime()); - LivingEntity livingentity = entitypatch.getOriginal(); - Vec3 motion = livingentity.getDeltaMovement(); - - this.getProperty(ActionAnimationProperty.NO_GRAVITY_TIME).ifPresentOrElse((noGravityTime) -> { - if (noGravityTime.isTimeInPairs(animation.get().isLinkAnimation() ? 0.0F : player.getElapsedTime())) { - livingentity.setDeltaMovement(motion.x, 0.0D, motion.z); - } else { - move.y = 0.0F; - } - }, () -> { - if (moveVertical && move.y > 0.0F && !hasNoGravity) { - double gravity = livingentity.getAttribute(ForgeMod.ENTITY_GRAVITY.get()).getValue(); - livingentity.setDeltaMovement(motion.x, motion.y < 0.0D ? motion.y + gravity : 0.0D, motion.z); - } - }); - - if (!moveVertical) { - move.y = 0.0F; - } - - if (inUpdateTime) { - this.getProperty(ActionAnimationProperty.ENTITY_YROT_PROVIDER).ifPresent((entityYRotProvider) -> { - float yRot = entityYRotProvider.get(animation.get(), entitypatch); - entitypatch.setYRot(yRot); - }); - } - - return move.toDoubleVector(); - } - - @OnlyIn(Dist.CLIENT) - public boolean shouldPlayerMove(LocalPlayerPatch playerpatch) { - return playerpatch.isLogicalClient(); + public ActionAnimation addProperty(ActionAnimationProperty property, V value) { + return this; } } diff --git a/src/main/java/com/tiedup/remake/rig/anim/types/AttackAnimation.java b/src/main/java/com/tiedup/remake/rig/anim/types/AttackAnimation.java index c1bc7d5..e765701 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/types/AttackAnimation.java +++ b/src/main/java/com/tiedup/remake/rig/anim/types/AttackAnimation.java @@ -6,565 +6,51 @@ package com.tiedup.remake.rig.anim.types; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import javax.annotation.Nullable; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.datafixers.util.Pair; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.entity.PartEntity; -import net.minecraftforge.registries.RegistryObject; -import com.tiedup.remake.rig.anim.AnimationManager.AnimationAccessor; -import com.tiedup.remake.rig.anim.AnimationPlayer; -import com.tiedup.remake.rig.anim.AnimationVariables; -import com.tiedup.remake.rig.anim.AnimationVariables.SharedAnimationVariableKey; -import com.tiedup.remake.rig.armature.Joint; -import com.tiedup.remake.rig.anim.property.AnimationProperty.ActionAnimationProperty; -import com.tiedup.remake.rig.anim.property.AnimationProperty.AttackAnimationProperty; -import com.tiedup.remake.rig.anim.property.AnimationProperty.AttackPhaseProperty; -import com.tiedup.remake.rig.anim.property.MoveCoordFunctions; -import com.tiedup.remake.rig.anim.types.EntityState.StateFactor; -import com.tiedup.remake.rig.asset.AssetAccessor; -import yesman.epicfight.api.collider.Collider; import com.tiedup.remake.rig.armature.Armature; -import com.tiedup.remake.rig.util.AttackResult; -import com.tiedup.remake.rig.util.HitEntityList; -import com.tiedup.remake.rig.math.MathUtils; -import com.tiedup.remake.rig.math.ValueModifier; -import com.tiedup.remake.rig.TiedUpRigConstants; -import yesman.epicfight.particle.HitParticleType; -import com.tiedup.remake.rig.patch.HumanoidMobPatch; -import com.tiedup.remake.rig.patch.LivingEntityPatch; -import com.tiedup.remake.rig.patch.PlayerPatch; -import com.tiedup.remake.rig.patch.ServerPlayerPatch; -import yesman.epicfight.world.damagesource.EpicFightDamageSource; -import yesman.epicfight.world.damagesource.EpicFightDamageSources; -import yesman.epicfight.world.entity.eventlistener.AttackEndEvent; -import yesman.epicfight.world.entity.eventlistener.AttackPhaseEndEvent; -import yesman.epicfight.world.entity.eventlistener.PlayerEventListener.EventType; +import com.tiedup.remake.rig.asset.AssetAccessor; +/** + * RIG stub. Upstream EF : AttackAnimation = système d'attaque combat (570L, + * Phase timings, hitboxes, damage source, attack events, colliders). 100% + * combat, strippé en stub minimal pour TiedUp. + * + *

On conserve :

+ *
    + *
  • Le type {@code AttackAnimation} pour les {@code instanceof} dans + * {@link com.tiedup.remake.rig.asset.JsonAssetLoader}:584
  • + *
  • Le field {@code phases} (liste vide) pour la boucle d'itération + * en JsonAssetLoader:591
  • + *
  • La classe interne {@link Phase} avec un {@code getColliders()} + * no-op pour JsonAssetLoader:592
  • + *
+ */ public class AttackAnimation extends ActionAnimation { - /** Entities that collided **/ - public static final SharedAnimationVariableKey> ATTACK_TRIED_ENTITIES = AnimationVariables.shared((animator) -> Lists.newArrayList(), false); - /** Entities that actually hurt **/ - public static final SharedAnimationVariableKey> ACTUALLY_HIT_ENTITIES = AnimationVariables.shared((animator) -> Lists.newArrayList(), false); - - public final Phase[] phases; - - public AttackAnimation(float transitionTime, float antic, float preDelay, float contact, float recovery, @Nullable Collider collider, Joint colliderJoint, AnimationAccessor accessor, AssetAccessor armature) { - this(transitionTime, accessor, armature, new Phase(0.0F, antic, preDelay, contact, recovery, Float.MAX_VALUE, colliderJoint, collider)); - } - - public AttackAnimation(float transitionTime, float antic, float preDelay, float contact, float recovery, InteractionHand hand, @Nullable Collider collider, Joint colliderJoint, AnimationAccessor accessor, AssetAccessor armature) { - this(transitionTime, accessor, armature, new Phase(0.0F, antic, preDelay, contact, recovery, Float.MAX_VALUE, hand, colliderJoint, collider)); - } - - public AttackAnimation(float transitionTime, AnimationAccessor accessor, AssetAccessor armature, Phase... phases) { - super(transitionTime, accessor, armature); - - this.addProperty(ActionAnimationProperty.COORD_SET_BEGIN, MoveCoordFunctions.TRACE_TARGET_DISTANCE); - this.addProperty(ActionAnimationProperty.COORD_SET_TICK, MoveCoordFunctions.TRACE_TARGET_DISTANCE); - this.addProperty(ActionAnimationProperty.COORD_GET, MoveCoordFunctions.MODEL_COORD); - this.addProperty(ActionAnimationProperty.DEST_LOCATION_PROVIDER, MoveCoordFunctions.ATTACK_TARGET_LOCATION); - this.addProperty(ActionAnimationProperty.ENTITY_YROT_PROVIDER, MoveCoordFunctions.MOB_ATTACK_TARGET_LOOK); - this.addProperty(ActionAnimationProperty.STOP_MOVEMENT, true); - - this.phases = phases; - this.stateSpectrumBlueprint.clear(); - - for (Phase phase : phases) { - if (!phase.noStateBind) { - this.bindPhaseState(phase); - } - } - } - + /** - * For resourcepack animation + * Liste des phases d'attaque. Toujours vide en TiedUp — on ne joue + * jamais d'animation attaque. Mais le field doit exister pour que + * JsonAssetLoader.java ligne 591 puisse itérer dessus sans NPE. */ - public AttackAnimation(float convertTime, float antic, float preDelay, float contact, float recovery, InteractionHand hand, @Nullable Collider collider, Joint colliderJoint, String path, AssetAccessor armature) { - this(convertTime, path, armature, new Phase(0.0F, antic, preDelay, contact, recovery, Float.MAX_VALUE, hand, colliderJoint, collider)); + public final List phases = Collections.emptyList(); + + public AttackAnimation(float transitionTime, boolean isRepeat, String registryName, AssetAccessor armature) { + super(transitionTime, isRepeat, registryName, armature); } - + + public AttackAnimation(boolean isRepeat, String registryName, AssetAccessor armature) { + super(isRepeat, registryName, armature); + } + /** - * For resourcepack animation + * Phase d'attaque. Stub pour satisfaire {@code phase.getColliders()} + * en JsonAssetLoader. */ - public AttackAnimation(float convertTime, String path, AssetAccessor armature, Phase... phases) { - super(convertTime, 0.0F, path, armature); - - this.addProperty(ActionAnimationProperty.COORD_SET_BEGIN, MoveCoordFunctions.TRACE_TARGET_DISTANCE); - this.addProperty(ActionAnimationProperty.COORD_SET_TICK, MoveCoordFunctions.TRACE_TARGET_DISTANCE); - this.addProperty(ActionAnimationProperty.COORD_GET, MoveCoordFunctions.MODEL_COORD); - this.addProperty(ActionAnimationProperty.DEST_LOCATION_PROVIDER, MoveCoordFunctions.ATTACK_TARGET_LOCATION); - this.addProperty(ActionAnimationProperty.ENTITY_YROT_PROVIDER, MoveCoordFunctions.MOB_ATTACK_TARGET_LOOK); - this.addProperty(ActionAnimationProperty.STOP_MOVEMENT, true); - - this.phases = phases; - this.stateSpectrumBlueprint.clear(); - - for (Phase phase : phases) { - if (!phase.noStateBind) { - this.bindPhaseState(phase); - } - } - } - - protected void bindPhaseState(Phase phase) { - float preDelay = phase.preDelay; - - this.stateSpectrumBlueprint - .newTimePair(phase.start, preDelay) - .addState(EntityState.PHASE_LEVEL, 1) - .newTimePair(phase.start, phase.contact) - .addState(EntityState.CAN_SKILL_EXECUTION, false) - .newTimePair(phase.start, phase.recovery) - .addState(EntityState.MOVEMENT_LOCKED, true) - .addState(EntityState.UPDATE_LIVING_MOTION, false) - .addState(EntityState.CAN_BASIC_ATTACK, false) - .newTimePair(phase.start, phase.end) - .addState(EntityState.INACTION, true) - .newTimePair(phase.antic, phase.end) - .addState(EntityState.TURNING_LOCKED, true) - .newTimePair(preDelay, phase.contact) - .addState(EntityState.ATTACKING, true) - .addState(EntityState.PHASE_LEVEL, 2) - .newTimePair(phase.contact, phase.end) - .addState(EntityState.PHASE_LEVEL, 3) - ; - } - - @Override - public void begin(LivingEntityPatch entitypatch) { - super.begin(entitypatch); - - entitypatch.setLastAttackSuccess(false); - } - - @Override - public void linkTick(LivingEntityPatch entitypatch, AssetAccessor linkAnimation) { - super.linkTick(entitypatch, linkAnimation); - - if (!entitypatch.isLogicalClient()) { - this.attackTick(entitypatch, linkAnimation); - } - } - - @Override - public void tick(LivingEntityPatch entitypatch) { - super.tick(entitypatch); - - if (!entitypatch.isLogicalClient()) { - this.attackTick(entitypatch, this.getAccessor()); - } - } - - @Override - public void end(LivingEntityPatch entitypatch, AssetAccessor nextAnimation, boolean isEnd) { - super.end(entitypatch, nextAnimation, isEnd); - - if (entitypatch instanceof ServerPlayerPatch playerpatch) { - if (isEnd) { - playerpatch.getEventListener().triggerEvents(EventType.ATTACK_ANIMATION_END_EVENT, new AttackEndEvent(playerpatch, this.getAccessor())); - } - - AnimationPlayer player = entitypatch.getAnimator().getPlayerFor(this.getAccessor()); - float elapsedTime = player.getElapsedTime(); - EntityState state = this.getState(entitypatch, elapsedTime); - - if (!isEnd && state.attacking()) { - playerpatch.getEventListener().triggerEvents(EventType.ATTACK_PHASE_END_EVENT, new AttackPhaseEndEvent(playerpatch, this.getAccessor(), this.getPhaseByTime(elapsedTime), this.getPhaseOrderByTime(elapsedTime))); - } - } - - if (entitypatch instanceof HumanoidMobPatch mobpatch && entitypatch.isLogicalClient()) { - Mob entity = mobpatch.getOriginal(); - - if (entity.getTarget() != null && !entity.getTarget().isAlive()) { - entity.setTarget(null); - } - } - } - - protected void attackTick(LivingEntityPatch entitypatch, AssetAccessor animation) { - AnimationPlayer player = entitypatch.getAnimator().getPlayerFor(this.getAccessor()); - float prevElapsedTime = player.getPrevElapsedTime(); - float elapsedTime = player.getElapsedTime(); - EntityState prevState = animation.get().getState(entitypatch, prevElapsedTime); - EntityState state = animation.get().getState(entitypatch, elapsedTime); - Phase phase = this.getPhaseByTime(animation.get().isLinkAnimation() ? 0.0F : elapsedTime); - - if (prevState.attacking() || state.attacking() || (prevState.getLevel() <= 2 && state.getLevel() > 2)) { - if (!prevState.attacking() || (phase != this.getPhaseByTime(prevElapsedTime) && (state.attacking() || (prevState.getLevel() <= 2 && state.getLevel() > 2)))) { - entitypatch.onStrike(this, phase.hand); - entitypatch.playSound(this.getSwingSound(entitypatch, phase), 0.0F, 0.0F); - entitypatch.removeHurtEntities(); - } - - this.hurtCollidingEntities(entitypatch, prevElapsedTime, elapsedTime, prevState, state, phase); - - if ((!state.attacking() || elapsedTime >= this.getTotalTime()) && entitypatch instanceof ServerPlayerPatch playerpatch) { - playerpatch.getEventListener().triggerEvents(EventType.ATTACK_PHASE_END_EVENT, new AttackPhaseEndEvent(playerpatch, this.getAccessor(), phase, this.getPhaseOrderByTime(elapsedTime))); - } - } - } - - protected void hurtCollidingEntities(LivingEntityPatch entitypatch, float prevElapsedTime, float elapsedTime, EntityState prevState, EntityState state, Phase phase) { - LivingEntity entity = entitypatch.getOriginal(); - float prevPoseTime = prevState.attacking() ? prevElapsedTime : phase.preDelay; - float poseTime = state.attacking() ? elapsedTime : phase.contact; - List list = this.getPhaseByTime(elapsedTime).getCollidingEntities(entitypatch, this, prevPoseTime, poseTime, this.getPlaySpeed(entitypatch, this)); - - if (!list.isEmpty()) { - HitEntityList hitEntities = new HitEntityList(entitypatch, list, phase.getProperty(AttackPhaseProperty.HIT_PRIORITY).orElse(HitEntityList.Priority.DISTANCE)); - int maxStrikes = this.getMaxStrikes(entitypatch, phase); - - while (entitypatch.getCurrentlyActuallyHitEntities().size() < maxStrikes && hitEntities.next()) { - Entity target = hitEntities.getEntity(); - LivingEntity trueEntity = this.getTrueEntity(target); - - if (trueEntity != null && trueEntity.isAlive() && !entitypatch.getCurrentlyAttackTriedEntities().contains(trueEntity) && !entitypatch.isTargetInvulnerable(target)) { - if (target instanceof LivingEntity || target instanceof PartEntity) { - AABB aabb = target.getBoundingBox(); - - if (MathUtils.canBeSeen(target, entity, target.position().distanceTo(entity.getEyePosition()) + aabb.getCenter().distanceTo(new Vec3(aabb.maxX, aabb.maxY, aabb.maxZ)))) { - EpicFightDamageSource damagesource = this.getEpicFightDamageSource(entitypatch, target, phase); - int prevInvulTime = target.invulnerableTime; - target.invulnerableTime = 0; - - AttackResult attackResult = entitypatch.attack(damagesource, target, phase.hand); - target.invulnerableTime = prevInvulTime; - - if (attackResult.resultType.dealtDamage()) { - SoundEvent hitSound = this.getHitSound(entitypatch, phase); - - if (hitSound != null) { - target.level().playSound(null, target.getX(), target.getY(), target.getZ(), this.getHitSound(entitypatch, phase), target.getSoundSource(), 1.0F, 1.0F); - } - - this.spawnHitParticle((ServerLevel)target.level(), entitypatch, target, phase); - } - - entitypatch.getCurrentlyAttackTriedEntities().add(trueEntity); - - if (attackResult.resultType.shouldCount()) { - entitypatch.getCurrentlyActuallyHitEntities().add(trueEntity); - } - } - } - } - } - } - } - - public LivingEntity getTrueEntity(Entity entity) { - if (entity instanceof LivingEntity livingEntity) { - return livingEntity; - } else if (entity instanceof PartEntity partEntity) { - Entity parentEntity = partEntity.getParent(); - - if (parentEntity instanceof LivingEntity livingEntity) { - return livingEntity; - } - } - - return null; - } - - protected int getMaxStrikes(LivingEntityPatch entitypatch, Phase phase) { - return phase.getProperty(AttackPhaseProperty.MAX_STRIKES_MODIFIER) - .map(valueModifier -> (int)ValueModifier.calculator().attach(valueModifier).getResult(entitypatch.getMaxStrikes(phase.hand))) - .orElse(entitypatch.getMaxStrikes(phase.hand)); - } - - protected SoundEvent getSwingSound(LivingEntityPatch entitypatch, Phase phase) { - return phase.getProperty(AttackPhaseProperty.SWING_SOUND).orElse(entitypatch.getSwingSound(phase.hand)); - } - - protected SoundEvent getHitSound(LivingEntityPatch entitypatch, Phase phase) { - return phase.getProperty(AttackPhaseProperty.HIT_SOUND).orElse(entitypatch.getWeaponHitSound(phase.hand)); - } - - public EpicFightDamageSource getEpicFightDamageSource(LivingEntityPatch entitypatch, Entity target, Phase phase) { - return this.getEpicFightDamageSource(entitypatch.getDamageSource(this.getAccessor(), phase.hand), entitypatch, target, phase); - } - - public EpicFightDamageSource getEpicFightDamageSource(DamageSource originalSource, LivingEntityPatch entitypatch, Entity target, Phase phase) { - if (phase == null) { - phase = this.getPhaseByTime(entitypatch.getAnimator().getPlayerFor(this.getAccessor()).getElapsedTime()); - } - - EpicFightDamageSource epicfightSource; - - if (originalSource instanceof EpicFightDamageSource epicfightDamageSource) { - epicfightSource = epicfightDamageSource; - } else { - epicfightSource = EpicFightDamageSources.fromVanillaDamageSource(originalSource).setAnimation(this.getAccessor()); - } - - phase.getProperty(AttackPhaseProperty.DAMAGE_MODIFIER).ifPresent(opt -> { - epicfightSource.attachDamageModifier(opt); - }); - - phase.getProperty(AttackPhaseProperty.ARMOR_NEGATION_MODIFIER).ifPresent(opt -> { - epicfightSource.attachArmorNegationModifier(opt); - }); - - phase.getProperty(AttackPhaseProperty.IMPACT_MODIFIER).ifPresent(opt -> { - epicfightSource.attachImpactModifier(opt); - }); - - phase.getProperty(AttackPhaseProperty.STUN_TYPE).ifPresent(opt -> { - epicfightSource.setStunType(opt); - }); - - phase.getProperty(AttackPhaseProperty.SOURCE_TAG).ifPresent(opt -> { - opt.forEach(epicfightSource::addRuntimeTag); - }); - - phase.getProperty(AttackPhaseProperty.EXTRA_DAMAGE).ifPresent(opt -> { - opt.forEach(epicfightSource::addExtraDamage); - }); - - phase.getProperty(AttackPhaseProperty.SOURCE_LOCATION_PROVIDER).ifPresentOrElse(opt -> { - epicfightSource.setInitialPosition(opt.apply(entitypatch)); - }, () -> { - epicfightSource.setInitialPosition(entitypatch.getOriginal().position()); - }); - - return epicfightSource; - } - - protected void spawnHitParticle(ServerLevel world, LivingEntityPatch attacker, Entity hit, Phase phase) { - Optional> particleOptional = phase.getProperty(AttackPhaseProperty.PARTICLE); - HitParticleType particle = particleOptional.isPresent() ? particleOptional.get().get() : attacker.getWeaponHitParticle(phase.hand); - particle.spawnParticleWithArgument(world, null, null, hit, attacker.getOriginal()); - } - - @Override - public float getPlaySpeed(LivingEntityPatch entitypatch, DynamicAnimation animation) { - if (entitypatch instanceof PlayerPatch playerpatch) { - Phase phase = this.getPhaseByTime(playerpatch.getAnimator().getPlayerFor(this.getAccessor()).getElapsedTime()); - float speedFactor = this.getProperty(AttackAnimationProperty.ATTACK_SPEED_FACTOR).orElse(1.0F); - Optional property = this.getProperty(AttackAnimationProperty.BASIS_ATTACK_SPEED); - float correctedSpeed = property.map((value) -> playerpatch.getAttackSpeed(phase.hand) / value).orElse(this.getTotalTime() * playerpatch.getAttackSpeed(phase.hand)); - correctedSpeed = Math.round(correctedSpeed * 1000.0F) / 1000.0F; - - return 1.0F + (correctedSpeed - 1.0F) * speedFactor; - } - - return 1.0F; - } - - @SuppressWarnings("unchecked") - public A addProperty(AttackPhaseProperty propertyType, V value) { - return (A)this.addProperty(propertyType, value, 0); - } - - @SuppressWarnings("unchecked") - public A addProperty(AttackPhaseProperty propertyType, V value, int index) { - this.phases[index].addProperty(propertyType, value); - return (A)this; - } - - public A removeProperty(AttackPhaseProperty propertyType) { - return this.removeProperty(propertyType, 0); - } - - @SuppressWarnings("unchecked") - public A removeProperty(AttackPhaseProperty propertyType, int index) { - this.phases[index].removeProperty(propertyType); - return (A)this; - } - - public Phase getPhaseByTime(float elapsedTime) { - Phase currentPhase = null; - - for (Phase phase : this.phases) { - currentPhase = phase; - - if (phase.end > elapsedTime) { - break; - } - } - - return currentPhase; - } - - public int getPhaseOrderByTime(float elapsedTime) { - int i = 0; - - for (Phase phase : this.phases) { - if (phase.end > elapsedTime) { - break; - } - - i++; - } - - return i; - } - - @Override - public Object getModifiedLinkState(StateFactor factor, Object val, LivingEntityPatch entitypatch, float elapsedTime) { - if (factor == EntityState.ATTACKING && elapsedTime < this.getPlaySpeed(entitypatch, this) * TiedUpRigConstants.A_TICK) { - return false; - } - - return val; - } - - @Override - @OnlyIn(Dist.CLIENT) - public void renderDebugging(PoseStack poseStack, MultiBufferSource buffer, LivingEntityPatch entitypatch, float playbackTime, float partialTicks) { - AnimationPlayer animPlayer = entitypatch.getAnimator().getPlayerFor(this.getAccessor()); - float prevElapsedTime = animPlayer.getPrevElapsedTime(); - float elapsedTime = animPlayer.getElapsedTime(); - Phase phase = this.getPhaseByTime(playbackTime); - - for (Pair colliderInfo : phase.colliders) { - Collider collider = colliderInfo.getSecond(); - - if (collider == null) { - collider = entitypatch.getColliderMatching(phase.hand); - } - - collider.draw(poseStack, buffer, entitypatch, this, colliderInfo.getFirst(), prevElapsedTime, elapsedTime, partialTicks, this.getPlaySpeed(entitypatch, this)); - } - } - - public static class JointColliderPair extends Pair { - public JointColliderPair(Joint first, Collider second) { - super(first, second); - } - - public static JointColliderPair of(Joint joint, Collider collider) { - return new JointColliderPair(joint, collider); - } - } - public static class Phase { - private final Map, Object> properties = Maps.newHashMap(); - public final float start; - public final float antic; - public final float preDelay; - public final float contact; - public final float recovery; - public final float end; - public final InteractionHand hand; - public JointColliderPair[] colliders; - - //public final Joint first; - //public final Collider second; - - public final boolean noStateBind; - - public Phase(float start, float antic, float contact, float recovery, float end, Joint joint, Collider collider) { - this(start, antic, contact, recovery, end, InteractionHand.MAIN_HAND, joint, collider); - } - - public Phase(float start, float antic, float contact, float recovery, float end, InteractionHand hand, Joint joint, Collider collider) { - this(start, antic, antic, contact, recovery, end, hand, joint, collider); - } - - public Phase(float start, float antic, float preDelay, float contact, float recovery, float end, Joint joint, Collider collider) { - this(start, antic, preDelay, contact, recovery, end, InteractionHand.MAIN_HAND, joint, collider); - } - - public Phase(float start, float antic, float preDelay, float contact, float recovery, float end, InteractionHand hand, Joint joint, Collider collider) { - this(start, antic, preDelay, contact, recovery, end, false, hand, joint, collider); - } - - public Phase(InteractionHand hand, Joint joint, Collider collider) { - this(0, 0, 0, 0, 0, 0, true, hand, joint, collider); - } - - public Phase(float start, float antic, float preDelay, float contact, float recovery, float end, boolean noStateBind, InteractionHand hand, Joint joint, Collider collider) { - this(start, antic, preDelay, contact, recovery, end, noStateBind, hand, JointColliderPair.of(joint, collider)); - } - - public Phase(float start, float antic, float preDelay, float contact, float recovery, float end, InteractionHand hand, JointColliderPair... colliders) { - this(start, antic, preDelay, contact, recovery, end, false, hand, colliders); - } - - public Phase(float start, float antic, float preDelay, float contact, float recovery, float end, boolean noStateBind, InteractionHand hand, JointColliderPair... colliders) { - if (start > end) { - throw new IllegalArgumentException("Phase create exception: Start time is bigger than end time"); - } - - this.start = start; - this.antic = antic; - this.preDelay = preDelay; - this.contact = contact; - this.recovery = recovery; - this.end = end; - this.colliders = colliders; - this.hand = hand; - this.noStateBind = noStateBind; - } - - public Phase addProperty(AttackPhaseProperty propertyType, V value) { - this.properties.put(propertyType, value); - return this; - } - - public Phase removeProperty(AttackPhaseProperty propertyType) { - this.properties.remove(propertyType); - return this; - } - - public void addProperties(Set, Object>> set) { - for(Map.Entry, Object> entry : set) { - this.properties.put(entry.getKey(), entry.getValue()); - } - } - - @SuppressWarnings("unchecked") - public Optional getProperty(AttackPhaseProperty propertyType) { - return (Optional) Optional.ofNullable(this.properties.get(propertyType)); - } - - public List getCollidingEntities(LivingEntityPatch entitypatch, AttackAnimation animation, float prevElapsedTime, float elapsedTime, float attackSpeed) { - Set entities = Sets.newHashSet(); - - for (Pair colliderInfo : this.colliders) { - Collider collider = colliderInfo.getSecond(); - - if (collider == null) { - collider = entitypatch.getColliderMatching(this.hand); - } - - entities.addAll(collider.updateAndSelectCollideEntity(entitypatch, animation, prevElapsedTime, elapsedTime, colliderInfo.getFirst(), attackSpeed)); - } - - return new ArrayList<>(entities); - } - - public JointColliderPair[] getColliders() { - return this.colliders; - } - - public InteractionHand getHand() { - return this.hand; + public Object[] getColliders() { + return new Object[0]; } } } diff --git a/src/main/java/com/tiedup/remake/rig/anim/types/MainFrameAnimation.java b/src/main/java/com/tiedup/remake/rig/anim/types/MainFrameAnimation.java index 56cadcf..f407f38 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/types/MainFrameAnimation.java +++ b/src/main/java/com/tiedup/remake/rig/anim/types/MainFrameAnimation.java @@ -6,88 +6,23 @@ package com.tiedup.remake.rig.anim.types; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import com.tiedup.remake.rig.anim.AnimationManager.AnimationAccessor; -import com.tiedup.remake.rig.anim.property.AnimationProperty.StaticAnimationProperty; -import com.tiedup.remake.rig.anim.types.EntityState.StateFactor; -import com.tiedup.remake.rig.asset.AssetAccessor; -import com.tiedup.remake.rig.anim.client.Layer; -import com.tiedup.remake.rig.anim.client.property.ClientAnimationProperties; import com.tiedup.remake.rig.armature.Armature; -import com.tiedup.remake.rig.util.datastruct.TypeFlexibleHashMap; -import com.tiedup.remake.rig.patch.LivingEntityPatch; -import com.tiedup.remake.rig.patch.PlayerPatch; -import com.tiedup.remake.rig.patch.ServerPlayerPatch; -import yesman.epicfight.world.entity.eventlistener.ActionEvent; -import yesman.epicfight.world.entity.eventlistener.PlayerEventListener.EventType; +import com.tiedup.remake.rig.asset.AssetAccessor; +/** + * RIG stub. Upstream EF : MainFrameAnimation ajoute du scheduling combat + * via {@code ActionEvent}/{@code PlayerEventListener} (combat tick hooks). + * Strippé pour TiedUp — garde juste le type pour satisfaire les + * instanceof checks de {@link com.tiedup.remake.rig.asset.JsonAssetLoader} + * et la hiérarchie {@link ActionAnimation} / {@link AttackAnimation}. + */ public class MainFrameAnimation extends StaticAnimation { - public MainFrameAnimation(float convertTime, AnimationAccessor accessor, AssetAccessor armature) { - super(convertTime, false, accessor, armature); + + public MainFrameAnimation(float transitionTime, boolean isRepeat, String registryName, AssetAccessor armature) { + super(transitionTime, isRepeat, registryName, armature); } - - public MainFrameAnimation(float convertTime, String path, AssetAccessor armature) { - super(convertTime, false, path, armature); - } - - @Override - public void begin(LivingEntityPatch entitypatch) { - if (entitypatch.getAnimator().getPlayerFor(null).getAnimation().get() == this) { - TypeFlexibleHashMap> stateMap = this.stateSpectrum.getStateMap(entitypatch, 0.0F); - TypeFlexibleHashMap> modifiedStateMap = new TypeFlexibleHashMap<> (false); - stateMap.forEach((k, v) -> modifiedStateMap.put(k, this.getModifiedLinkState(k, v, entitypatch, 0.0F))); - entitypatch.updateEntityState(new EntityState(modifiedStateMap)); - } - - if (entitypatch.isLogicalClient()) { - entitypatch.updateMotion(false); - - this.getProperty(StaticAnimationProperty.RESET_LIVING_MOTION).ifPresentOrElse(livingMotion -> { - entitypatch.getClientAnimator().forceResetBeforeAction(livingMotion, livingMotion); - }, () -> { - entitypatch.getClientAnimator().resetMotion(true); - entitypatch.getClientAnimator().resetCompositeMotion(); - }); - - entitypatch.getClientAnimator().getPlayerFor(this.getAccessor()).setReversed(false); - } - - super.begin(entitypatch); - - if (entitypatch instanceof PlayerPatch playerpatch) { - if (playerpatch.isLogicalClient()) { - if (playerpatch.getOriginal().isLocalPlayer()) { - playerpatch.getEventListener().triggerEvents(EventType.ACTION_EVENT_CLIENT, new ActionEvent<>(playerpatch, this.getAccessor())); - } - } else { - ActionEvent actionEvent = new ActionEvent<>(playerpatch, this.getAccessor()); - playerpatch.getEventListener().triggerEvents(EventType.ACTION_EVENT_SERVER, actionEvent); - - if (actionEvent.shouldResetActionTick()) { - playerpatch.resetActionTick(); - } - } - } - } - - @Override - public void tick(LivingEntityPatch entitypatch) { - super.tick(entitypatch); - - if (entitypatch.getEntityState().movementLocked()) { - entitypatch.getOriginal().walkAnimation.setSpeed(0); - } - } - - @Override - public boolean isMainFrameAnimation() { - return true; - } - - @Override - @OnlyIn(Dist.CLIENT) - public Layer.Priority getPriority() { - return this.getProperty(ClientAnimationProperties.PRIORITY).orElse(Layer.Priority.HIGHEST); + + public MainFrameAnimation(boolean isRepeat, String registryName, AssetAccessor armature) { + super(isRepeat, registryName, armature); } } diff --git a/src/main/java/com/tiedup/remake/rig/anim/types/StateSpectrum.java b/src/main/java/com/tiedup/remake/rig/anim/types/StateSpectrum.java new file mode 100644 index 0000000..95bcd90 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/anim/types/StateSpectrum.java @@ -0,0 +1,288 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.anim.types; + +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import com.tiedup.remake.rig.anim.types.EntityState.StateFactor; +import com.tiedup.remake.rig.util.datastruct.TypeFlexibleHashMap; +import com.tiedup.remake.rig.patch.LivingEntityPatch; + +public class StateSpectrum { + private final Set timePairs = Sets.newHashSet(); + + void readFrom(StateSpectrum.Blueprint blueprint) { + this.timePairs.clear(); + this.timePairs.addAll(blueprint.timePairs); + } + + @SuppressWarnings("unchecked") + public T getSingleState(StateFactor stateFactor, LivingEntityPatch entitypatch, float time) { + for (StatesInTime state : this.timePairs) { + if (state.isIn(entitypatch, time)) { + for (Map.Entry, ?> timeEntry : state.getStates(entitypatch)) { + if (timeEntry.getKey() == stateFactor) { + return (T) timeEntry.getValue(); + } + } + } + } + + return stateFactor.defaultValue(); + } + + public TypeFlexibleHashMap> getStateMap(LivingEntityPatch entitypatch, float time) { + TypeFlexibleHashMap> stateMap = new TypeFlexibleHashMap<>(true); + + for (StatesInTime state : this.timePairs) { + if (state.isIn(entitypatch, time)) { + for (Map.Entry, ?> timeEntry : state.getStates(entitypatch)) { + stateMap.put(timeEntry.getKey(), timeEntry.getValue()); + } + } + } + + return stateMap; + } + + abstract static class StatesInTime { + public abstract Set, Object>> getStates(LivingEntityPatch entitypatch); + + public abstract void removeState(StateFactor state); + + public abstract boolean hasState(StateFactor state); + + public abstract boolean isIn(LivingEntityPatch entitypatch, float time); + } + + static class SimpleStatesInTime extends StatesInTime { + float start; + float end; + Map, Object> states = Maps.newHashMap(); + + public SimpleStatesInTime(float start, float end) { + this.start = start; + this.end = end; + } + + @Override + public boolean isIn(LivingEntityPatch entitypatch, float time) { + return this.start <= time && this.end > time; + } + + public StatesInTime addState(StateFactor factor, T val) { + this.states.put(factor, val); + return this; + } + + @Override + public Set, Object>> getStates(LivingEntityPatch entitypatch) { + return this.states.entrySet(); + } + + @Override + public boolean hasState(StateFactor state) { + return this.states.containsKey(state); + } + + @Override + public void removeState(StateFactor state) { + this.states.remove(state); + } + + @Override + public String toString() { + return String.format("Time: %.2f ~ %.2f, States: %s", this.start, this.end, this.states); + } + } + + static class ConditionalStatesInTime extends StatesInTime { + float start; + float end; + Int2ObjectMap, Object>> conditionalStates = new Int2ObjectOpenHashMap<>(); + Function, Integer> condition; + + public ConditionalStatesInTime(Function, Integer> condition, float start, float end) { + this.start = start; + this.end = end; + this.condition = condition; + } + + public StatesInTime addConditionalState(int metadata, StateFactor factor, T val) { + Map, Object> states = this.conditionalStates.computeIfAbsent(metadata, (key) -> Maps.newHashMap()); + states.put(factor, val); + return this; + } + + @SuppressWarnings("deprecation") + @Override + public Set, Object>> getStates(LivingEntityPatch entitypatch) { + return this.conditionalStates.get(this.condition.apply(entitypatch)).entrySet(); + } + + @Override + public boolean isIn(LivingEntityPatch entitypatch, float time) { + return this.start <= time && this.end > time; + } + + @Override + public boolean hasState(StateFactor state) { + boolean hasState = false; + for (Map, Object> states : this.conditionalStates.values()) { + hasState |= states.containsKey(state); + } + return hasState; + } + + @Override + public void removeState(StateFactor state) { + for (Map, Object> states : this.conditionalStates.values()) { + states.remove(state); + } + } + + @SuppressWarnings("deprecation") + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format("Time: %.2f ~ %.2f, ", this.start, this.end)); + int entryCnt = 0; + for (Map.Entry, Object>> entry : this.conditionalStates.entrySet()) { + sb.append(String.format("States %d: %s", entry.getKey(), entry.getValue())); + entryCnt++; + if (entryCnt < this.conditionalStates.size()) { + sb.append(", "); + } + } + return sb.toString(); + } + } + + static class VariableStatesInTime extends StatesInTime { + Function, Float> variableStart; + Function, Float> variableEnd; + Map, Object> states = Maps.newHashMap(); + + public VariableStatesInTime(Function, Float> variableStart, Function, Float> variableEnd) { + this.variableStart = variableStart; + this.variableEnd = variableEnd; + } + + @Override + public boolean isIn(LivingEntityPatch entitypatch, float time) { + return this.variableStart.apply(entitypatch) <= time && this.variableEnd.apply(entitypatch) > time; + } + + public StatesInTime addState(StateFactor factor, T val) { + this.states.put(factor, val); + return this; + } + + @Override + public Set, Object>> getStates(LivingEntityPatch entitypatch) { + return this.states.entrySet(); + } + + @Override + public boolean hasState(StateFactor state) { + return this.states.containsKey(state); + } + + @Override + public void removeState(StateFactor state) { + this.states.remove(state); + } + + @Override + public String toString() { + return String.format("States: %s", this.states); + } + } + + public static class Blueprint { + StatesInTime currentState; + Set timePairs = Sets.newHashSet(); + + public Blueprint newTimePair(float start, float end) { + this.currentState = new SimpleStatesInTime(start, end); + this.timePairs.add(this.currentState); + return this; + } + + public Blueprint newConditionalTimePair(Function, Integer> condition, float start, float end) { + this.currentState = new ConditionalStatesInTime(condition, start, end); + this.timePairs.add(this.currentState); + return this; + } + + public Blueprint newVariableTimePair(Function, Float> variableStart, Function, Float> variableEnd) { + this.currentState = new VariableStatesInTime(variableStart, variableEnd); + this.timePairs.add(this.currentState); + return this; + } + + public Blueprint addState(StateFactor factor, T val) { + if (this.currentState instanceof SimpleStatesInTime simpleState) { + simpleState.addState(factor, val); + } + if (this.currentState instanceof VariableStatesInTime variableState) { + variableState.addState(factor, val); + } + return this; + } + + public Blueprint addConditionalState(int metadata, StateFactor factor, T val) { + if (this.currentState instanceof ConditionalStatesInTime conditionalState) { + conditionalState.addConditionalState(metadata, factor, val); + } + return this; + } + + public Blueprint removeState(StateFactor factor) { + for (StatesInTime timePair : this.timePairs) { + timePair.removeState(factor); + } + return this; + } + + public Blueprint addStateRemoveOld(StateFactor factor, T val) { + this.removeState(factor); + return this.addState(factor, val); + } + + public Blueprint addStateIfNotExist(StateFactor factor, T val) { + for (StatesInTime timePair : this.timePairs) { + if (timePair.hasState(factor)) { + return this; + } + } + return this.addState(factor, val); + } + + public Blueprint clear() { + this.currentState = null; + this.timePairs.clear(); + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (StatesInTime state : this.timePairs) { + sb.append(state + "\n"); + } + return sb.toString(); + } + } +} diff --git a/src/main/java/com/tiedup/remake/rig/anim/types/StaticAnimation.java b/src/main/java/com/tiedup/remake/rig/anim/types/StaticAnimation.java index a81f537..992cef8 100644 --- a/src/main/java/com/tiedup/remake/rig/anim/types/StaticAnimation.java +++ b/src/main/java/com/tiedup/remake/rig/anim/types/StaticAnimation.java @@ -52,25 +52,19 @@ import com.tiedup.remake.rig.anim.client.property.JointMaskEntry; import com.tiedup.remake.rig.anim.client.property.TrailInfo; import com.tiedup.remake.rig.exception.AssetLoadingException; import com.tiedup.remake.rig.armature.Armature; -import yesman.epicfight.api.physics.ik.InverseKinematicsProvider; -import yesman.epicfight.api.physics.ik.InverseKinematicsSimulatable; -import yesman.epicfight.api.physics.ik.InverseKinematicsSimulator; -import yesman.epicfight.api.physics.ik.InverseKinematicsSimulator.BakedInverseKinematicsDefinition; -import yesman.epicfight.api.physics.ik.InverseKinematicsSimulator.InverseKinematicsObject; +import com.tiedup.remake.rig.physics.ik.InverseKinematicsProvider; +import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulatable; +import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator; +import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator.BakedInverseKinematicsDefinition; +import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator.InverseKinematicsObject; import com.tiedup.remake.rig.util.datastruct.TypeFlexibleHashMap; import com.tiedup.remake.rig.math.OpenMatrix4f; import com.tiedup.remake.rig.math.Vec3f; -import yesman.epicfight.client.ClientEngine; import com.tiedup.remake.rig.render.TiedUpRenderTypes; -import yesman.epicfight.client.renderer.RenderingTool; -import com.tiedup.remake.rig.render.item.RenderItemBase; import com.tiedup.remake.rig.TiedUpRigRegistry; import com.tiedup.remake.rig.TiedUpRigConstants; import com.tiedup.remake.rig.patch.LivingEntityPatch; import com.tiedup.remake.rig.patch.PlayerPatch; -import yesman.epicfight.world.entity.eventlistener.AnimationBeginEvent; -import yesman.epicfight.world.entity.eventlistener.AnimationEndEvent; -import yesman.epicfight.world.entity.eventlistener.PlayerEventListener.EventType; public class StaticAnimation extends DynamicAnimation implements InverseKinematicsProvider { public static final IndependentAnimationVariableKey HAD_NO_PHYSICS = AnimationVariables.independent((animator) -> false, true); @@ -271,13 +265,9 @@ public class StaticAnimation extends DynamicAnimation implements InverseKinemati double jointId = Double.longBitsToDouble((long)this.armature.get().searchJointByName(trailInfo.joint()).getId()); double index = Double.longBitsToDouble((long)idx++); - if (trailInfo.hand() != null) { - RenderItemBase renderitembase = ClientEngine.getInstance().renderEngine.getItemRenderer(entitypatch.getAdvancedHoldingItemStack(trailInfo.hand())); - - if (renderitembase != null && renderitembase.trailInfo() != null) { - trailInfo = renderitembase.trailInfo().overwrite(trailInfo); - } - } + // RIG : RenderItemBase (combat weapon item render) strippé — + // TiedUp n'a pas d'items "actifs" porteurs de trails comme + // les weapons EF. Le trailInfo reste tel quel de la définition. if (!trailInfo.playable()) { continue; @@ -294,16 +284,13 @@ public class StaticAnimation extends DynamicAnimation implements InverseKinemati } }); - if (entitypatch instanceof PlayerPatch playerpatch) { - playerpatch.getEventListener().triggerEvents(EventType.ANIMATION_BEGIN_EVENT, new AnimationBeginEvent(playerpatch, this)); - } + // RIG : PlayerEventListener (combat animation events) strippé. + // Les ON_BEGIN_EVENTS SimpleEvent continuent de fonctionner ci-dessus. } - + @Override public void end(LivingEntityPatch entitypatch, AssetAccessor nextAnimation, boolean isEnd) { - if (entitypatch instanceof PlayerPatch playerpatch) { - playerpatch.getEventListener().triggerEvents(EventType.ANIMATION_END_EVENT, new AnimationEndEvent(playerpatch, this, isEnd)); - } + // RIG : ANIMATION_END_EVENT fire strippé (PlayerEventListener combat). this.getProperty(StaticAnimationProperty.ON_END_EVENTS).ifPresent((events) -> { for (SimpleEvent event : events) { @@ -604,38 +591,9 @@ public class StaticAnimation extends DynamicAnimation implements InverseKinemati @OnlyIn(Dist.CLIENT) public void renderDebugging(PoseStack poseStack, MultiBufferSource buffer, LivingEntityPatch entitypatch, float playTime, float partialTicks) { - if (entitypatch instanceof InverseKinematicsSimulatable ikSimulatable) { - this.getProperty(StaticAnimationProperty.BAKED_IK_DEFINITION).ifPresent((ikDefinitions) -> { - OpenMatrix4f modelmat = ikSimulatable.getModelMatrix(partialTicks); - LivingEntity originalEntity = entitypatch.getOriginal(); - Vec3 entitypos = originalEntity.position(); - float x = (float)entitypos.x; - float y = (float)entitypos.y; - float z = (float)entitypos.z; - float xo = (float)originalEntity.xo; - float yo = (float)originalEntity.yo; - float zo = (float)originalEntity.zo; - OpenMatrix4f toModelPos = OpenMatrix4f.mul(OpenMatrix4f.createTranslation(xo + (x - xo) * partialTicks, yo + (y - yo) * partialTicks, zo + (z - zo) * partialTicks), modelmat, null).invert(); - - for (BakedInverseKinematicsDefinition bakedIKInfo : this.getProperty(StaticAnimationProperty.BAKED_IK_DEFINITION).orElse(null)) { - ikSimulatable.getIKSimulator().getRunningObject(bakedIKInfo.endJoint()).ifPresent((ikObjet) -> { - VertexConsumer vertexBuilder = buffer.getBuffer(TiedUpRenderTypes.debugQuads()); - Vec3f worldtargetpos = ikObjet.getDestination(); - Vec3f modeltargetpos = OpenMatrix4f.transform3v(toModelPos, worldtargetpos, null).multiply(-1.0F, 1.0F, -1.0F); - RenderingTool.drawQuad(poseStack, vertexBuilder, modeltargetpos, 0.5F, 1.0F, 0.0F, 0.0F); - Vec3f jointWorldPos = ikObjet.getTipPosition(partialTicks); - Vec3f jointModelpos = OpenMatrix4f.transform3v(toModelPos, jointWorldPos, null); - RenderingTool.drawQuad(poseStack, vertexBuilder, jointModelpos.multiply(-1.0F, 1.0F, -1.0F), 0.4F, 0.0F, 0.0F, 1.0F); - - Pose pose = new Pose(); - - for (String jointName : this.getTransfroms().keySet()) { - pose.putJointData(jointName, this.getTransfroms().get(jointName).getInterpolatedTransform(playTime)); - } - }); - } - }); - } + // RIG : debug render des targets IK (RenderingTool.drawQuad) strippé. + // Pas d'IK en TiedUp. Reactivable Phase 2+ avec un helper drawQuad + // simple si on veut debug les joints. } @Override diff --git a/src/main/java/com/tiedup/remake/rig/armature/Joint.java b/src/main/java/com/tiedup/remake/rig/armature/Joint.java index 6bacd21..b1b76dc 100644 --- a/src/main/java/com/tiedup/remake/rig/armature/Joint.java +++ b/src/main/java/com/tiedup/remake/rig/armature/Joint.java @@ -4,7 +4,7 @@ * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. */ -package com.tiedup.remake.rig.anim; +package com.tiedup.remake.rig.armature; import java.util.Iterator; import java.util.LinkedList; diff --git a/src/main/java/com/tiedup/remake/rig/armature/JointTransform.java b/src/main/java/com/tiedup/remake/rig/armature/JointTransform.java index 294b55a..9769e97 100644 --- a/src/main/java/com/tiedup/remake/rig/armature/JointTransform.java +++ b/src/main/java/com/tiedup/remake/rig/armature/JointTransform.java @@ -4,7 +4,7 @@ * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. */ -package com.tiedup.remake.rig.anim; +package com.tiedup.remake.rig.armature; import java.util.Map; diff --git a/src/main/java/com/tiedup/remake/rig/cloth/AbstractSimulator.java b/src/main/java/com/tiedup/remake/rig/cloth/AbstractSimulator.java index 5fc5534..20ccec0 100644 --- a/src/main/java/com/tiedup/remake/rig/cloth/AbstractSimulator.java +++ b/src/main/java/com/tiedup/remake/rig/cloth/AbstractSimulator.java @@ -15,10 +15,10 @@ import org.apache.commons.lang3.tuple.Pair; import com.google.common.collect.Maps; -import yesman.epicfight.api.physics.PhysicsSimulator; -import yesman.epicfight.api.physics.SimulationObject; -import yesman.epicfight.api.physics.SimulationObject.SimulationObjectBuilder; -import yesman.epicfight.api.physics.SimulationProvider; +import com.tiedup.remake.rig.physics.PhysicsSimulator; +import com.tiedup.remake.rig.physics.SimulationObject; +import com.tiedup.remake.rig.physics.SimulationObject.SimulationObjectBuilder; +import com.tiedup.remake.rig.physics.SimulationProvider; public abstract class AbstractSimulator, O, SO extends SimulationObject> implements PhysicsSimulator { protected Map simulationObjects = Maps.newHashMap(); diff --git a/src/main/java/com/tiedup/remake/rig/cloth/ClothSimulatable.java b/src/main/java/com/tiedup/remake/rig/cloth/ClothSimulatable.java index f9c18a3..3af2c98 100644 --- a/src/main/java/com/tiedup/remake/rig/cloth/ClothSimulatable.java +++ b/src/main/java/com/tiedup/remake/rig/cloth/ClothSimulatable.java @@ -11,7 +11,7 @@ import javax.annotation.Nullable; import net.minecraft.world.phys.Vec3; import com.tiedup.remake.rig.anim.Animator; import com.tiedup.remake.rig.armature.Armature; -import yesman.epicfight.api.physics.SimulatableObject; +import com.tiedup.remake.rig.physics.SimulatableObject; public interface ClothSimulatable extends SimulatableObject { @Nullable diff --git a/src/main/java/com/tiedup/remake/rig/cloth/ClothSimulator.java b/src/main/java/com/tiedup/remake/rig/cloth/ClothSimulator.java index 2e39110..d7dbda8 100644 --- a/src/main/java/com/tiedup/remake/rig/cloth/ClothSimulator.java +++ b/src/main/java/com/tiedup/remake/rig/cloth/ClothSimulator.java @@ -48,9 +48,9 @@ import com.tiedup.remake.rig.mesh.SoftBodyTranslatable; import com.tiedup.remake.rig.mesh.VertexBuilder; import com.tiedup.remake.rig.cloth.AbstractSimulator; import com.tiedup.remake.rig.cloth.ClothSimulator.ClothObjectBuilder; -import yesman.epicfight.api.collider.OBBCollider; +import com.tiedup.remake.rig.collider.OBBCollider; import com.tiedup.remake.rig.armature.Armature; -import yesman.epicfight.api.physics.SimulationObject; +import com.tiedup.remake.rig.physics.SimulationObject; import com.tiedup.remake.rig.math.MathUtils; import com.tiedup.remake.rig.math.OpenMatrix4f; import com.tiedup.remake.rig.math.Vec3f; diff --git a/src/main/java/com/tiedup/remake/rig/collider/OBBCollider.java b/src/main/java/com/tiedup/remake/rig/collider/OBBCollider.java new file mode 100644 index 0000000..fc2ebab --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/collider/OBBCollider.java @@ -0,0 +1,81 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.collider; + +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +import com.tiedup.remake.rig.math.OpenMatrix4f; +import com.tiedup.remake.rig.math.Vec3f; + +/** + * OBB géométrique forké depuis EF, strippé de la logique combat + * (isCollide(Entity), drawInternal, updateAndSelectCollideEntity). + * Ne garde que les données + transform() utilisés par ClothOBBCollider. + */ +public class OBBCollider { + protected final Vec3 modelCenter; + protected final AABB outerAABB; + protected Vec3 worldCenter; + protected final Vec3[] modelVertices; + protected final Vec3[] modelNormals; + protected Vec3[] rotatedVertices; + protected Vec3[] rotatedNormals; + protected Vec3f scale = new Vec3f(1.0F, 1.0F, 1.0F); + + public OBBCollider(double vertexX, double vertexY, double vertexZ, double centerX, double centerY, double centerZ) { + this(getInitialAABB(vertexX, vertexY, vertexZ, centerX, centerY, centerZ), vertexX, vertexY, vertexZ, centerX, centerY, centerZ); + } + + protected OBBCollider(AABB outerAABB, double vertexX, double vertexY, double vertexZ, double centerX, double centerY, double centerZ) { + this.modelCenter = new Vec3(centerX, centerY, centerZ); + this.outerAABB = outerAABB; + this.worldCenter = new Vec3(0.0D, 0.0D, 0.0D); + + this.modelVertices = new Vec3[4]; + this.modelNormals = new Vec3[3]; + this.rotatedVertices = new Vec3[4]; + this.rotatedNormals = new Vec3[3]; + this.modelVertices[0] = new Vec3(vertexX, vertexY, -vertexZ); + this.modelVertices[1] = new Vec3(vertexX, vertexY, vertexZ); + this.modelVertices[2] = new Vec3(-vertexX, vertexY, vertexZ); + this.modelVertices[3] = new Vec3(-vertexX, vertexY, -vertexZ); + this.modelNormals[0] = new Vec3(1, 0, 0); + this.modelNormals[1] = new Vec3(0, 1, 0); + this.modelNormals[2] = new Vec3(0, 0, 1); + this.rotatedVertices[0] = new Vec3(0.0D, 0.0D, 0.0D); + this.rotatedVertices[1] = new Vec3(0.0D, 0.0D, 0.0D); + this.rotatedVertices[2] = new Vec3(0.0D, 0.0D, 0.0D); + this.rotatedVertices[3] = new Vec3(0.0D, 0.0D, 0.0D); + this.rotatedNormals[0] = new Vec3(0.0D, 0.0D, 0.0D); + this.rotatedNormals[1] = new Vec3(0.0D, 0.0D, 0.0D); + this.rotatedNormals[2] = new Vec3(0.0D, 0.0D, 0.0D); + } + + static AABB getInitialAABB(double posX, double posY, double posZ, double center_x, double center_y, double center_z) { + double xLength = Math.abs(posX) + Math.abs(center_x); + double yLength = Math.abs(posY) + Math.abs(center_y); + double zLength = Math.abs(posZ) + Math.abs(center_z); + double maxLength = Math.max(xLength, Math.max(yLength, zLength)); + return new AABB(maxLength, maxLength, maxLength, -maxLength, -maxLength, -maxLength); + } + + public void transform(OpenMatrix4f modelMatrix) { + OpenMatrix4f noTranslation = modelMatrix.removeTranslation(); + + for (int i = 0; i < this.modelVertices.length; i++) { + this.rotatedVertices[i] = OpenMatrix4f.transform(noTranslation, this.modelVertices[i]); + } + + for (int i = 0; i < this.modelNormals.length; i++) { + this.rotatedNormals[i] = OpenMatrix4f.transform(noTranslation, this.modelNormals[i]); + } + + this.scale = noTranslation.toScaleVector(); + this.worldCenter = OpenMatrix4f.transform(modelMatrix, this.modelCenter); + } +} diff --git a/src/main/java/com/tiedup/remake/rig/mesh/SkinnedMesh.java b/src/main/java/com/tiedup/remake/rig/mesh/SkinnedMesh.java index e15c5bb..d282d45 100644 --- a/src/main/java/com/tiedup/remake/rig/mesh/SkinnedMesh.java +++ b/src/main/java/com/tiedup/remake/rig/mesh/SkinnedMesh.java @@ -34,8 +34,8 @@ import com.tiedup.remake.rig.util.ParseUtil; import com.tiedup.remake.rig.math.OpenMatrix4f; import com.tiedup.remake.rig.math.Vec4f; import com.tiedup.remake.rig.render.TiedUpRenderTypes; -import yesman.epicfight.client.renderer.shader.compute.ComputeShaderSetup; -import yesman.epicfight.client.renderer.shader.compute.loader.ComputeShaderProvider; +import com.tiedup.remake.rig.render.compute.ComputeShaderSetup; +import com.tiedup.remake.rig.render.compute.ComputeShaderProvider; import com.tiedup.remake.rig.TiedUpAnimationConfig; import com.tiedup.remake.rig.TiedUpRigConstants; diff --git a/src/main/java/com/tiedup/remake/rig/mesh/SoftBodyTranslatable.java b/src/main/java/com/tiedup/remake/rig/mesh/SoftBodyTranslatable.java index 1604ba0..11eefb0 100644 --- a/src/main/java/com/tiedup/remake/rig/mesh/SoftBodyTranslatable.java +++ b/src/main/java/com/tiedup/remake/rig/mesh/SoftBodyTranslatable.java @@ -15,7 +15,7 @@ import com.tiedup.remake.rig.mesh.Meshes.MeshAccessor; import com.tiedup.remake.rig.cloth.ClothSimulatable; import com.tiedup.remake.rig.cloth.ClothSimulator; import com.tiedup.remake.rig.cloth.ClothSimulator.ClothObject.ClothPart.ConstraintType; -import yesman.epicfight.api.physics.SimulationProvider; +import com.tiedup.remake.rig.physics.SimulationProvider; public interface SoftBodyTranslatable extends SimulationProvider { public static final List TRACKING_SIMULATION_SUBJECTS = Lists.newArrayList(); diff --git a/src/main/java/com/tiedup/remake/rig/patch/ClientPlayerPatch.java b/src/main/java/com/tiedup/remake/rig/patch/ClientPlayerPatch.java deleted file mode 100644 index c63772f..0000000 --- a/src/main/java/com/tiedup/remake/rig/patch/ClientPlayerPatch.java +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) - * by the Epic Fight Team, licensed under GPLv3. - * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. - */ - -package com.tiedup.remake.rig.patch; - -import java.util.Optional; - -import org.joml.Vector4f; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.AbstractClientPlayer; -import net.minecraft.client.resources.sounds.SimpleSoundInstance; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.PlayerRideableJumping; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.UseAnim; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.entity.EntityJoinLevelEvent; -import net.minecraftforge.event.entity.living.LivingEvent; -import com.tiedup.remake.rig.anim.Animator; -import com.tiedup.remake.rig.armature.JointTransform; -import com.tiedup.remake.rig.anim.LivingMotion; -import com.tiedup.remake.rig.anim.LivingMotions; -import com.tiedup.remake.rig.anim.Pose; -import com.tiedup.remake.rig.anim.property.AnimationProperty.StaticAnimationProperty; -import com.tiedup.remake.rig.anim.types.ActionAnimation; -import com.tiedup.remake.rig.anim.types.DynamicAnimation; -import com.tiedup.remake.rig.anim.client.ClientAnimator; -import com.tiedup.remake.rig.anim.client.Layer; -import com.tiedup.remake.rig.event.RenderEpicFightPlayerEvent; -import com.tiedup.remake.rig.event.UpdatePlayerMotionEvent; -import yesman.epicfight.client.online.EpicSkins; -import com.tiedup.remake.rig.cloth.ClothSimulatable; -import com.tiedup.remake.rig.cloth.ClothSimulator; -import yesman.epicfight.api.physics.PhysicsSimulator; -import yesman.epicfight.api.physics.SimulationTypes; -import com.tiedup.remake.rig.util.EntitySnapshot; -import com.tiedup.remake.rig.math.MathUtils; -import com.tiedup.remake.rig.math.OpenMatrix4f; -import com.tiedup.remake.rig.math.Vec3f; -import com.tiedup.remake.rig.TiedUpAnimationConfig; -import yesman.epicfight.gameasset.EpicFightSounds; -import yesman.epicfight.network.EntityPairingPacketTypes; -import yesman.epicfight.network.server.SPEntityPairingPacket; -import yesman.epicfight.particle.EpicFightParticles; -import com.tiedup.remake.rig.patch.EntityDecorations; -import com.tiedup.remake.rig.patch.EntityDecorations.RenderAttributeModifier; -import com.tiedup.remake.rig.patch.PlayerPatch; -import com.tiedup.remake.rig.patch.item.CapabilityItem; -import yesman.epicfight.world.entity.eventlistener.PlayerEventListener.EventType; - -public class AbstractClientPlayerPatch extends PlayerPatch implements ClothSimulatable { - private Item prevHeldItem; - private Item prevHeldItemOffHand; - protected EpicSkins epicSkinsInformation; - - @Override - public void onJoinWorld(T entity, EntityJoinLevelEvent event) { - super.onJoinWorld(entity, event); - - this.prevHeldItem = Items.AIR; - this.prevHeldItemOffHand = Items.AIR; - - EpicSkins.initEpicSkins(this); - } - - @Override - public void updateMotion(boolean considerInaction) { - if (this.original.getHealth() <= 0.0F) { - currentLivingMotion = LivingMotions.DEATH; - } else if (!this.state.updateLivingMotion() && considerInaction) { - currentLivingMotion = LivingMotions.INACTION; - } else { - if (original.isFallFlying() || original.isAutoSpinAttack()) { - currentLivingMotion = LivingMotions.FLY; - } else if (original.getVehicle() != null) { - if (original.getVehicle() instanceof PlayerRideableJumping) - currentLivingMotion = LivingMotions.MOUNT; - else - currentLivingMotion = LivingMotions.SIT; - } else if (original.isVisuallySwimming()) { - currentLivingMotion = LivingMotions.SWIM; - } else if (original.isSleeping()) { - currentLivingMotion = LivingMotions.SLEEP; - } else if (!original.onGround() && original.onClimbable()) { - currentLivingMotion = LivingMotions.CLIMB; - } else if (!original.getAbilities().flying) { - ClientAnimator animator = this.getClientAnimator(); - - if (original.isUnderWater() && (original.getY() - this.yo) < -0.005) - currentLivingMotion = LivingMotions.FLOAT; - else if (original.getY() - this.yo < -0.4F || this.isAirborneState()) - currentLivingMotion = LivingMotions.FALL; - else if (this.isMoving()) { - if (original.isCrouching()) - currentLivingMotion = LivingMotions.SNEAK; - else if (original.isSprinting()) - currentLivingMotion = LivingMotions.RUN; - else - currentLivingMotion = LivingMotions.WALK; - - animator.baseLayer.animationPlayer.setReversed(this.dz < 0); - - } else { - animator.baseLayer.animationPlayer.setReversed(false); - - if (original.isCrouching()) - currentLivingMotion = LivingMotions.KNEEL; - else - currentLivingMotion = LivingMotions.IDLE; - } - } else { - if (this.isMoving()) - currentLivingMotion = LivingMotions.CREATIVE_FLY; - else - currentLivingMotion = LivingMotions.CREATIVE_IDLE; - } - } - - UpdatePlayerMotionEvent.BaseLayer baseLayerEvent = new UpdatePlayerMotionEvent.BaseLayer(this, this.currentLivingMotion, !this.state.updateLivingMotion() && considerInaction); - this.eventListeners.triggerEvents(EventType.UPDATE_BASE_LIVING_MOTION_EVENT, baseLayerEvent); - MinecraftForge.EVENT_BUS.post(baseLayerEvent); - - this.currentLivingMotion = baseLayerEvent.getMotion(); - - if (!this.state.updateLivingMotion() && considerInaction) { - this.currentCompositeMotion = LivingMotions.NONE; - } else { - CapabilityItem mainhandItemCap = this.getHoldingItemCapability(InteractionHand.MAIN_HAND); - CapabilityItem offhandItemCap = this.getHoldingItemCapability(InteractionHand.OFF_HAND); - LivingMotion customLivingMotion = mainhandItemCap.getLivingMotion(this, InteractionHand.MAIN_HAND); - - if (customLivingMotion == null) customLivingMotion = offhandItemCap.getLivingMotion(this, InteractionHand.OFF_HAND); - - // When item capabilities has custom living motion - if (customLivingMotion != null) - currentCompositeMotion = customLivingMotion; - else if (this.original.isUsingItem()) { - UseAnim useAnim = this.original.getUseItem().getUseAnimation(); - if (useAnim == UseAnim.BLOCK) - currentCompositeMotion = LivingMotions.BLOCK_SHIELD; - else if (useAnim == UseAnim.CROSSBOW) - currentCompositeMotion = LivingMotions.RELOAD; - else if (useAnim == UseAnim.DRINK) - currentCompositeMotion = LivingMotions.DRINK; - else if (useAnim == UseAnim.EAT) - currentCompositeMotion = LivingMotions.EAT; - else if (useAnim == UseAnim.SPYGLASS) - currentCompositeMotion = LivingMotions.SPECTATE; - else - currentCompositeMotion = currentLivingMotion; - } else { - if (this.getClientAnimator().getCompositeLayer(Layer.Priority.MIDDLE).animationPlayer.getRealAnimation().get().isReboundAnimation()) - currentCompositeMotion = LivingMotions.SHOT; - else if (this.original.swinging && this.original.getSleepingPos().isEmpty()) - currentCompositeMotion = LivingMotions.DIGGING; - else - currentCompositeMotion = currentLivingMotion; - } - - UpdatePlayerMotionEvent.CompositeLayer compositeLayerEvent = new UpdatePlayerMotionEvent.CompositeLayer(this, this.currentCompositeMotion); - this.eventListeners.triggerEvents(EventType.UPDATE_COMPOSITE_LIVING_MOTION_EVENT, compositeLayerEvent); - MinecraftForge.EVENT_BUS.post(compositeLayerEvent); - - this.currentCompositeMotion = compositeLayerEvent.getMotion(); - } - } - - @Override - public void onOldPosUpdate() { - this.modelYRotO2 = this.modelYRotO; - this.xPosO2 = (float)this.original.xOld; - this.yPosO2 = (float)this.original.yOld; - this.zPosO2 = (float)this.original.zOld; - } - - @Override - protected void clientTick(LivingEvent.LivingTickEvent event) { - this.xCloakO2 = this.original.xCloakO; - this.yCloakO2 = this.original.yCloakO; - this.zCloakO2 = this.original.zCloakO; - - super.clientTick(event); - - if (!this.getEntityState().updateLivingMotion()) { - this.original.yBodyRot = this.original.yHeadRot; - } - - boolean isMainHandChanged = this.prevHeldItem != this.original.getInventory().getSelected().getItem(); - boolean isOffHandChanged = this.prevHeldItemOffHand != this.original.getInventory().offhand.get(0).getItem(); - - if (isMainHandChanged || isOffHandChanged) { - this.updateHeldItem(this.getHoldingItemCapability(InteractionHand.MAIN_HAND), this.getHoldingItemCapability(InteractionHand.OFF_HAND)); - - if (isMainHandChanged) { - this.prevHeldItem = this.original.getInventory().getSelected().getItem(); - } - - if (isOffHandChanged) { - this.prevHeldItemOffHand = this.original.getInventory().offhand.get(0).getItem(); - } - } - - /** {@link LivingDeathEvent} never fired for client players **/ - if (this.original.deathTime == 1) { - this.getClientAnimator().playDeathAnimation(); - } - - this.clothSimulator.tick(this); - } - - protected boolean isMoving() { - return Math.abs(this.dx) > 0.01F || Math.abs(this.dz) > 0.01F; - } - - public void updateHeldItem(CapabilityItem mainHandCap, CapabilityItem offHandCap) { - this.cancelItemUse(); - - this.getClientAnimator().iterAllLayers((layer) -> { - if (layer.isOff()) { - return; - } - - layer.animationPlayer.getRealAnimation().get().getProperty(StaticAnimationProperty.ON_ITEM_CHANGE_EVENT).ifPresent((event) -> { - event.params(mainHandCap, offHandCap); - event.execute(this, layer.animationPlayer.getRealAnimation(), layer.animationPlayer.getPrevElapsedTime(), layer.animationPlayer.getElapsedTime()); - }); - }); - } - - // RIG : entityPairing() EF = hook combat skills (Technician, Adrenaline, - // Emergency Escape). Strippé intégralement — ces skills n'existent pas - // en TiedUp. Le super.entityPairing() de base reste disponible si jamais - // une extension TiedUp veut hooker des paires custom. - - @Override - public boolean overrideRender() { - RenderEpicFightPlayerEvent renderepicfightplayerevent = new RenderEpicFightPlayerEvent(this, !TiedUpAnimationConfig.enableOriginalModel || this.isEpicFightMode()); - MinecraftForge.EVENT_BUS.post(renderepicfightplayerevent); - return renderepicfightplayerevent.getShouldRender(); - } - - @Override - public boolean shouldMoveOnCurrentSide(ActionAnimation actionAnimation) { - return false; - } - - @Override - public void poseTick(DynamicAnimation animation, Pose pose, float elapsedTime, float partialTick) { - if (pose.hasTransform("Head") && this.armature.hasJoint("Head")) { - if (animation.doesHeadRotFollowEntityHead()) { - float headRelativeRot = Mth.rotLerp(partialTick, Mth.wrapDegrees(this.modelYRotO - this.original.yHeadRotO), Mth.wrapDegrees(this.modelYRot - this.original.yHeadRot)); - OpenMatrix4f headTransform = this.armature.getBoundTransformFor(pose, this.armature.searchJointByName("Head")); - OpenMatrix4f toOriginalRotation = headTransform.removeScale().removeTranslation().invert(); - Vec3f xAxis = OpenMatrix4f.transform3v(toOriginalRotation, Vec3f.X_AXIS, null); - Vec3f yAxis = OpenMatrix4f.transform3v(toOriginalRotation, Vec3f.Y_AXIS, null); - OpenMatrix4f headRotation = OpenMatrix4f.createRotatorDeg(headRelativeRot, yAxis).rotateDeg(-Mth.rotLerp(partialTick, this.original.xRotO, this.original.getXRot()), xAxis); - pose.orElseEmpty("Head").frontResult(JointTransform.fromMatrix(headRotation), OpenMatrix4f::mul); - } - } - } - - @Override - public OpenMatrix4f getModelMatrix(float partialTick) { - if (this.original.isAutoSpinAttack()) { - OpenMatrix4f mat = MathUtils.getModelMatrixIntegral(0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0, 0, 0, 0, partialTick, PLAYER_SCALE, PLAYER_SCALE, PLAYER_SCALE); - float yRot = MathUtils.lerpBetween(this.original.yRotO, this.original.getYRot(), partialTick); - float xRot = MathUtils.lerpBetween(this.original.xRotO, this.original.getXRot(), partialTick); - - mat.rotateDeg(-yRot, Vec3f.Y_AXIS) - .rotateDeg(-xRot, Vec3f.X_AXIS) - .rotateDeg((this.original.tickCount + partialTick) * -55.0F, Vec3f.Z_AXIS) - .translate(0F, -0.39F, 0F); - - return mat; - } else if (this.original.isFallFlying()) { - OpenMatrix4f mat = MathUtils.getModelMatrixIntegral(0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0, 0, 0, 0, partialTick, PLAYER_SCALE, PLAYER_SCALE, PLAYER_SCALE); - float f1 = (float)this.original.getFallFlyingTicks() + partialTick; - float f2 = Mth.clamp(f1 * f1 / 100.0F, 0.0F, 1.0F); - - mat.rotateDeg(-Mth.rotLerp(partialTick, this.original.yBodyRotO, this.original.yBodyRot), Vec3f.Y_AXIS).rotateDeg(f2 * (-this.original.getXRot()), Vec3f.X_AXIS); - - Vec3 vec3d = this.original.getViewVector(partialTick); - Vec3 vec3d1 = this.original.getDeltaMovementLerped(partialTick); - double d0 = vec3d1.horizontalDistanceSqr(); - double d1 = vec3d.horizontalDistanceSqr(); - - if (d0 > 0.0D && d1 > 0.0D) { - double d2 = (vec3d1.x * vec3d.x + vec3d1.z * vec3d.z) / (Math.sqrt(d0) * Math.sqrt(d1)); - double d3 = vec3d1.x * vec3d.z - vec3d1.z * vec3d.x; - mat.rotate((float)-((Math.signum(d3) * Math.acos(d2))), Vec3f.Z_AXIS); - } - - return mat; - - } else if (this.original.isSleeping()) { - BlockState blockstate = this.original.getFeetBlockState(); - float yRot = 0.0F; - - if (blockstate.isBed(this.original.level(), this.original.getSleepingPos().orElse(null), this.original)) { - if (blockstate.hasProperty(BlockStateProperties.HORIZONTAL_FACING)) { - switch(blockstate.getValue(BlockStateProperties.HORIZONTAL_FACING)) { - case EAST: - yRot = 90.0F; - break; - case WEST: - yRot = -90.0F; - break; - case SOUTH: - yRot = 180.0F; - break; - default: - break; - } - } - } - - return MathUtils.getModelMatrixIntegral(0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, yRot, yRot, 0, PLAYER_SCALE, PLAYER_SCALE, PLAYER_SCALE); - } else { - float yRotO; - float yRot; - float xRotO = 0; - float xRot = 0; - - if (this.original.getVehicle() instanceof LivingEntity ridingEntity) { - yRotO = ridingEntity.yBodyRotO; - yRot = ridingEntity.yBodyRot; - } else { - yRotO = this.modelYRotO; - yRot = this.modelYRot; - } - - if (!this.getEntityState().inaction() && this.original.getPose() == net.minecraft.world.entity.Pose.SWIMMING) { - float f = this.original.getSwimAmount(partialTick); - float f3 = this.original.isInWater() ? this.original.getXRot() : 0; - float f4 = Mth.lerp(f, 0.0F, f3); - xRotO = f4; - xRot = f4; - } - - return MathUtils.getModelMatrixIntegral(0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, xRotO, xRot, yRotO, yRot, partialTick, PLAYER_SCALE, PLAYER_SCALE, PLAYER_SCALE); - } - } - - public void setEpicSkinsInformation(EpicSkins epicSkinsInformation) { - this.epicSkinsInformation = epicSkinsInformation; - } - - public EpicSkins getEpicSkinsInformation() { - return this.epicSkinsInformation; - } - - public boolean isEpicSkinsLoaded() { - return this.epicSkinsInformation != null; - } - - @Override - public EntitySnapshot captureEntitySnapshot() { - return EntitySnapshot.capturePlayer(this); - } - - private final ClothSimulator clothSimulator = new ClothSimulator(); - public float modelYRotO2; - public double xPosO2; - public double yPosO2; - public double zPosO2; - public double xCloakO2; - public double yCloakO2; - public double zCloakO2; - - @SuppressWarnings("unchecked") - @Override - public > Optional getSimulator(SimulationTypes simulationType) { - if (simulationType == SimulationTypes.CLOTH) { - return Optional.of((SIM)this.clothSimulator); - } - - return Optional.empty(); - } - - @Override - public ClothSimulator getClothSimulator() { - return this.clothSimulator; - } - - @Override - public Vec3 getAccurateCloakLocation(float partialFrame) { - if (partialFrame < 0.0F) { - partialFrame = 1.0F - partialFrame; - - double x = Mth.lerp((double)partialFrame, this.xCloakO2, this.original.xCloakO) - Mth.lerp((double)partialFrame, this.xPosO2, this.original.xo); - double y = Mth.lerp((double)partialFrame, this.yCloakO2, this.original.yCloakO) - Mth.lerp((double)partialFrame, this.yPosO2, this.original.yo); - double z = Mth.lerp((double)partialFrame, this.zCloakO2, this.original.zCloakO) - Mth.lerp((double)partialFrame, this.zPosO2, this.original.zo); - - return new Vec3(x, y, z); - } else { - double x = Mth.lerp((double)partialFrame, this.original.xCloakO, this.original.xCloak) - Mth.lerp((double)partialFrame, this.original.xo, this.original.getX()); - double y = Mth.lerp((double)partialFrame, this.original.yCloakO, this.original.yCloak) - Mth.lerp((double)partialFrame, this.original.yo, this.original.getY()); - double z = Mth.lerp((double)partialFrame, this.original.zCloakO, this.original.zCloak) - Mth.lerp((double)partialFrame, this.original.zo, this.original.getZ()); - - return new Vec3(x, y, z); - } - } - - @Override - public Vec3 getAccuratePartialLocation(float partialFrame) { - if (partialFrame < 0.0F) { - partialFrame = 1.0F + partialFrame; - - double x = Mth.lerp((double)partialFrame, this.xPosO2, this.original.xOld); - double y = Mth.lerp((double)partialFrame, this.yPosO2, this.original.yOld); - double z = Mth.lerp((double)partialFrame, this.zPosO2, this.original.zOld); - - return new Vec3(x, y, z); - } else { - double x = Mth.lerp((double)partialFrame, this.original.xOld, this.original.getX()); - double y = Mth.lerp((double)partialFrame, this.original.yOld, this.original.getY()); - double z = Mth.lerp((double)partialFrame, this.original.zOld, this.original.getZ()); - - return new Vec3(x, y, z); - } - } - - @Override - public Vec3 getObjectVelocity() { - return new Vec3(this.original.getX() - this.original.xOld, this.original.getY() - this.original.yOld, this.original.getZ() - this.original.zOld); - } - - @Override - public float getAccurateYRot(float partialFrame) { - if (partialFrame < 0.0F) { - partialFrame = 1.0F + partialFrame; - - return Mth.rotLerp(partialFrame, this.modelYRotO2, this.getYRotO()); - } else { - return Mth.rotLerp(partialFrame, this.getYRotO(), this.getYRot()); - } - } - - @Override - public float getYRotDelta(float partialFrame) { - if (partialFrame < 0.0F) { - partialFrame = 1.0F + partialFrame; - - return Mth.rotLerp(partialFrame, this.modelYRotO2, this.getYRotO()) - this.modelYRotO2; - } else { - return Mth.rotLerp(partialFrame, this.getYRotO(), this.getYRot()) - this.getYRotO(); - } - } - - @Override - public boolean invalid() { - return this.original.isRemoved(); - } - - @Override - public float getScale() { - return PLAYER_SCALE; - } - - @Override - public Animator getSimulatableAnimator() { - return this.animator; - } - - @Override - public float getGravity() { - return this.getOriginal().isUnderWater() ? 0.98F : 9.8F; - } -} diff --git a/src/main/java/com/tiedup/remake/rig/patch/EntityPatch.java b/src/main/java/com/tiedup/remake/rig/patch/EntityPatch.java new file mode 100644 index 0000000..1835cc0 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/patch/EntityPatch.java @@ -0,0 +1,83 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.patch; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.event.entity.EntityJoinLevelEvent; +import net.minecraftforge.event.entity.living.LivingDeathEvent; + +import com.tiedup.remake.rig.math.MathUtils; +import com.tiedup.remake.rig.math.OpenMatrix4f; + +/** + * Stub RIG Phase 0 — patch de capability Forge attaché à une entité pour porter + * armature/animator/état. Version strippée des références combat EF + * (SPEntityPairingPacket, ProcessEntityPairingPacketEvent). + */ +public abstract class EntityPatch { + protected T original; + protected boolean initialized = false; + + public void onOldPosUpdate() { + } + + public void onAddedToWorld() { + } + + public abstract boolean overrideRender(); + + public void onStartTracking(ServerPlayer trackingPlayer) { + } + + public void onStopTracking(ServerPlayer trackingPlayer) { + } + + public void onConstructed(T entity) { + this.original = entity; + } + + public void onJoinWorld(T entity, EntityJoinLevelEvent event) { + this.initialized = true; + } + + public void onDeath(LivingDeathEvent event) { + } + + public final T getOriginal() { + return this.original; + } + + public boolean isInitialized() { + return this.initialized; + } + + public boolean isLogicalClient() { + return this.original.level().isClientSide(); + } + + public OpenMatrix4f getMatrix(float partialTick) { + return MathUtils.getModelMatrixIntegral(0, 0, 0, 0, 0, 0, this.original.xRotO, this.original.getXRot(), this.original.yRotO, this.original.getYRot(), partialTick, 1, 1, 1); + } + + public double getAngleTo(Entity entity) { + Vec3 a = this.original.getLookAngle(); + Vec3 b = new Vec3(entity.getX() - this.original.getX(), entity.getY() - this.original.getY(), entity.getZ() - this.original.getZ()).normalize(); + double cos = (a.x * b.x + a.y * b.y + a.z * b.z); + return Math.toDegrees(Math.acos(cos)); + } + + public double getAngleToHorizontal(Entity entity) { + Vec3 a = this.original.getLookAngle(); + Vec3 b = new Vec3(entity.getX() - this.original.getX(), 0.0D, entity.getZ() - this.original.getZ()).normalize(); + double cos = (a.x * b.x + a.y * b.y + a.z * b.z); + return Math.toDegrees(Math.acos(cos)); + } + + public abstract OpenMatrix4f getModelMatrix(float partialTick); +} diff --git a/src/main/java/com/tiedup/remake/rig/patch/LivingEntityPatch.java b/src/main/java/com/tiedup/remake/rig/patch/LivingEntityPatch.java new file mode 100644 index 0000000..4c63d4d --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/patch/LivingEntityPatch.java @@ -0,0 +1,96 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.patch; + +import javax.annotation.Nullable; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.Vec3; + +import com.tiedup.remake.rig.anim.Animator; +import com.tiedup.remake.rig.anim.LivingMotion; +import com.tiedup.remake.rig.anim.LivingMotions; +import com.tiedup.remake.rig.anim.Pose; +import com.tiedup.remake.rig.anim.client.ClientAnimator; +import com.tiedup.remake.rig.anim.types.DynamicAnimation; +import com.tiedup.remake.rig.armature.Armature; + +/** + * Stub RIG Phase 0 — patch de capability attaché à un {@link LivingEntity}. + * Expose l'animator, l'armature, la motion courante + quelques helpers. + * La version finale sera étoffée en Phase 2 (NPCs + player) avec les données + * d'entraînement/bondage spécifiques. + */ +public abstract class LivingEntityPatch extends EntityPatch { + public LivingMotion currentLivingMotion = LivingMotions.IDLE; + public LivingMotion currentCompositeMotion = LivingMotions.IDLE; + + public abstract void updateMotion(boolean considerInaction); + + public abstract Armature getArmature(); + + public Animator getAnimator() { + return null; + } + + @Nullable + public ClientAnimator getClientAnimator() { + return null; + } + + public LivingMotion getCurrentLivingMotion() { + return this.currentLivingMotion; + } + + public LivingMotion getCurrentCompositeMotion() { + return this.currentCompositeMotion; + } + + @Nullable + public LivingEntity getTarget() { + return this.original != null ? this.original.getLastHurtMob() : null; + } + + @Nullable + public LivingEntity getGrapplingTarget() { + return null; + } + + public float getReach() { + return 1.0F; + } + + public float getYRot() { + return this.original.getYRot(); + } + + public void setYRot(float yRot) { + this.original.setYRot(yRot); + } + + public float getYRotLimit() { + return 180.0F; + } + + public float getYRotDeltaTo(Entity entity) { + Vec3 delta = entity.position().subtract(this.original.position()); + float yaw = (float) Math.toDegrees(Math.atan2(delta.z, delta.x)) - 90.0F; + return net.minecraft.util.Mth.wrapDegrees(yaw - this.original.getYRot()); + } + + public void poseTick(DynamicAnimation animation, Pose pose, float elapsedTime, float partialTick) { + } + + public void updateEntityState() { + } + + @Override + public boolean overrideRender() { + return false; + } +} diff --git a/src/main/java/com/tiedup/remake/rig/patch/LocalPlayerPatch.java b/src/main/java/com/tiedup/remake/rig/patch/LocalPlayerPatch.java deleted file mode 100644 index a4c5f29..0000000 --- a/src/main/java/com/tiedup/remake/rig/patch/LocalPlayerPatch.java +++ /dev/null @@ -1,579 +0,0 @@ -/* - * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) - * by the Epic Fight Team, licensed under GPLv3. - * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. - */ - -package com.tiedup.remake.rig.patch; - -import net.minecraft.client.CameraType; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.client.event.ClientPlayerNetworkEvent; -import net.minecraftforge.entity.PartEntity; -import net.minecraftforge.event.entity.EntityJoinLevelEvent; -import net.minecraftforge.event.entity.living.LivingEvent; -import com.tiedup.remake.rig.armature.JointTransform; -import com.tiedup.remake.rig.anim.Keyframe; -import com.tiedup.remake.rig.anim.Pose; -import com.tiedup.remake.rig.anim.TransformSheet; -import com.tiedup.remake.rig.anim.property.AnimationProperty.ActionAnimationProperty; -import com.tiedup.remake.rig.anim.types.ActionAnimation; -import com.tiedup.remake.rig.anim.types.AttackAnimation; -import com.tiedup.remake.rig.anim.types.DirectStaticAnimation; -import com.tiedup.remake.rig.anim.types.StaticAnimation; -import com.tiedup.remake.rig.asset.AssetAccessor; -import com.tiedup.remake.rig.anim.client.AnimationSubFileReader; -import com.tiedup.remake.rig.anim.client.AnimationSubFileReader.PovSettings; -import com.tiedup.remake.rig.anim.client.AnimationSubFileReader.PovSettings.ViewLimit; -import com.tiedup.remake.rig.anim.client.Layer; -import com.tiedup.remake.rig.anim.client.property.ClientAnimationProperties; -import yesman.epicfight.api.client.camera.EpicFightCameraAPI; -import yesman.epicfight.api.client.input.InputManager; -import yesman.epicfight.api.client.input.action.MinecraftInputAction; -import com.tiedup.remake.rig.math.MathUtils; -import yesman.epicfight.client.ClientEngine; -import yesman.epicfight.client.events.engine.RenderEngine; -import yesman.epicfight.client.gui.screen.SkillBookScreen; -import com.tiedup.remake.rig.TiedUpAnimationConfig; -import com.tiedup.remake.rig.TiedUpRigRegistry; -import com.tiedup.remake.rig.TiedUpRigConstants; -import yesman.epicfight.network.EpicFightNetworkManager; -import yesman.epicfight.network.client.CPAnimatorControl; -import yesman.epicfight.network.client.CPChangePlayerMode; -import yesman.epicfight.network.client.CPModifyEntityModelYRot; -import yesman.epicfight.network.client.CPSetStamina; -import yesman.epicfight.network.common.AnimatorControlPacket; -import yesman.epicfight.skill.modules.ChargeableSkill; -import com.tiedup.remake.rig.patch.LivingEntityPatch; -import com.tiedup.remake.rig.patch.PlayerPatch; -import com.tiedup.remake.rig.patch.item.CapabilityItem; -import yesman.epicfight.world.entity.eventlistener.PlayerEventListener.EventType; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -public class LocalPlayerPatch extends AbstractClientPlayerPatch { - - private static final UUID ACTION_EVENT_UUID = UUID.fromString("d1a1e102-1621-11ed-861d-0242ac120002"); - private Minecraft minecraft; - private float staminaO; - private int prevChargingAmount; - - private AnimationSubFileReader.PovSettings povSettings; - private FirstPersonLayer firstPersonLayer = new FirstPersonLayer(); - - @Override - public void onConstructed(LocalPlayer entity) { - super.onConstructed(entity); - this.minecraft = Minecraft.getInstance(); - } - - @Override - public void onJoinWorld(LocalPlayer player, EntityJoinLevelEvent event) { - super.onJoinWorld(player, event); - - this.eventListeners.addEventListener(EventType.ACTION_EVENT_CLIENT, ACTION_EVENT_UUID, (playerEvent) -> { - ClientEngine.getInstance().controlEngine.unlockHotkeys(); - }); - } - - public void onRespawnLocalPlayer(ClientPlayerNetworkEvent.Clone event) { - this.onJoinWorld(event.getNewPlayer(), new EntityJoinLevelEvent(event.getNewPlayer(), event.getNewPlayer().level())); - } - - @Override - public void tick(LivingEvent.LivingTickEvent event) { - this.staminaO = this.getStamina(); - - if (this.isHoldingAny() && this.getHoldingSkill() instanceof ChargeableSkill) { - this.prevChargingAmount = this.getChargingAmount(); - } else { - this.prevChargingAmount = 0; - } - - super.tick(event); - } - - @Override - public void clientTick(LivingEvent.LivingTickEvent event) { - this.staminaO = this.getStamina(); - - super.clientTick(event); - - // Handle first person animation - final AssetAccessor currentPlaying = this.firstPersonLayer.animationPlayer.getRealAnimation(); - - boolean noPovAnimation = this.getClientAnimator().iterVisibleLayersUntilFalse(layer -> { - if (layer.isOff()) { - return true; - } - - Optional optPovAnimation = layer.animationPlayer.getRealAnimation().get().getProperty(ClientAnimationProperties.POV_ANIMATION); - Optional optPovSettings = layer.animationPlayer.getRealAnimation().get().getProperty(ClientAnimationProperties.POV_SETTINGS); - - optPovAnimation.ifPresent(povAnimation -> { - if (!povAnimation.equals(currentPlaying.get())) { - this.firstPersonLayer.playAnimation(povAnimation, layer.animationPlayer.getRealAnimation(), this, 0.0F); - this.povSettings = optPovSettings.get(); - } - }); - - return !optPovAnimation.isPresent(); - }); - - if (noPovAnimation && !currentPlaying.equals(TiedUpRigRegistry.EMPTY_ANIMATION)) { - this.firstPersonLayer.off(); - } - - this.firstPersonLayer.update(this); - - if (this.firstPersonLayer.animationPlayer.getAnimation().equals(TiedUpRigRegistry.EMPTY_ANIMATION)) { - this.povSettings = null; - } - } - - @Override - public boolean overrideRender() { - // Disable rendering the player when animated first person model disabled - if (this.original.is(this.minecraft.player)) { - if (this.minecraft.options.getCameraType().isFirstPerson() && !TiedUpAnimationConfig.enableAnimatedFirstPersonModel) { - return false; - } - } - - return super.overrideRender(); - } - - @Override - public LivingEntity getTarget() { - return EpicFightCameraAPI.getInstance().getFocusingEntity(); - } - - @Override - public void toVanillaMode(boolean synchronize) { - if (this.playerMode != PlayerMode.VANILLA) { - ClientEngine.getInstance().renderEngine.downSlideSkillUI(); - - if (TiedUpAnimationConfig.autoSwitchCamera) { - this.minecraft.options.setCameraType(CameraType.FIRST_PERSON); - } - - if (synchronize) { - EpicFightNetworkManager.sendToServer(new CPChangePlayerMode(PlayerMode.VANILLA)); - } - } - - super.toVanillaMode(synchronize); - } - - @Override - public void toEpicFightMode(boolean synchronize) { - if (this.playerMode != PlayerMode.EPICFIGHT) { - ClientEngine.getInstance().renderEngine.upSlideSkillUI(); - - if (TiedUpAnimationConfig.autoSwitchCamera) { - this.minecraft.options.setCameraType(CameraType.THIRD_PERSON_BACK); - } - - if (synchronize) { - EpicFightNetworkManager.sendToServer(new CPChangePlayerMode(PlayerMode.EPICFIGHT)); - } - } - - super.toEpicFightMode(synchronize); - } - - @Override - public boolean isFirstPerson() { - return this.minecraft.options.getCameraType() == CameraType.FIRST_PERSON; - } - - @Override - public boolean shouldBlockMoving() { - return InputManager.isActionActive(MinecraftInputAction.MOVE_BACKWARD) || InputManager.isActionActive(MinecraftInputAction.SNEAK); - } - - @Override - public boolean shouldMoveOnCurrentSide(ActionAnimation actionAnimation) { - if (!this.isLogicalClient()) { - return false; - } - - return actionAnimation.shouldPlayerMove(this); - } - - public float getStaminaO() { - return this.staminaO; - } - - public int getPrevChargingAmount() { - return this.prevChargingAmount; - } - - public FirstPersonLayer getFirstPersonLayer() { - return this.firstPersonLayer; - } - - public AnimationSubFileReader.PovSettings getPovSettings() { - return this.povSettings; - } - - public boolean hasCameraAnimation() { - return this.povSettings != null && this.povSettings.cameraTransform() != null; - } - - @Override - public void setStamina(float value) { - EpicFightNetworkManager.sendToServer(new CPSetStamina(value, true)); - } - - @Override - public void setModelYRot(float amount, boolean sendPacket) { - super.setModelYRot(amount, sendPacket); - - if (sendPacket) { - EpicFightNetworkManager.sendToServer(new CPModifyEntityModelYRot(amount)); - } - } - - public float getModelYRot() { - return this.modelYRot; - } - - public void setModelYRotInGui(float rotDeg) { - this.useModelYRot = true; - this.modelYRot = rotDeg; - } - - public void disableModelYRotInGui(float originalDeg) { - this.useModelYRot = false; - this.modelYRot = originalDeg; - } - - @Override - public void disableModelYRot(boolean sendPacket) { - super.disableModelYRot(sendPacket); - - if (sendPacket) { - EpicFightNetworkManager.sendToServer(new CPModifyEntityModelYRot()); - } - } - - @Override - public double checkXTurn(double xRot) { - if (xRot == 0.0D) { - return xRot; - } - - if (TiedUpAnimationConfig.enablePovAction && this.minecraft.options.getCameraType().isFirstPerson() && this.isEpicFightMode() && !this.getFirstPersonLayer().isOff()) { - ViewLimit viewLimit = this.getPovSettings().viewLimit(); - - if (viewLimit != null) { - float xRotDest = this.original.getXRot() + (float)xRot * 0.15F; - - if (xRotDest <= viewLimit.xRotMin() || xRotDest >= viewLimit.xRotMax()) { - return 0.0D; - } - } - } - - return xRot; - } - - @Override - public double checkYTurn(double yRot) { - if (yRot == 0.0D) { - return yRot; - } - - if (TiedUpAnimationConfig.enablePovAction && this.minecraft.options.getCameraType().isFirstPerson() && this.isEpicFightMode() && !this.getFirstPersonLayer().isOff()) { - ViewLimit viewLimit = this.getPovSettings().viewLimit(); - - if (viewLimit != null) { - float yCamera = Mth.wrapDegrees(this.original.getYRot()); - float yBody = MathUtils.findNearestRotation(yCamera, this.getYRot()); - float yRotDest = yCamera + (float)yRot * 0.15F; - float yRotClamped = Mth.clamp(yRotDest, yBody + viewLimit.yRotMin(), yBody + viewLimit.yRotMax()); - - if (yRotDest != yRotClamped) { - return 0.0D; - } - } - } - - return yRot; - } - - @Override - public void beginAction(ActionAnimation animation) { - EpicFightCameraAPI cameraApi = EpicFightCameraAPI.getInstance(); - - if (cameraApi.isTPSMode()) { - if (cameraApi.getFocusingEntity() != null && animation instanceof AttackAnimation) { - cameraApi.alignPlayerLookToCrosshair(false, true, true); - } else { - cameraApi.alignPlayerLookToCameraRotation(false, true, true); - } - } - - if (!this.useModelYRot || animation.getProperty(ActionAnimationProperty.SYNC_CAMERA).orElse(false)) { - this.modelYRot = this.original.getYRot(); - } - - if (cameraApi.getFocusingEntity() != null && cameraApi.isLockingOnTarget() && !cameraApi.getFocusingEntity().isRemoved()) { - Vec3 playerPosition = this.original.position(); - Vec3 targetPosition = cameraApi.getFocusingEntity().position(); - Vec3 toTarget = targetPosition.subtract(playerPosition); - this.original.setYRot((float)MathUtils.getYRotOfVector(toTarget)); - } - } - - /** - * Play an animation after the current animation is finished - * @param animation - */ - @Override - public void reserveAnimation(AssetAccessor animation) { - this.animator.reserveAnimation(animation); - EpicFightNetworkManager.sendToServer(new CPAnimatorControl(AnimatorControlPacket.Action.RESERVE, animation, 0.0F, false, false, false)); - } - - /** - * Play an animation without convert time - * @param animation - */ - @Override - public void playAnimationInstantly(AssetAccessor animation) { - this.animator.playAnimationInstantly(animation); - EpicFightNetworkManager.sendToServer(new CPAnimatorControl(AnimatorControlPacket.Action.PLAY_INSTANTLY, animation, 0.0F, false, false, false)); - } - - /** - * Play a shooting animation to end aim pose - * This method doesn't send packet from client to server - */ - @Override - public void playShootingAnimation() { - this.animator.playShootingAnimation(); - EpicFightNetworkManager.sendToServer(new CPAnimatorControl(AnimatorControlPacket.Action.SHOT, -1, 0.0F, false, true, false)); - } - - /** - * Stop playing an animation - * @param animation - * @param transitionTimeModifier - */ - @Override - public void stopPlaying(AssetAccessor animation) { - this.animator.stopPlaying(animation); - EpicFightNetworkManager.sendToServer(new CPAnimatorControl(AnimatorControlPacket.Action.STOP, animation, -1.0F, false, false, false)); - } - - /** - * Play an animation ensuring synchronization between client-server - * Plays animation when getting response from server if it called in client side. - * Do not call this in client side for non-player entities. - * - * @param animation - * @param transitionTimeModifier - */ - @Override - public void playAnimationSynchronized(AssetAccessor animation, float transitionTimeModifier) { - EpicFightNetworkManager.sendToServer(new CPAnimatorControl(AnimatorControlPacket.Action.PLAY, animation, transitionTimeModifier, false, false, true)); - } - - /** - * Play an animation only in client side, including all clients tracking this entity - * @param animation - * @param convertTimeModifier - */ - @Override - public void playAnimationInClientSide(AssetAccessor animation, float transitionTimeModifier) { - this.animator.playAnimation(animation, transitionTimeModifier); - EpicFightNetworkManager.sendToServer(new CPAnimatorControl(AnimatorControlPacket.Action.PLAY, animation, transitionTimeModifier, false, true, false)); - } - - /** - * Pause an animator until it receives a proper order - * @param action SOFT_PAUSE: resume when next animation plays - * HARD_PAUSE: resume when hard pause is set false - * @param pause - **/ - @Override - public void pauseAnimator(AnimatorControlPacket.Action action, boolean pause) { - super.pauseAnimator(action, pause); - EpicFightNetworkManager.sendToServer(new CPAnimatorControl(action, -1, 0.0F, pause, false, false)); - } - - @Override - public void openSkillBook(ItemStack itemstack, InteractionHand hand) { - if (itemstack.hasTag() && itemstack.getTag().contains("skill")) { - Minecraft.getInstance().setScreen(new SkillBookScreen(this.original, itemstack, hand)); - } - } - - @Override - public void resetHolding() { - if (this.holdingSkill != null) { - ClientEngine.getInstance().controlEngine.releaseAllServedKeys(); - } - - super.resetHolding(); - } - - @Override - public void updateHeldItem(CapabilityItem mainHandCap, CapabilityItem offHandCap) { - super.updateHeldItem(mainHandCap, offHandCap); - - if (!TiedUpAnimationConfig.preferenceWork.checkHitResult()) { - if (TiedUpAnimationConfig.combatPreferredItems.contains(this.original.getMainHandItem().getItem())) { - this.toEpicFightMode(true); - } else if (TiedUpAnimationConfig.miningPreferredItems.contains(this.original.getMainHandItem().getItem())) { - this.toVanillaMode(true); - } - } - } - - /** - * Judge the next behavior depending on player's item preference and where he's looking at - * @return true if the next action is swing a weapon, false if the next action is breaking a block - */ - public boolean canPlayAttackAnimation() { - if (this.isVanillaMode()) { - return false; - } - - EpicFightCameraAPI cameraApi = EpicFightCameraAPI.getInstance(); - - HitResult hitResult = - (EpicFightCameraAPI.getInstance().isTPSMode() && cameraApi.getCrosshairHitResult() != null && cameraApi.getCrosshairHitResult().getLocation().distanceToSqr(this.original.getEyePosition()) < this.original.getBlockReach() * this.original.getBlockReach()) - ? cameraApi.getCrosshairHitResult() : this.minecraft.hitResult; - - if (hitResult == null) { - return true; - } - - EntityHitResult entityHitResult = RenderEngine.asEntityHitResult(hitResult); - - if (entityHitResult != null) { - Entity hitEntity = entityHitResult.getEntity(); - - if (!(hitEntity instanceof LivingEntity) && !(hitEntity instanceof PartEntity)) { - return false; - } - } - - if (EpicFightCameraAPI.getInstance().isLockingOnTarget()) { - return true; - } - - if (TiedUpAnimationConfig.preferenceWork.checkHitResult()) { - if (TiedUpAnimationConfig.combatPreferredItems.contains(this.original.getMainHandItem().getItem())) { - BlockHitResult blockHitResult = RenderEngine.asBlockHitResult(this.minecraft.hitResult); - - if (blockHitResult != null && this.minecraft.level != null) { - BlockPos bp = blockHitResult.getBlockPos(); - BlockState bs = this.minecraft.level.getBlockState(bp); - return !this.original.getMainHandItem().getItem().canAttackBlock(bs, this.original.level(), bp, this.original) || !this.original.getMainHandItem().isCorrectToolForDrops(bs); - } - } else { - return RenderEngine.hitResultNotEquals(this.minecraft.hitResult, HitResult.Type.BLOCK); - } - - return true; - } else { - return this.getPlayerMode() == PlayerPatch.PlayerMode.EPICFIGHT; - } - } - - public class FirstPersonLayer extends Layer { - private TransformSheet linkCameraTransform = new TransformSheet(List.of(new Keyframe(0.0F, JointTransform.empty()), new Keyframe(Float.MAX_VALUE, JointTransform.empty()))); - - public FirstPersonLayer() { - super(null); - } - - public void playAnimation(AssetAccessor nextFirstPersonAnimation, AssetAccessor originalAnimation, LivingEntityPatch entitypatch, float transitionTimeModifier) { - Optional povSettings = originalAnimation.get().getProperty(ClientAnimationProperties.POV_SETTINGS); - - boolean hasPrevCameraAnimation = LocalPlayerPatch.this.povSettings != null && LocalPlayerPatch.this.povSettings.cameraTransform() != null; - boolean hasNextCameraAnimation = povSettings.isPresent() && povSettings.get().cameraTransform() != null; - - // Activate pov animation - if (hasPrevCameraAnimation || hasNextCameraAnimation) { - if (hasPrevCameraAnimation) { - this.linkCameraTransform.getKeyframes()[0].transform().copyFrom(LocalPlayerPatch.this.povSettings.cameraTransform().getInterpolatedTransform(this.animationPlayer.getElapsedTime())); - } else { - this.linkCameraTransform.getKeyframes()[0].transform().copyFrom(JointTransform.empty()); - } - - if (hasNextCameraAnimation) { - this.linkCameraTransform.getKeyframes()[1].transform().copyFrom(povSettings.get().cameraTransform().getKeyframes()[0].transform()); - } else { - this.linkCameraTransform.getKeyframes()[1].transform().clearTransform(); - } - - this.linkCameraTransform.getKeyframes()[1].setTime(nextFirstPersonAnimation.get().getTransitionTime()); - } - - super.playAnimation(nextFirstPersonAnimation, entitypatch, transitionTimeModifier); - } - - public void off() { - // Off camera animation - if (LocalPlayerPatch.this.povSettings != null && LocalPlayerPatch.this.povSettings.cameraTransform() != null) { - this.linkCameraTransform.getKeyframes()[0].transform().copyFrom(LocalPlayerPatch.this.povSettings.cameraTransform().getInterpolatedTransform(this.animationPlayer.getElapsedTime())); - this.linkCameraTransform.getKeyframes()[1].transform().copyFrom(JointTransform.empty()); - this.linkCameraTransform.getKeyframes()[1].setTime(TiedUpRigConstants.GENERAL_ANIMATION_TRANSITION_TIME); - } - - super.off(LocalPlayerPatch.this); - } - - @Override - protected Pose getCurrentPose(LivingEntityPatch entitypatch) { - return this.animationPlayer.isEmpty() ? super.getCurrentPose(entitypatch) : this.animationPlayer.getCurrentPose(entitypatch, 0.0F); - } - - public TransformSheet getLinkCameraTransform() { - return this.linkCameraTransform; - } - } - - /** - * @deprecated Use {@link EpicFightCameraAPI#isLockingOnTarget()} instead - */ - @Deprecated(forRemoval = true) - public boolean isTargetLockedOn() { - return EpicFightCameraAPI.getInstance().isLockingOnTarget(); - } - - /** - * @deprecated Use {@link EpicFightCameraAPI#setLockOn(boolean)} instead - */ - @Deprecated(forRemoval = true) - public void setLockOn(boolean targetLockedOn) { - EpicFightCameraAPI.getInstance().setLockOn(targetLockedOn); - } - - /** - * @deprecated Use {@link EpicFightCameraAPI#toggleLockOn()} instead - */ - @Deprecated(forRemoval = true) - public void toggleLockOn() { - this.setLockOn(!EpicFightCameraAPI.getInstance().isLockingOnTarget()); - } -} diff --git a/src/main/java/com/tiedup/remake/rig/patch/MobPatch.java b/src/main/java/com/tiedup/remake/rig/patch/MobPatch.java new file mode 100644 index 0000000..3e53a40 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/patch/MobPatch.java @@ -0,0 +1,17 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.patch; + +import net.minecraft.world.entity.Mob; + +/** + * Stub RIG Phase 0 — patch générique pour {@link Mob} (NPCs). Utilisé par + * {@code instanceof MobPatch} dans les YRotProvider pour rediriger la tête + * et stopper la navigation pendant une animation. Version complète Phase 2. + */ +public abstract class MobPatch extends LivingEntityPatch { +} diff --git a/src/main/java/com/tiedup/remake/rig/patch/item/CapabilityItem.java b/src/main/java/com/tiedup/remake/rig/patch/item/CapabilityItem.java new file mode 100644 index 0000000..b6afc71 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/patch/item/CapabilityItem.java @@ -0,0 +1,15 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.patch.item; + +/** + * Stub RIG Phase 0 — capability item (côté combat EF). Ne sert ici que de type + * pour ON_ITEM_CHANGE_EVENT ; logique métier à re-implémenter Phase 3 si + * besoin (probablement via ItemStack + AnimationSet directement). + */ +public class CapabilityItem { +} diff --git a/src/main/java/com/tiedup/remake/rig/physics/PhysicsSimulator.java b/src/main/java/com/tiedup/remake/rig/physics/PhysicsSimulator.java new file mode 100644 index 0000000..8abcea9 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/physics/PhysicsSimulator.java @@ -0,0 +1,28 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.physics; + +import java.util.Optional; +import java.util.function.BooleanSupplier; + +import com.tiedup.remake.rig.physics.SimulationObject.SimulationObjectBuilder; + +public interface PhysicsSimulator, O, T extends SimulationObject> { + public void tick(O object); + + public boolean isRunning(KEY key); + + public void runUntil(KEY key, PV provider, B builder, BooleanSupplier when); + + public void runWhen(KEY key, PV provider, B builder, BooleanSupplier when); + + public void restart(KEY key); + + public void stop(KEY key); + + public Optional getRunningObject(KEY key); +} diff --git a/src/main/java/com/tiedup/remake/rig/physics/SimulatableObject.java b/src/main/java/com/tiedup/remake/rig/physics/SimulatableObject.java new file mode 100644 index 0000000..a003b37 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/physics/SimulatableObject.java @@ -0,0 +1,13 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.physics; + +import java.util.Optional; + +public interface SimulatableObject { + > Optional getSimulator(SimulationTypes simulationType); +} diff --git a/src/main/java/com/tiedup/remake/rig/physics/SimulationObject.java b/src/main/java/com/tiedup/remake/rig/physics/SimulationObject.java new file mode 100644 index 0000000..57ca3e9 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/physics/SimulationObject.java @@ -0,0 +1,17 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.physics; + +import com.tiedup.remake.rig.physics.SimulationObject.SimulationObjectBuilder; + +public interface SimulationObject, O> { + /** + * An abstract method to specify the parameters needed to build SimulationObject + */ + public abstract class SimulationObjectBuilder { + } +} \ No newline at end of file diff --git a/src/main/java/com/tiedup/remake/rig/physics/SimulationProvider.java b/src/main/java/com/tiedup/remake/rig/physics/SimulationProvider.java new file mode 100644 index 0000000..adc70ae --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/physics/SimulationProvider.java @@ -0,0 +1,15 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.physics; + +import javax.annotation.Nullable; + +import com.tiedup.remake.rig.physics.SimulationObject.SimulationObjectBuilder; + +public interface SimulationProvider, BUILDER extends SimulationObjectBuilder, P extends SimulationProvider> { + public OBJ createSimulationData(@Nullable P provider, OWN simOwner, BUILDER simBuilder); +} \ No newline at end of file diff --git a/src/main/java/com/tiedup/remake/rig/physics/SimulationTypes.java b/src/main/java/com/tiedup/remake/rig/physics/SimulationTypes.java new file mode 100644 index 0000000..0a6fe9f --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/physics/SimulationTypes.java @@ -0,0 +1,24 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.physics; + +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import com.tiedup.remake.rig.armature.Joint; +import com.tiedup.remake.rig.mesh.SoftBodyTranslatable; +import com.tiedup.remake.rig.cloth.ClothSimulatable; +import com.tiedup.remake.rig.cloth.ClothSimulator; +import com.tiedup.remake.rig.physics.ik.InverseKinematicsProvider; +import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulatable; +import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator; + +public interface SimulationTypes, B extends SimulationObject.SimulationObjectBuilder, DATA extends SimulationObject, SIM extends PhysicsSimulator> { + @OnlyIn(Dist.CLIENT) + public static final SimulationTypes CLOTH = new SimulationTypes<> () {}; + public static final SimulationTypes INVERSE_KINEMATICS = new SimulationTypes<> () {}; +} \ No newline at end of file diff --git a/src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsProvider.java b/src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsProvider.java new file mode 100644 index 0000000..b5f1e9e --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsProvider.java @@ -0,0 +1,35 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.physics.ik; + +import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator.InverseKinematicsBuilder; +import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator.InverseKinematicsObject; + +/** + * RIG stub. Upstream EF : interface implémentée par les providers + * d'inverse kinematics pour attacher une IK chain à une animation + * (typiquement pour forcer les mains à rester sur la poignée d'arme + * pendant une attaque, ou les pieds au sol pendant un coup de pied). + * + *

Non utilisé en TiedUp (pas de combat, pas de weapon IK). + * Conservé comme interface vide pour que {@code StaticAnimation + * implements InverseKinematicsProvider} compile.

+ */ +public interface InverseKinematicsProvider { + + /** + * Crée les données de simulation IK. Stub par défaut : no-op. + * Surchargé dans les classes qui auraient réellement de l'IK (aucune + * en TiedUp). + */ + default InverseKinematicsObject createSimulationData( + InverseKinematicsProvider provider, + InverseKinematicsSimulatable simOwner, + InverseKinematicsBuilder simBuilder) { + return new InverseKinematicsObject(simBuilder); + } +} diff --git a/src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsSimulatable.java b/src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsSimulatable.java new file mode 100644 index 0000000..475113b --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsSimulatable.java @@ -0,0 +1,15 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.physics.ik; + +/** + * RIG stub. Upstream EF : marker interface pour les entities/patches qui + * peuvent porter une simulation IK. Non utilisé en TiedUp — stub vide + * pour satisfaire les {@code instanceof} dans StaticAnimation. + */ +public interface InverseKinematicsSimulatable { +} diff --git a/src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsSimulator.java b/src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsSimulator.java new file mode 100644 index 0000000..9f16716 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/physics/ik/InverseKinematicsSimulator.java @@ -0,0 +1,47 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.physics.ik; + +/** + * RIG stub. Upstream EF : simulateur d'inverse kinematics (solveur CCD + * ou FABRIK) utilisé pour attacher des membres à des points cibles + * pendant les animations d'attaque combat. Non utilisé en TiedUp. + * + *

Conservé comme shell vide pour que les imports StaticAnimation + + * AnimationProperty compilent. Les nested types sont des stubs sans + * logique.

+ */ +public class InverseKinematicsSimulator { + + public static class InverseKinematicsObject { + public InverseKinematicsObject(InverseKinematicsBuilder builder) { + // no-op + } + } + + public static class InverseKinematicsBuilder { + // no-op stub + } + + /** + * Définition d'une chaîne IK (armature joint + cible). Stub avec + * juste la méthode {@code bake()} appelée par StaticAnimation. + */ + public static class InverseKinematicsDefinition { + public BakedInverseKinematicsDefinition bake( + Object armature, + Object jointTransforms, + float correctY, + float correctZ) { + return new BakedInverseKinematicsDefinition(); + } + } + + public static class BakedInverseKinematicsDefinition { + // no-op stub + } +} diff --git a/src/main/java/com/tiedup/remake/rig/render/compute/ComputeShaderProvider.java b/src/main/java/com/tiedup/remake/rig/render/compute/ComputeShaderProvider.java new file mode 100644 index 0000000..61b69ca --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/render/compute/ComputeShaderProvider.java @@ -0,0 +1,27 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.render.compute; + +/** + * RIG stub. Upstream EF : registry des ComputeShaderSetup par mesh. + * Non utilisé en TiedUp Phase 0 — classe vide pour satisfaire les refs + * dans SkinnedMesh. + */ +public final class ComputeShaderProvider { + + private ComputeShaderProvider() {} + + /** Stub no-op : retourne toujours null → chemin CPU skinning. */ + public static ComputeShaderSetup getComputeShaderSetup(Object key) { + return null; + } + + /** Stub no-op pour Iris init (référence pour IRISCompat éventuel). */ + public static void initIris() { + // no-op Phase 0 + } +} diff --git a/src/main/java/com/tiedup/remake/rig/render/compute/ComputeShaderSetup.java b/src/main/java/com/tiedup/remake/rig/render/compute/ComputeShaderSetup.java new file mode 100644 index 0000000..b81a002 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/render/compute/ComputeShaderSetup.java @@ -0,0 +1,43 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.render.compute; + +import com.mojang.blaze3d.vertex.PoseStack; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import com.tiedup.remake.rig.mesh.Mesh; +import com.tiedup.remake.rig.armature.Armature; +import com.tiedup.remake.rig.math.OpenMatrix4f; + +/** + * RIG stub. Upstream EF : ComputeShaderSetup = binding OpenGL 4.3+ compute + * shader pour le GPU skinning. Non utilisé en TiedUp Phase 0 (CPU skinning + * via VertexConsumer suffit). Classe vide, référencée par SkinnedMesh pour + * le chemin GPU optionnel. + * + *

Réactivation future (hors scope V1) : réintroduire l'implémentation + * complète EF + gérer IrisComputeShaderSetup pour compat shader packs.

+ */ +public abstract class ComputeShaderSetup { + + /** No-op stub : le chemin GPU compute n'est jamais emprunté. */ + public void drawWithShader( + Object mesh, + PoseStack poseStack, + MultiBufferSource bufferSources, + RenderType renderType, + int packedLight, + float r, float g, float b, float a, + int overlay, + Armature armature, + OpenMatrix4f[] poses) { + // no-op — le renderer bascule sur le CPU path si ComputeShaderSetup + // est null sur le mesh. Cette implémentation ne devrait jamais être + // appelée (SkinnedMesh.computerShaderSetup = null par défaut). + } +} diff --git a/src/main/java/com/tiedup/remake/rig/util/ExtendableEnum.java b/src/main/java/com/tiedup/remake/rig/util/ExtendableEnum.java new file mode 100644 index 0000000..45c5a5a --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/util/ExtendableEnum.java @@ -0,0 +1,11 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.util; + +public interface ExtendableEnum { + int universalOrdinal(); +} diff --git a/src/main/java/com/tiedup/remake/rig/util/ExtendableEnumManager.java b/src/main/java/com/tiedup/remake/rig/util/ExtendableEnumManager.java new file mode 100644 index 0000000..0473888 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/util/ExtendableEnumManager.java @@ -0,0 +1,116 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; + +import com.google.common.collect.Maps; + +import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import net.minecraft.network.chat.Component; + +import com.tiedup.remake.rig.TiedUpRigConstants; + +public class ExtendableEnumManager { + private final Int2ObjectMap enumMapByOrdinal = new Int2ObjectLinkedOpenHashMap<>(); + private final Map enumMapByName = Maps.newLinkedHashMap(); + private final Map> enums = Maps.newConcurrentMap(); + private final String enumName; + private int lastOrdinal = 0; + + public ExtendableEnumManager(String enumName) { + this.enumName = enumName; + } + + public void registerEnumCls(String modid, Class cls) { + if (this.enums.containsKey(modid)) { + TiedUpRigConstants.LOGGER.error(modid + " is already registered in " + this.enumName); + } + TiedUpRigConstants.LOGGER.debug("Registered Extendable Enum " + cls + " in " + this.enumName); + this.enums.put(modid, cls); + } + + public void loadEnum() { + List orderByModid = new ArrayList<>(this.enums.keySet()); + Collections.sort(orderByModid); + Class cls = null; + + try { + for (String modid : orderByModid) { + cls = this.enums.get(modid); + Method m = cls.getMethod("values"); + m.invoke(null); + TiedUpRigConstants.LOGGER.debug("Loaded enums in " + cls); + } + } catch (ClassCastException e) { + TiedUpRigConstants.LOGGER.error(cls.getCanonicalName() + " is not an ExtendableEnum!"); + e.printStackTrace(); + } catch (NoSuchMethodException e) { + TiedUpRigConstants.LOGGER.error(cls.getCanonicalName() + " is not an Enum class!"); + e.printStackTrace(); + } catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + TiedUpRigConstants.LOGGER.warn("Error while loading extendable enum " + cls.getCanonicalName()); + e.printStackTrace(); + } + + TiedUpRigConstants.LOGGER.debug("All enums are loaded: " + this.enumName + " " + this.enumMapByName.values()); + } + + public int assign(T value) { + int lastOrdinal = this.lastOrdinal; + String enumName = ParseUtil.toLowerCase(value.toString()); + + if (this.enumMapByName.containsKey(enumName)) { + throw new IllegalArgumentException("Enum name " + enumName + " already exists in " + this.enumName); + } + + this.enumMapByOrdinal.put(lastOrdinal, value); + this.enumMapByName.put(enumName, value); + ++this.lastOrdinal; + + return lastOrdinal; + } + + public T getOrThrow(int id) throws NoSuchElementException { + if (!this.enumMapByOrdinal.containsKey(id)) { + throw new NoSuchElementException("Enum id " + id + " does not exist in " + this.enumName); + } + return this.enumMapByOrdinal.get(id); + } + + public T getOrThrow(String name) throws NoSuchElementException { + String key = ParseUtil.toLowerCase(name); + if (!this.enumMapByName.containsKey(key)) { + throw new NoSuchElementException("Enum name " + key + " does not exist in " + this.enumName); + } + return this.enumMapByName.get(key); + } + + public T get(int id) { + return this.enumMapByOrdinal.get(id); + } + + public T get(String name) { + return this.enumMapByName.get(ParseUtil.toLowerCase(name)); + } + + public Collection universalValues() { + return this.enumMapByOrdinal.values(); + } + + public String toTranslated(ExtendableEnum e) { + return Component.translatable(TiedUpRigConstants.MODID + "." + this.enumName + "." + ParseUtil.toLowerCase(e.toString())).getString(); + } +} diff --git a/src/main/java/com/tiedup/remake/rig/util/HitEntityList.java b/src/main/java/com/tiedup/remake/rig/util/HitEntityList.java new file mode 100644 index 0000000..591f9a8 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/util/HitEntityList.java @@ -0,0 +1,19 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.util; + +/** + * Stub RIG Phase 0 — utilisé uniquement pour exposer {@link Priority} au + * type {@code AttackPhaseProperty HIT_PRIORITY}. Logique combat + * (ordonner les entités touchées par une attack animation) non portée. + */ +public class HitEntityList { + + public enum Priority { + DISTANCE, TARGET; + } +} diff --git a/src/main/java/com/tiedup/remake/rig/util/InstantiateInvoker.java b/src/main/java/com/tiedup/remake/rig/util/InstantiateInvoker.java new file mode 100644 index 0000000..aba2f97 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/util/InstantiateInvoker.java @@ -0,0 +1,254 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.util; + +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import javax.annotation.Nullable; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import net.minecraft.world.InteractionHand; +import com.tiedup.remake.rig.armature.Joint; +import com.tiedup.remake.rig.asset.AssetAccessor; +import com.tiedup.remake.rig.exception.AnimationInvokeException; +import com.tiedup.remake.rig.armature.Armature; + +public class InstantiateInvoker { + private static final BiMap> PRIMITIVE_KEYWORDS = HashBiMap.create(); + private static final BiMap, Class> RETURN_TYPE_MAPPER = HashBiMap.create(); + private static final Map, Function> STRING_TO_OBJECT_PARSER = Maps.newHashMap(); + + static { + registerPrimitive("B", byte.class, Byte::parseByte); + registerPrimitive("C", char.class, (s) -> s.charAt(0)); + registerPrimitive("D", double.class, Double::parseDouble); + registerPrimitive("F", float.class, Float::parseFloat); + registerPrimitive("I", int.class, Integer::parseInt); + registerPrimitive("J", long.class, Long::parseLong); + registerPrimitive("S", short.class, Short::parseShort); + registerPrimitive("Z", boolean.class, Boolean::parseBoolean); + + registerReturnTypeMapper(Armature.class, AssetAccessor.class); + + registerKeyword(String.class, (s) -> s); + // RIG : Collider.class (combat) + ColliderPreset strippés — re-implem Phase 2 + // si besoin pour les hitboxes de menottes. Joint/Armature stubbés le temps + // que TiedUpRigRegistry expose un armature registry (Phase 2). + registerKeyword(Joint.class, (s) -> { + String[] armature$joint = s.split("\\."); + AssetAccessor armature = getArmature(armature$joint[0]); + return armature.get().searchJointByName(armature$joint[1]); + }); + registerKeyword(Armature.class, (s) -> getArmature(s)); + registerKeyword(InteractionHand.class, InteractionHand::valueOf); + } + + private static AssetAccessor getArmature(String id) { + throw new AnimationInvokeException("Armature registry not yet implemented — Phase 2 (lookup for '" + id + "')"); + } + + public static void registerPrimitive(String keyword, Class clz, Function decoder) { + PRIMITIVE_KEYWORDS.put(keyword, clz); + STRING_TO_OBJECT_PARSER.put(clz, decoder); + } + + public static void registerReturnTypeMapper(Class clz, Class returnClz) { + RETURN_TYPE_MAPPER.put(clz, returnClz); + } + + public static void registerKeyword(Class clz, Function decoder) { + STRING_TO_OBJECT_PARSER.put(clz, decoder); + } + + @SuppressWarnings("unchecked") + public static Result invoke(String invocationCommand, @Nullable Class hint) throws Exception { + if (invocationCommand.matches("\\(.+\\)") || invocationCommand.matches("\\(.+\\)\\#.+")) { // invoke instance + return (Result)invokeInstance(invocationCommand, hint); + } else if (invocationCommand.matches("\\[.+\\]") || invocationCommand.matches("\\[.+\\]\\#.+")) { // invoke array + return (Result)invokeArray(invocationCommand, hint); + } else { + String[] param = splitExceptWrapper(invocationCommand, '#', true); + String sValue = param[0]; + String sType = param[1]; + + if ("IMeshRenderBoost".equals(sType)) { + sType = "I"; // Bad Implementation: I > IMeshRenderBoost is caused by replace all but kept to preserve backward compatibility + } + + if (PRIMITIVE_KEYWORDS.containsKey(sType)) { + Class type = (Class)PRIMITIVE_KEYWORDS.get(sType); + return Result.of(type, (T)STRING_TO_OBJECT_PARSER.get(type).apply(sValue)); + } + + Class type = (Class)Class.forName(sType); + + if (STRING_TO_OBJECT_PARSER.containsKey(type)) { + if (RETURN_TYPE_MAPPER.containsKey(type)) { + return Result.of((Class)RETURN_TYPE_MAPPER.get(type), (T)STRING_TO_OBJECT_PARSER.get(type).apply(sValue)); + } + + return Result.of(type, (T)STRING_TO_OBJECT_PARSER.get(type).apply(sValue)); + } + + throw new AnimationInvokeException("Can't find the matching type for the command " + invocationCommand); + } + } + + /** + * @param hint has a higher priority than class specified in invocation command + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static Result invokeInstance(String invocationCommand, @Nullable Class hint) throws Exception { + if (!invocationCommand.matches("\\(.+\\)") && !invocationCommand.matches("\\(.+\\)\\#.+")) { + throw new IllegalStateException("Invalid instantiate invocation command: " + invocationCommand); + } + + String[] param$type = splitExceptWrapper(invocationCommand, '#', true); + String sParams = param$type[0]; + Class type = param$type.length > 1 ? Class.forName(param$type[1]) : hint; + + if (type == null) { + throw new AnimationInvokeException("Can't find the type in command " + invocationCommand); + } + + String[] params = splitExceptWrapper(sParams, ',', false); + Object[] oArgs = new Object[params.length]; + Class[] oArgClss = new Class[params.length]; + + for (int i = 0; i < params.length; i++) { + Result result = invoke(params[i], null); + oArgs[i] = result.result; + oArgClss[i] = result.type; + + for (Class reservedClass : STRING_TO_OBJECT_PARSER.keySet()) { + if (!result.type.equals(reservedClass) && reservedClass.isAssignableFrom(result.type)) { + oArgClss[i] = reservedClass; + } + } + } + + Constructor constructor = null; + + try { + if (hint == null) { + throw new NoSuchMethodException(); + } + + constructor = hint.getConstructor(oArgClss); + } catch (NoSuchMethodException e) { + //EpicFightMod.LOGGER.debug("Can't find the matching constructor for the hint class " + hint + ". Use the given class " + type); + constructor = type.getConstructor(oArgClss); + } + + return Result.of((Class)type, (T)constructor.newInstance(oArgs)); + } + + /** + * @param hint has a higher priority than class specified in invocation command + */ + @SuppressWarnings("unchecked") + public static Result invokeArray(String invocationCommand, @Nullable Class hint) throws Exception { + if (!invocationCommand.matches("\\[.+\\]") && !invocationCommand.matches("\\[.+\\]\\#.+")) { + throw new AnimationInvokeException("Invalid array invocation command: " + invocationCommand); + } + + String[] param$type = splitExceptWrapper(invocationCommand, '#', true); + String sParams = param$type[0]; + Class type = param$type.length > 1 ? Class.forName(param$type[1]) : hint; + + if (type == null) { + throw new AnimationInvokeException("Can't find the type in command " + invocationCommand); + } + + String[] params = splitExceptWrapper(sParams, ',', false); + List resultArray = Lists.newArrayList(); + T[] result = (T[]) Array.newInstance(type, params.length); + + for (int i = 0; i < params.length; i++) { + T obj = (T)invoke(params[i], type).result; + + if (obj.getClass() != type) { + throw new AnimationInvokeException("Heterogeneous array elements for the command " + invocationCommand); + } + + resultArray.add(obj); + result[i] = obj; + } + + return Result.of((Class)type.arrayType(), resultArray.toArray(result)); + } + + private static String[] splitExceptWrapper(String sArgs, char keyword, boolean skipWrapper) { + List sArgsList = Lists.newArrayList(); + + int arrayNestCounter = 0; + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < sArgs.length(); i++) { + char c = sArgs.charAt(i); + + if (c == keyword) { + if (arrayNestCounter < 1) { + sArgsList.add(sb.toString()); + sb.setLength(0); + } else { + sb.append(c); + } + } else if (c == '[' || c == '(') { + if (!skipWrapper || arrayNestCounter > 0) { + sb.append(c); + } + + arrayNestCounter++; + } else if (c == ']' || c == ')') { + arrayNestCounter--; + + if (!skipWrapper || arrayNestCounter > 0) { + sb.append(c); + } + } else { + sb.append(c); + } + } + + if (!sb.isEmpty()) { + sArgsList.add(sb.toString()); + } + + return sArgsList.toArray(new String[0]); + } + + public static class Result { + final Class type; + final T result; + + Result(Class type, T result) { + this.type = type; + this.result = result; + } + + public static Result of(Class type, T value) { + return new Result<>(type, value); + } + + public Class getType() { + return this.type; + } + + public T getResult() { + return this.result; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/tiedup/remake/rig/util/MutableBoolean.java b/src/main/java/com/tiedup/remake/rig/util/MutableBoolean.java new file mode 100644 index 0000000..740cec4 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/util/MutableBoolean.java @@ -0,0 +1,48 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.util; + +import org.apache.commons.lang3.BooleanUtils; + +public class MutableBoolean implements Comparable { + boolean val; + + public MutableBoolean() { + this(false); + } + + public MutableBoolean(boolean init) { + this.val = init; + } + + public boolean value() { + return this.val; + } + + public void set(boolean val) { + this.val = val; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof MutableBoolean) { + return this.val == ((MutableBoolean)obj).val; + } + + return false; + } + + @Override + public int hashCode() { + return this.val ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode(); + } + + @Override + public int compareTo(final MutableBoolean other) { + return BooleanUtils.compare(this.val, other.val); + } +} diff --git a/src/main/java/com/tiedup/remake/rig/util/PacketBufferCodec.java b/src/main/java/com/tiedup/remake/rig/util/PacketBufferCodec.java new file mode 100644 index 0000000..b05c381 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/util/PacketBufferCodec.java @@ -0,0 +1,78 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.util; + +import net.minecraft.core.Registry; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.phys.Vec3; + +import com.tiedup.remake.rig.math.Vec3f; + +/** + * Backport de StreamCodec (MC 1.21.1) — encode/decode pour FriendlyByteBuf. + * Forké depuis EF, identique. + */ +public interface PacketBufferCodec { + void encode(T obj, FriendlyByteBuf buffer); + + T decode(FriendlyByteBuf buffer); + + public static final PacketBufferCodec BOOLEAN = new PacketBufferCodec<>() { + @Override public void encode(Boolean obj, FriendlyByteBuf buffer) { buffer.writeBoolean(obj); } + @Override public Boolean decode(FriendlyByteBuf buffer) { return buffer.readBoolean(); } + }; + + public static final PacketBufferCodec INTEGER = new PacketBufferCodec<>() { + @Override public void encode(Integer obj, FriendlyByteBuf buffer) { buffer.writeInt(obj); } + @Override public Integer decode(FriendlyByteBuf buffer) { return buffer.readInt(); } + }; + + public static final PacketBufferCodec FLOAT = new PacketBufferCodec<>() { + @Override public void encode(Float obj, FriendlyByteBuf buffer) { buffer.writeFloat(obj); } + @Override public Float decode(FriendlyByteBuf buffer) { return buffer.readFloat(); } + }; + + public static final PacketBufferCodec DOUBLE = new PacketBufferCodec<>() { + @Override public void encode(Double obj, FriendlyByteBuf buffer) { buffer.writeDouble(obj); } + @Override public Double decode(FriendlyByteBuf buffer) { return buffer.readDouble(); } + }; + + public static final PacketBufferCodec VEC3 = new PacketBufferCodec<>() { + @Override public void encode(Vec3 obj, FriendlyByteBuf buffer) { + buffer.writeDouble(obj.x); buffer.writeDouble(obj.y); buffer.writeDouble(obj.z); + } + @Override public Vec3 decode(FriendlyByteBuf buffer) { + return new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); + } + }; + + public static final PacketBufferCodec VEC3F = new PacketBufferCodec<>() { + @Override public void encode(Vec3f obj, FriendlyByteBuf buffer) { + buffer.writeFloat(obj.x); buffer.writeFloat(obj.y); buffer.writeFloat(obj.z); + } + @Override public Vec3f decode(FriendlyByteBuf buffer) { + return new Vec3f(buffer.readFloat(), buffer.readFloat(), buffer.readFloat()); + } + }; + + public static PacketBufferCodec> tagKey(ResourceKey> registry) { + return new PacketBufferCodec<>() { + @Override public void encode(TagKey tagKey, FriendlyByteBuf buffer) { + buffer.writeResourceLocation(tagKey.registry().location()); + buffer.writeResourceLocation(tagKey.location()); + } + @Override public TagKey decode(FriendlyByteBuf buffer) { + ResourceLocation reg = buffer.readResourceLocation(); + ResourceLocation tagName = buffer.readResourceLocation(); + return TagKey.create(ResourceKey.createRegistryKey(reg), tagName); + } + }; + } +} diff --git a/src/main/java/com/tiedup/remake/rig/util/TimePairList.java b/src/main/java/com/tiedup/remake/rig/util/TimePairList.java new file mode 100644 index 0000000..eb37c83 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/util/TimePairList.java @@ -0,0 +1,49 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.util; + +public class TimePairList { + private final TimePair[] timePairs; + + private TimePairList(TimePair[] timePairs) { + this.timePairs = timePairs; + } + + public boolean isTimeInPairs(float time) { + for (TimePair timePair : this.timePairs) { + if (timePair.isTimeIn(time)) { + return true; + } + } + return false; + } + + private static class TimePair { + public final float begin; + public final float end; + + private TimePair(float begin, float end) { + this.begin = begin; + this.end = end; + } + + private boolean isTimeIn(float time) { + return time >= this.begin && time < end; + } + } + + public static TimePairList create(float... times) { + if (times.length % 2 != 0) { + throw new IllegalArgumentException("Time pair exception : number of given times is not an even number"); + } + TimePair[] timePairs = new TimePair[times.length / 2]; + for (int i = 0; i < times.length / 2; i++) { + timePairs[i] = new TimePair(times[i * 2], times[i * 2 + 1]); + } + return new TimePairList(timePairs); + } +}