WIP: fork patch/collider/codec stubs, 464->135 compile errors
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<T> abstract — getOriginal, isLogicalClient, getMatrix, getAngleTo
- LivingEntityPatch<T> abstract — getAnimator, getArmature, getTarget, getYRot*
- MobPatch<T extends Mob> — 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)
This commit is contained in:
@@ -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.AssetAccessor;
|
||||||
import com.tiedup.remake.rig.asset.JsonAssetLoader;
|
import com.tiedup.remake.rig.asset.JsonAssetLoader;
|
||||||
import com.tiedup.remake.rig.anim.client.AnimationSubFileReader;
|
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.exception.AssetLoadingException;
|
||||||
import com.tiedup.remake.rig.util.InstantiateInvoker;
|
import com.tiedup.remake.rig.util.InstantiateInvoker;
|
||||||
import com.tiedup.remake.rig.util.MutableBoolean;
|
import com.tiedup.remake.rig.util.MutableBoolean;
|
||||||
import com.tiedup.remake.rig.TiedUpRigRegistry;
|
import com.tiedup.remake.rig.TiedUpRigRegistry;
|
||||||
import com.tiedup.remake.rig.TiedUpRigConstants;
|
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")
|
@SuppressWarnings("unchecked")
|
||||||
public class AnimationManager extends SimplePreparableReloadListener<List<ResourceLocation>> {
|
public class AnimationManager extends SimplePreparableReloadListener<List<ResourceLocation>> {
|
||||||
@@ -212,7 +208,7 @@ public class AnimationManager extends SimplePreparableReloadListener<List<Resour
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
SkillManager.reloadAllSkillsAnimations();
|
// RIG : SkillManager.reloadAllSkillsAnimations() strippé (combat skills).
|
||||||
|
|
||||||
this.animations.entrySet().stream()
|
this.animations.entrySet().stream()
|
||||||
.reduce(
|
.reduce(
|
||||||
@@ -301,88 +297,13 @@ public class AnimationManager extends SimplePreparableReloadListener<List<Resour
|
|||||||
* custom weapon types & mob capabilities won't be created because they won't be able to find the animations from the server
|
* custom weapon types & mob capabilities won't be created because they won't be able to find the animations from the server
|
||||||
* dummy animations will be automatically removed right after reloading resourced as the server forces using resource pack
|
* dummy animations will be automatically removed right after reloading resourced as the server forces using resource pack
|
||||||
*/
|
*/
|
||||||
@OnlyIn(Dist.CLIENT)
|
// RIG : processServerPacket + validateClientAnimationRegistry strippés.
|
||||||
public void processServerPacket(SPDatapackSync packet, boolean mandatoryPack) {
|
// C'était le protocole datapack-sync EF pour valider que le client a les
|
||||||
if (mandatoryPack) {
|
// mêmes animations que le serveur au login (important pour les animations
|
||||||
for (CompoundTag tag : packet.getTags()) {
|
// combat stockées en data/). TiedUp utilise resource pack uniquement
|
||||||
String invocationCommand = tag.getString("invoke_command");
|
// (assets/) côté client, pas de sync datapack nécessaire.
|
||||||
ResourceLocation registryName = ResourceLocation.parse(tag.getString("registry_name"));
|
// Ré-introduire Phase 2+ si on veut un warning quand un pack d'animations
|
||||||
int id = tag.getInt("id");
|
// custom diverge.
|
||||||
|
|
||||||
if (this.animationByName.containsKey(registryName)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationAccessor<? extends StaticAnimation> 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<String> 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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Set<String> NO_WARNING_MODID = Sets.newHashSet();
|
private static final Set<String> NO_WARNING_MODID = Sets.newHashSet();
|
||||||
|
|
||||||
|
|||||||
@@ -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).
|
||||||
|
*
|
||||||
|
* <p>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}).</p>
|
||||||
|
*
|
||||||
|
* <p>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.</p>
|
||||||
|
*/
|
||||||
|
public class AnimationVariablePacket {
|
||||||
|
|
||||||
|
public enum Action {
|
||||||
|
PUT,
|
||||||
|
REMOVE,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
import com.tiedup.remake.rig.util.datastruct.TypeFlexibleHashMap.TypeKey;
|
import com.tiedup.remake.rig.util.datastruct.TypeFlexibleHashMap.TypeKey;
|
||||||
import com.tiedup.remake.rig.TiedUpRigRegistry;
|
import com.tiedup.remake.rig.TiedUpRigRegistry;
|
||||||
import yesman.epicfight.network.common.AnimationVariablePacket;
|
import com.tiedup.remake.rig.anim.AnimationVariablePacket;
|
||||||
|
|
||||||
public class AnimationVariables {
|
public class AnimationVariables {
|
||||||
protected final Animator animator;
|
protected final Animator animator;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
package com.tiedup.remake.rig.anim;
|
package com.tiedup.remake.rig.anim;
|
||||||
|
|
||||||
|
import com.tiedup.remake.rig.armature.JointTransform;
|
||||||
|
|
||||||
public class Keyframe {
|
public class Keyframe {
|
||||||
private float timeStamp;
|
private float timeStamp;
|
||||||
private final JointTransform transform;
|
private final JointTransform transform;
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import java.util.function.BiConsumer;
|
|||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import com.tiedup.remake.rig.armature.JointTransform;
|
||||||
|
|
||||||
public class Pose {
|
public class Pose {
|
||||||
public static final Pose EMPTY_POSE = new Pose();
|
public static final Pose EMPTY_POSE = new Pose();
|
||||||
|
|
||||||
|
|||||||
@@ -22,10 +22,9 @@ import com.tiedup.remake.rig.asset.AssetAccessor;
|
|||||||
import com.tiedup.remake.rig.util.PacketBufferCodec;
|
import com.tiedup.remake.rig.util.PacketBufferCodec;
|
||||||
import com.tiedup.remake.rig.util.datastruct.ClearableIdMapper;
|
import com.tiedup.remake.rig.util.datastruct.ClearableIdMapper;
|
||||||
import com.tiedup.remake.rig.TiedUpRigConstants;
|
import com.tiedup.remake.rig.TiedUpRigConstants;
|
||||||
import yesman.epicfight.network.EpicFightNetworkManager;
|
import com.tiedup.remake.rig.anim.AnimationVariablePacket;
|
||||||
import yesman.epicfight.network.client.CPAnimationVariablePacket;
|
import com.tiedup.remake.rig.anim.AnimationVariablePacket;
|
||||||
import yesman.epicfight.network.common.AnimationVariablePacket;
|
import com.tiedup.remake.rig.anim.AnimationVariablePacket;
|
||||||
import yesman.epicfight.network.server.SPAnimationVariablePacket;
|
|
||||||
import com.tiedup.remake.rig.patch.LivingEntityPatch;
|
import com.tiedup.remake.rig.patch.LivingEntityPatch;
|
||||||
|
|
||||||
public interface SynchedAnimationVariableKey<T> {
|
public interface SynchedAnimationVariableKey<T> {
|
||||||
@@ -83,11 +82,9 @@ public interface SynchedAnimationVariableKey<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default void sync(LivingEntityPatch<?> entitypatch, @Nullable AssetAccessor<? extends StaticAnimation> animation, T value, AnimationVariablePacket.Action action) {
|
default void sync(LivingEntityPatch<?> entitypatch, @Nullable AssetAccessor<? extends StaticAnimation> animation, T value, AnimationVariablePacket.Action action) {
|
||||||
if (entitypatch.isLogicalClient()) {
|
// RIG : sync réseau des animation variables strippé.
|
||||||
EpicFightNetworkManager.sendToServer(new CPAnimationVariablePacket<> (this, animation, value, action));
|
// Pas d'usage bondage identifié — ré-implémenter Phase 2 avec packet
|
||||||
} else {
|
// dédié si besoin. Voir AnimationVariablePacket stub.
|
||||||
entitypatch.sendToAllPlayersTrackingMe(new SPAnimationVariablePacket<> (entitypatch, this, animation, value, action));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SynchedSharedAnimationVariableKey<T> extends SharedAnimationVariableKey<T> implements SynchedAnimationVariableKey<T> {
|
public static class SynchedSharedAnimationVariableKey<T> extends SharedAnimationVariableKey<T> implements SynchedAnimationVariableKey<T> {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.joml.Quaternionf;
|
|||||||
|
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.phys.Vec3;
|
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.MathUtils;
|
||||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||||
import com.tiedup.remake.rig.math.Vec3f;
|
import com.tiedup.remake.rig.math.Vec3f;
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
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.util.datastruct.TypeFlexibleHashMap;
|
||||||
import com.tiedup.remake.rig.TiedUpRigRegistry;
|
import com.tiedup.remake.rig.TiedUpRigRegistry;
|
||||||
import com.tiedup.remake.rig.TiedUpRigConstants;
|
import com.tiedup.remake.rig.TiedUpRigConstants;
|
||||||
import yesman.epicfight.network.common.AnimatorControlPacket;
|
|
||||||
import com.tiedup.remake.rig.patch.LivingEntityPatch;
|
import com.tiedup.remake.rig.patch.LivingEntityPatch;
|
||||||
|
|
||||||
public class ClientAnimator extends Animator {
|
public class ClientAnimator extends Animator {
|
||||||
@@ -85,14 +83,10 @@ public class ClientAnimator extends Animator {
|
|||||||
layer.playAnimation(nextAnimation, this.entitypatch, transitionTimeModifier);
|
layer.playAnimation(nextAnimation, this.entitypatch, transitionTimeModifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Play an animation with specifying layer and priority **/
|
// RIG : playAnimationAt(..., AnimatorControlPacket.Layer, AnimatorControlPacket.Priority)
|
||||||
@ApiStatus.Internal
|
// strippé — re-implem Phase 2 avec packet dédié. Voir AnimationVariablePacket.
|
||||||
public void playAnimationAt(AssetAccessor<? extends StaticAnimation> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void playAnimationInstantly(AssetAccessor<? extends StaticAnimation> nextAnimation) {
|
public void playAnimationInstantly(AssetAccessor<? extends StaticAnimation> nextAnimation) {
|
||||||
Layer layer = nextAnimation.get().getLayerType() == Layer.LayerType.BASE_LAYER ? this.baseLayer : this.baseLayer.compositeLayers.get(nextAnimation.get().getPriority());
|
Layer layer = nextAnimation.get().getLayerType() == Layer.LayerType.BASE_LAYER ? this.baseLayer : this.baseLayer.compositeLayers.get(nextAnimation.get().getPriority());
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import net.minecraft.sounds.SoundEvent;
|
|||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.damagesource.DamageType;
|
import net.minecraft.world.damagesource.DamageType;
|
||||||
import net.minecraft.world.phys.Vec3;
|
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.AnimationManager.AnimationAccessor;
|
||||||
import com.tiedup.remake.rig.anim.LivingMotion;
|
import com.tiedup.remake.rig.anim.LivingMotion;
|
||||||
import com.tiedup.remake.rig.anim.Pose;
|
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.DynamicAnimation;
|
||||||
import com.tiedup.remake.rig.anim.types.LinkAnimation;
|
import com.tiedup.remake.rig.anim.types.LinkAnimation;
|
||||||
import com.tiedup.remake.rig.anim.types.StaticAnimation;
|
import com.tiedup.remake.rig.anim.types.StaticAnimation;
|
||||||
import yesman.epicfight.api.physics.ik.InverseKinematicsSimulator.BakedInverseKinematicsDefinition;
|
import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator.BakedInverseKinematicsDefinition;
|
||||||
import yesman.epicfight.api.physics.ik.InverseKinematicsSimulator.InverseKinematicsDefinition;
|
import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator.InverseKinematicsDefinition;
|
||||||
import com.tiedup.remake.rig.util.HitEntityList.Priority;
|
import com.tiedup.remake.rig.util.HitEntityList.Priority;
|
||||||
import com.tiedup.remake.rig.util.TimePairList;
|
import com.tiedup.remake.rig.util.TimePairList;
|
||||||
import com.tiedup.remake.rig.math.ValueModifier;
|
import com.tiedup.remake.rig.math.ValueModifier;
|
||||||
import com.tiedup.remake.rig.TiedUpRigConstants;
|
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.LivingEntityPatch;
|
||||||
import com.tiedup.remake.rig.patch.item.CapabilityItem;
|
import com.tiedup.remake.rig.patch.item.CapabilityItem;
|
||||||
import yesman.epicfight.world.damagesource.ExtraDamageInstance;
|
|
||||||
import yesman.epicfight.world.damagesource.StunType;
|
|
||||||
|
|
||||||
public abstract class AnimationProperty<T> {
|
public abstract class AnimationProperty<T> {
|
||||||
private static final Map<String, AnimationProperty<?>> SERIALIZABLE_ANIMATION_PROPERTY_KEYS = Maps.newHashMap();
|
private static final Map<String, AnimationProperty<?>> SERIALIZABLE_ANIMATION_PROPERTY_KEYS = Maps.newHashMap();
|
||||||
@@ -250,10 +245,11 @@ public abstract class AnimationProperty<T> {
|
|||||||
public static final ActionAnimationProperty<TimePairList> COORD_UPDATE_TIME = new ActionAnimationProperty<TimePairList> ();
|
public static final ActionAnimationProperty<TimePairList> COORD_UPDATE_TIME = new ActionAnimationProperty<TimePairList> ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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<Boolean> RESET_PLAYER_COMBO_COUNTER = new ActionAnimationProperty<Boolean> ("reset_combo_attack_counter", Codec.BOOL);
|
public static final ActionAnimationProperty<Boolean> RESET_PLAYER_COMBO_COUNTER = new ActionAnimationProperty<Boolean> ("reset_combo_attack_counter", Codec.BOOL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide destination of action animation {@link MoveCoordFunctions}
|
* Provide destination of action animation {@link MoveCoordFunctions}
|
||||||
*/
|
*/
|
||||||
@@ -333,11 +329,9 @@ public abstract class AnimationProperty<T> {
|
|||||||
public static final AttackPhaseProperty<ValueModifier> DAMAGE_MODIFIER = new AttackPhaseProperty<ValueModifier> ("damage", ValueModifier.CODEC);
|
public static final AttackPhaseProperty<ValueModifier> DAMAGE_MODIFIER = new AttackPhaseProperty<ValueModifier> ("damage", ValueModifier.CODEC);
|
||||||
public static final AttackPhaseProperty<ValueModifier> ARMOR_NEGATION_MODIFIER = new AttackPhaseProperty<ValueModifier> ("armor_negation", ValueModifier.CODEC);
|
public static final AttackPhaseProperty<ValueModifier> ARMOR_NEGATION_MODIFIER = new AttackPhaseProperty<ValueModifier> ("armor_negation", ValueModifier.CODEC);
|
||||||
public static final AttackPhaseProperty<ValueModifier> IMPACT_MODIFIER = new AttackPhaseProperty<ValueModifier> ("impact", ValueModifier.CODEC);
|
public static final AttackPhaseProperty<ValueModifier> IMPACT_MODIFIER = new AttackPhaseProperty<ValueModifier> ("impact", ValueModifier.CODEC);
|
||||||
public static final AttackPhaseProperty<Set<ExtraDamageInstance>> EXTRA_DAMAGE = new AttackPhaseProperty<Set<ExtraDamageInstance>> ();
|
// RIG : EXTRA_DAMAGE, STUN_TYPE, PARTICLE strippés (combat).
|
||||||
public static final AttackPhaseProperty<StunType> STUN_TYPE = new AttackPhaseProperty<StunType> ();
|
|
||||||
public static final AttackPhaseProperty<SoundEvent> SWING_SOUND = new AttackPhaseProperty<SoundEvent> ();
|
public static final AttackPhaseProperty<SoundEvent> SWING_SOUND = new AttackPhaseProperty<SoundEvent> ();
|
||||||
public static final AttackPhaseProperty<SoundEvent> HIT_SOUND = new AttackPhaseProperty<SoundEvent> ();
|
public static final AttackPhaseProperty<SoundEvent> HIT_SOUND = new AttackPhaseProperty<SoundEvent> ();
|
||||||
public static final AttackPhaseProperty<RegistryObject<HitParticleType>> PARTICLE = new AttackPhaseProperty<RegistryObject<HitParticleType>> ();
|
|
||||||
public static final AttackPhaseProperty<Priority> HIT_PRIORITY = new AttackPhaseProperty<Priority> ();
|
public static final AttackPhaseProperty<Priority> HIT_PRIORITY = new AttackPhaseProperty<Priority> ();
|
||||||
public static final AttackPhaseProperty<Set<TagKey<DamageType>>> SOURCE_TAG = new AttackPhaseProperty<Set<TagKey<DamageType>>> ();
|
public static final AttackPhaseProperty<Set<TagKey<DamageType>>> SOURCE_TAG = new AttackPhaseProperty<Set<TagKey<DamageType>>> ();
|
||||||
public static final AttackPhaseProperty<Function<LivingEntityPatch<?>, Vec3>> SOURCE_LOCATION_PROVIDER = new AttackPhaseProperty<Function<LivingEntityPatch<?>, Vec3>> ();
|
public static final AttackPhaseProperty<Function<LivingEntityPatch<?>, Vec3>> SOURCE_LOCATION_PROVIDER = new AttackPhaseProperty<Function<LivingEntityPatch<?>, Vec3>> ();
|
||||||
|
|||||||
@@ -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.AttackAnimation.Phase;
|
||||||
import com.tiedup.remake.rig.anim.types.DynamicAnimation;
|
import com.tiedup.remake.rig.anim.types.DynamicAnimation;
|
||||||
import com.tiedup.remake.rig.anim.types.EntityState;
|
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.MathUtils;
|
||||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||||
import com.tiedup.remake.rig.math.Vec3f;
|
import com.tiedup.remake.rig.math.Vec3f;
|
||||||
|
|||||||
@@ -6,400 +6,32 @@
|
|||||||
|
|
||||||
package com.tiedup.remake.rig.anim.types;
|
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.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.armature.Armature;
|
||||||
import com.tiedup.remake.rig.util.TimePairList;
|
import com.tiedup.remake.rig.asset.AssetAccessor;
|
||||||
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;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 class ActionAnimation extends MainFrameAnimation {
|
||||||
public static final SharedAnimationVariableKey<TransformSheet> ACTION_ANIMATION_COORD = AnimationVariables.shared((animator) -> new TransformSheet(), false);
|
|
||||||
public static final IndependentAnimationVariableKey<Vec3> BEGINNING_LOCATION = AnimationVariables.independent((animator) -> animator.getEntityPatch().getOriginal().position(), true);
|
public ActionAnimation(float transitionTime, boolean isRepeat, String registryName, AssetAccessor<? extends Armature> armature) {
|
||||||
public static final IndependentAnimationVariableKey<Float> INITIAL_LOOK_VEC_DOT = AnimationVariables.independent((animator) -> 1.0F, true);
|
super(transitionTime, isRepeat, registryName, armature);
|
||||||
|
|
||||||
public ActionAnimation(float transitionTime, AnimationAccessor<? extends ActionAnimation> accessor, AssetAccessor<? extends Armature> armature) {
|
|
||||||
this(transitionTime, Float.MAX_VALUE, accessor, armature);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionAnimation(float transitionTime, float postDelay, AnimationAccessor<? extends ActionAnimation> accessor, AssetAccessor<? extends Armature> 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<? extends Armature> 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<? extends DynamicAnimation> 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void move(LivingEntityPatch<?> entitypatch, AssetAccessor<? extends DynamicAnimation> animation) {
|
public ActionAnimation(boolean isRepeat, String registryName, AssetAccessor<? extends Armature> armature) {
|
||||||
if (!this.validateMovement(entitypatch, animation)) {
|
super(isRepeat, registryName, armature);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean validateMovement(LivingEntityPatch<?> entitypatch, AssetAccessor<? extends DynamicAnimation> 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<? extends DynamicAnimation> 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<String, JointTransform> data1 = startPose.getJointTransformData();
|
|
||||||
Map<String, JointTransform> data2 = nextStartPose.getJointTransformData();
|
|
||||||
Set<String> joint1 = new HashSet<> (isOnSameLayer ? data1.keySet() : Set.of());
|
|
||||||
Set<String> 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<String, JointTransform> 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
|
* Ajoute une propriété action-specific (COORD TransformSheet typiquement).
|
||||||
*
|
* Version stub : no-op, juste pour que les refs JsonAssetLoader compilent.
|
||||||
* @param entitypatch
|
|
||||||
* @param elapseTime
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public Vec3 getExpectedMovement(LivingEntityPatch<?> entitypatch, float elapseTime) {
|
public <V> ActionAnimation addProperty(ActionAnimationProperty<V> property, V value) {
|
||||||
this.initCoordVariables(entitypatch);
|
return this;
|
||||||
|
|
||||||
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<? extends DynamicAnimation> 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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,565 +6,51 @@
|
|||||||
|
|
||||||
package com.tiedup.remake.rig.anim.types;
|
package com.tiedup.remake.rig.anim.types;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
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.armature.Armature;
|
||||||
import com.tiedup.remake.rig.util.AttackResult;
|
import com.tiedup.remake.rig.asset.AssetAccessor;
|
||||||
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;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* <p>On conserve :</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Le type {@code AttackAnimation} pour les {@code instanceof} dans
|
||||||
|
* {@link com.tiedup.remake.rig.asset.JsonAssetLoader}:584</li>
|
||||||
|
* <li>Le field {@code phases} (liste vide) pour la boucle d'itération
|
||||||
|
* en JsonAssetLoader:591</li>
|
||||||
|
* <li>La classe interne {@link Phase} avec un {@code getColliders()}
|
||||||
|
* no-op pour JsonAssetLoader:592</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
public class AttackAnimation extends ActionAnimation {
|
public class AttackAnimation extends ActionAnimation {
|
||||||
/** Entities that collided **/
|
|
||||||
public static final SharedAnimationVariableKey<List<Entity>> ATTACK_TRIED_ENTITIES = AnimationVariables.shared((animator) -> Lists.newArrayList(), false);
|
|
||||||
/** Entities that actually hurt **/
|
|
||||||
public static final SharedAnimationVariableKey<List<LivingEntity>> 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<? extends AttackAnimation> accessor, AssetAccessor<? extends Armature> 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<? extends AttackAnimation> accessor, AssetAccessor<? extends Armature> armature) {
|
|
||||||
this(transitionTime, accessor, armature, new Phase(0.0F, antic, preDelay, contact, recovery, Float.MAX_VALUE, hand, colliderJoint, collider));
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackAnimation(float transitionTime, AnimationAccessor<? extends AttackAnimation> accessor, AssetAccessor<? extends Armature> 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<? extends Armature> armature) {
|
public final List<Phase> phases = Collections.emptyList();
|
||||||
this(convertTime, path, armature, new Phase(0.0F, antic, preDelay, contact, recovery, Float.MAX_VALUE, hand, colliderJoint, collider));
|
|
||||||
|
public AttackAnimation(float transitionTime, boolean isRepeat, String registryName, AssetAccessor<? extends Armature> armature) {
|
||||||
|
super(transitionTime, isRepeat, registryName, armature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AttackAnimation(boolean isRepeat, String registryName, AssetAccessor<? extends Armature> 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<? extends Armature> 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<? extends DynamicAnimation> 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<? extends DynamicAnimation> 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<? extends DynamicAnimation> 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<Entity> 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<RegistryObject<HitParticleType>> 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<Float> 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 <V, A extends AttackAnimation> A addProperty(AttackPhaseProperty<V> propertyType, V value) {
|
|
||||||
return (A)this.addProperty(propertyType, value, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <V, A extends AttackAnimation> A addProperty(AttackPhaseProperty<V> propertyType, V value, int index) {
|
|
||||||
this.phases[index].addProperty(propertyType, value);
|
|
||||||
return (A)this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <A extends AttackAnimation> A removeProperty(AttackPhaseProperty<?> propertyType) {
|
|
||||||
return this.removeProperty(propertyType, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <A extends AttackAnimation> 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<Joint, Collider> 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<Joint, Collider> {
|
|
||||||
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 {
|
public static class Phase {
|
||||||
private final Map<AttackPhaseProperty<?>, Object> properties = Maps.newHashMap();
|
public Object[] getColliders() {
|
||||||
public final float start;
|
return new Object[0];
|
||||||
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 <V> Phase addProperty(AttackPhaseProperty<V> 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<Map.Entry<AttackPhaseProperty<?>, Object>> set) {
|
|
||||||
for(Map.Entry<AttackPhaseProperty<?>, Object> entry : set) {
|
|
||||||
this.properties.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <V> Optional<V> getProperty(AttackPhaseProperty<V> propertyType) {
|
|
||||||
return (Optional<V>) Optional.ofNullable(this.properties.get(propertyType));
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Entity> getCollidingEntities(LivingEntityPatch<?> entitypatch, AttackAnimation animation, float prevElapsedTime, float elapsedTime, float attackSpeed) {
|
|
||||||
Set<Entity> entities = Sets.newHashSet();
|
|
||||||
|
|
||||||
for (Pair<Joint, Collider> 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,88 +6,23 @@
|
|||||||
|
|
||||||
package com.tiedup.remake.rig.anim.types;
|
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.armature.Armature;
|
||||||
import com.tiedup.remake.rig.util.datastruct.TypeFlexibleHashMap;
|
import com.tiedup.remake.rig.asset.AssetAccessor;
|
||||||
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;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 class MainFrameAnimation extends StaticAnimation {
|
||||||
public MainFrameAnimation(float convertTime, AnimationAccessor<? extends MainFrameAnimation> accessor, AssetAccessor<? extends Armature> armature) {
|
|
||||||
super(convertTime, false, accessor, armature);
|
public MainFrameAnimation(float transitionTime, boolean isRepeat, String registryName, AssetAccessor<? extends Armature> armature) {
|
||||||
|
super(transitionTime, isRepeat, registryName, armature);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MainFrameAnimation(float convertTime, String path, AssetAccessor<? extends Armature> armature) {
|
public MainFrameAnimation(boolean isRepeat, String registryName, AssetAccessor<? extends Armature> armature) {
|
||||||
super(convertTime, false, path, armature);
|
super(isRepeat, registryName, armature);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void begin(LivingEntityPatch<?> entitypatch) {
|
|
||||||
if (entitypatch.getAnimator().getPlayerFor(null).getAnimation().get() == this) {
|
|
||||||
TypeFlexibleHashMap<StateFactor<?>> stateMap = this.stateSpectrum.getStateMap(entitypatch, 0.0F);
|
|
||||||
TypeFlexibleHashMap<StateFactor<?>> 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<ServerPlayerPatch> 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<StatesInTime> timePairs = Sets.newHashSet();
|
||||||
|
|
||||||
|
void readFrom(StateSpectrum.Blueprint blueprint) {
|
||||||
|
this.timePairs.clear();
|
||||||
|
this.timePairs.addAll(blueprint.timePairs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T getSingleState(StateFactor<T> stateFactor, LivingEntityPatch<?> entitypatch, float time) {
|
||||||
|
for (StatesInTime state : this.timePairs) {
|
||||||
|
if (state.isIn(entitypatch, time)) {
|
||||||
|
for (Map.Entry<StateFactor<?>, ?> timeEntry : state.getStates(entitypatch)) {
|
||||||
|
if (timeEntry.getKey() == stateFactor) {
|
||||||
|
return (T) timeEntry.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stateFactor.defaultValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeFlexibleHashMap<StateFactor<?>> getStateMap(LivingEntityPatch<?> entitypatch, float time) {
|
||||||
|
TypeFlexibleHashMap<StateFactor<?>> stateMap = new TypeFlexibleHashMap<>(true);
|
||||||
|
|
||||||
|
for (StatesInTime state : this.timePairs) {
|
||||||
|
if (state.isIn(entitypatch, time)) {
|
||||||
|
for (Map.Entry<StateFactor<?>, ?> timeEntry : state.getStates(entitypatch)) {
|
||||||
|
stateMap.put(timeEntry.getKey(), timeEntry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stateMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract static class StatesInTime {
|
||||||
|
public abstract Set<Map.Entry<StateFactor<?>, 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<StateFactor<?>, 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 <T> StatesInTime addState(StateFactor<T> factor, T val) {
|
||||||
|
this.states.put(factor, val);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Map.Entry<StateFactor<?>, 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<Map<StateFactor<?>, Object>> conditionalStates = new Int2ObjectOpenHashMap<>();
|
||||||
|
Function<LivingEntityPatch<?>, Integer> condition;
|
||||||
|
|
||||||
|
public ConditionalStatesInTime(Function<LivingEntityPatch<?>, Integer> condition, float start, float end) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.condition = condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> StatesInTime addConditionalState(int metadata, StateFactor<T> factor, T val) {
|
||||||
|
Map<StateFactor<?>, Object> states = this.conditionalStates.computeIfAbsent(metadata, (key) -> Maps.newHashMap());
|
||||||
|
states.put(factor, val);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Override
|
||||||
|
public Set<Map.Entry<StateFactor<?>, 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<StateFactor<?>, Object> states : this.conditionalStates.values()) {
|
||||||
|
hasState |= states.containsKey(state);
|
||||||
|
}
|
||||||
|
return hasState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeState(StateFactor<?> state) {
|
||||||
|
for (Map<StateFactor<?>, 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<Integer, Map<StateFactor<?>, 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<LivingEntityPatch<?>, Float> variableStart;
|
||||||
|
Function<LivingEntityPatch<?>, Float> variableEnd;
|
||||||
|
Map<StateFactor<?>, Object> states = Maps.newHashMap();
|
||||||
|
|
||||||
|
public VariableStatesInTime(Function<LivingEntityPatch<?>, Float> variableStart, Function<LivingEntityPatch<?>, 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 <T> StatesInTime addState(StateFactor<T> factor, T val) {
|
||||||
|
this.states.put(factor, val);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Map.Entry<StateFactor<?>, 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<StatesInTime> 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<LivingEntityPatch<?>, Integer> condition, float start, float end) {
|
||||||
|
this.currentState = new ConditionalStatesInTime(condition, start, end);
|
||||||
|
this.timePairs.add(this.currentState);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Blueprint newVariableTimePair(Function<LivingEntityPatch<?>, Float> variableStart, Function<LivingEntityPatch<?>, Float> variableEnd) {
|
||||||
|
this.currentState = new VariableStatesInTime(variableStart, variableEnd);
|
||||||
|
this.timePairs.add(this.currentState);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Blueprint addState(StateFactor<T> 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 <T> Blueprint addConditionalState(int metadata, StateFactor<T> factor, T val) {
|
||||||
|
if (this.currentState instanceof ConditionalStatesInTime conditionalState) {
|
||||||
|
conditionalState.addConditionalState(metadata, factor, val);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Blueprint removeState(StateFactor<T> factor) {
|
||||||
|
for (StatesInTime timePair : this.timePairs) {
|
||||||
|
timePair.removeState(factor);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Blueprint addStateRemoveOld(StateFactor<T> factor, T val) {
|
||||||
|
this.removeState(factor);
|
||||||
|
return this.addState(factor, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Blueprint addStateIfNotExist(StateFactor<T> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.anim.client.property.TrailInfo;
|
||||||
import com.tiedup.remake.rig.exception.AssetLoadingException;
|
import com.tiedup.remake.rig.exception.AssetLoadingException;
|
||||||
import com.tiedup.remake.rig.armature.Armature;
|
import com.tiedup.remake.rig.armature.Armature;
|
||||||
import yesman.epicfight.api.physics.ik.InverseKinematicsProvider;
|
import com.tiedup.remake.rig.physics.ik.InverseKinematicsProvider;
|
||||||
import yesman.epicfight.api.physics.ik.InverseKinematicsSimulatable;
|
import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulatable;
|
||||||
import yesman.epicfight.api.physics.ik.InverseKinematicsSimulator;
|
import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator;
|
||||||
import yesman.epicfight.api.physics.ik.InverseKinematicsSimulator.BakedInverseKinematicsDefinition;
|
import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator.BakedInverseKinematicsDefinition;
|
||||||
import yesman.epicfight.api.physics.ik.InverseKinematicsSimulator.InverseKinematicsObject;
|
import com.tiedup.remake.rig.physics.ik.InverseKinematicsSimulator.InverseKinematicsObject;
|
||||||
import com.tiedup.remake.rig.util.datastruct.TypeFlexibleHashMap;
|
import com.tiedup.remake.rig.util.datastruct.TypeFlexibleHashMap;
|
||||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||||
import com.tiedup.remake.rig.math.Vec3f;
|
import com.tiedup.remake.rig.math.Vec3f;
|
||||||
import yesman.epicfight.client.ClientEngine;
|
|
||||||
import com.tiedup.remake.rig.render.TiedUpRenderTypes;
|
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.TiedUpRigRegistry;
|
||||||
import com.tiedup.remake.rig.TiedUpRigConstants;
|
import com.tiedup.remake.rig.TiedUpRigConstants;
|
||||||
import com.tiedup.remake.rig.patch.LivingEntityPatch;
|
import com.tiedup.remake.rig.patch.LivingEntityPatch;
|
||||||
import com.tiedup.remake.rig.patch.PlayerPatch;
|
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 class StaticAnimation extends DynamicAnimation implements InverseKinematicsProvider {
|
||||||
public static final IndependentAnimationVariableKey<Boolean> HAD_NO_PHYSICS = AnimationVariables.independent((animator) -> false, true);
|
public static final IndependentAnimationVariableKey<Boolean> 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 jointId = Double.longBitsToDouble((long)this.armature.get().searchJointByName(trailInfo.joint()).getId());
|
||||||
double index = Double.longBitsToDouble((long)idx++);
|
double index = Double.longBitsToDouble((long)idx++);
|
||||||
|
|
||||||
if (trailInfo.hand() != null) {
|
// RIG : RenderItemBase (combat weapon item render) strippé —
|
||||||
RenderItemBase renderitembase = ClientEngine.getInstance().renderEngine.getItemRenderer(entitypatch.getAdvancedHoldingItemStack(trailInfo.hand()));
|
// TiedUp n'a pas d'items "actifs" porteurs de trails comme
|
||||||
|
// les weapons EF. Le trailInfo reste tel quel de la définition.
|
||||||
if (renderitembase != null && renderitembase.trailInfo() != null) {
|
|
||||||
trailInfo = renderitembase.trailInfo().overwrite(trailInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!trailInfo.playable()) {
|
if (!trailInfo.playable()) {
|
||||||
continue;
|
continue;
|
||||||
@@ -294,16 +284,13 @@ public class StaticAnimation extends DynamicAnimation implements InverseKinemati
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (entitypatch instanceof PlayerPatch<?> playerpatch) {
|
// RIG : PlayerEventListener (combat animation events) strippé.
|
||||||
playerpatch.getEventListener().triggerEvents(EventType.ANIMATION_BEGIN_EVENT, new AnimationBeginEvent(playerpatch, this));
|
// Les ON_BEGIN_EVENTS SimpleEvent continuent de fonctionner ci-dessus.
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void end(LivingEntityPatch<?> entitypatch, AssetAccessor<? extends DynamicAnimation> nextAnimation, boolean isEnd) {
|
public void end(LivingEntityPatch<?> entitypatch, AssetAccessor<? extends DynamicAnimation> nextAnimation, boolean isEnd) {
|
||||||
if (entitypatch instanceof PlayerPatch<?> playerpatch) {
|
// RIG : ANIMATION_END_EVENT fire strippé (PlayerEventListener combat).
|
||||||
playerpatch.getEventListener().triggerEvents(EventType.ANIMATION_END_EVENT, new AnimationEndEvent(playerpatch, this, isEnd));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.getProperty(StaticAnimationProperty.ON_END_EVENTS).ifPresent((events) -> {
|
this.getProperty(StaticAnimationProperty.ON_END_EVENTS).ifPresent((events) -> {
|
||||||
for (SimpleEvent<?> event : events) {
|
for (SimpleEvent<?> event : events) {
|
||||||
@@ -604,38 +591,9 @@ public class StaticAnimation extends DynamicAnimation implements InverseKinemati
|
|||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public void renderDebugging(PoseStack poseStack, MultiBufferSource buffer, LivingEntityPatch<?> entitypatch, float playTime, float partialTicks) {
|
public void renderDebugging(PoseStack poseStack, MultiBufferSource buffer, LivingEntityPatch<?> entitypatch, float playTime, float partialTicks) {
|
||||||
if (entitypatch instanceof InverseKinematicsSimulatable ikSimulatable) {
|
// RIG : debug render des targets IK (RenderingTool.drawQuad) strippé.
|
||||||
this.getProperty(StaticAnimationProperty.BAKED_IK_DEFINITION).ifPresent((ikDefinitions) -> {
|
// Pas d'IK en TiedUp. Reactivable Phase 2+ avec un helper drawQuad
|
||||||
OpenMatrix4f modelmat = ikSimulatable.getModelMatrix(partialTicks);
|
// simple si on veut debug les joints.
|
||||||
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));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
* 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.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.tiedup.remake.rig.anim;
|
package com.tiedup.remake.rig.armature;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ import org.apache.commons.lang3.tuple.Pair;
|
|||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import yesman.epicfight.api.physics.PhysicsSimulator;
|
import com.tiedup.remake.rig.physics.PhysicsSimulator;
|
||||||
import yesman.epicfight.api.physics.SimulationObject;
|
import com.tiedup.remake.rig.physics.SimulationObject;
|
||||||
import yesman.epicfight.api.physics.SimulationObject.SimulationObjectBuilder;
|
import com.tiedup.remake.rig.physics.SimulationObject.SimulationObjectBuilder;
|
||||||
import yesman.epicfight.api.physics.SimulationProvider;
|
import com.tiedup.remake.rig.physics.SimulationProvider;
|
||||||
|
|
||||||
public abstract class AbstractSimulator<KEY, B extends SimulationObjectBuilder, PV extends SimulationProvider<O, SO, B, PV>, O, SO extends SimulationObject<B, PV, O>> implements PhysicsSimulator<KEY, B, PV, O, SO> {
|
public abstract class AbstractSimulator<KEY, B extends SimulationObjectBuilder, PV extends SimulationProvider<O, SO, B, PV>, O, SO extends SimulationObject<B, PV, O>> implements PhysicsSimulator<KEY, B, PV, O, SO> {
|
||||||
protected Map<KEY, ObjectWrapper> simulationObjects = Maps.newHashMap();
|
protected Map<KEY, ObjectWrapper> simulationObjects = Maps.newHashMap();
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import javax.annotation.Nullable;
|
|||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import com.tiedup.remake.rig.anim.Animator;
|
import com.tiedup.remake.rig.anim.Animator;
|
||||||
import com.tiedup.remake.rig.armature.Armature;
|
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 {
|
public interface ClothSimulatable extends SimulatableObject {
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -48,9 +48,9 @@ import com.tiedup.remake.rig.mesh.SoftBodyTranslatable;
|
|||||||
import com.tiedup.remake.rig.mesh.VertexBuilder;
|
import com.tiedup.remake.rig.mesh.VertexBuilder;
|
||||||
import com.tiedup.remake.rig.cloth.AbstractSimulator;
|
import com.tiedup.remake.rig.cloth.AbstractSimulator;
|
||||||
import com.tiedup.remake.rig.cloth.ClothSimulator.ClothObjectBuilder;
|
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 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.MathUtils;
|
||||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||||
import com.tiedup.remake.rig.math.Vec3f;
|
import com.tiedup.remake.rig.math.Vec3f;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,8 +34,8 @@ import com.tiedup.remake.rig.util.ParseUtil;
|
|||||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||||
import com.tiedup.remake.rig.math.Vec4f;
|
import com.tiedup.remake.rig.math.Vec4f;
|
||||||
import com.tiedup.remake.rig.render.TiedUpRenderTypes;
|
import com.tiedup.remake.rig.render.TiedUpRenderTypes;
|
||||||
import yesman.epicfight.client.renderer.shader.compute.ComputeShaderSetup;
|
import com.tiedup.remake.rig.render.compute.ComputeShaderSetup;
|
||||||
import yesman.epicfight.client.renderer.shader.compute.loader.ComputeShaderProvider;
|
import com.tiedup.remake.rig.render.compute.ComputeShaderProvider;
|
||||||
import com.tiedup.remake.rig.TiedUpAnimationConfig;
|
import com.tiedup.remake.rig.TiedUpAnimationConfig;
|
||||||
import com.tiedup.remake.rig.TiedUpRigConstants;
|
import com.tiedup.remake.rig.TiedUpRigConstants;
|
||||||
|
|
||||||
|
|||||||
@@ -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.ClothSimulatable;
|
||||||
import com.tiedup.remake.rig.cloth.ClothSimulator;
|
import com.tiedup.remake.rig.cloth.ClothSimulator;
|
||||||
import com.tiedup.remake.rig.cloth.ClothSimulator.ClothObject.ClothPart.ConstraintType;
|
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<ClothSimulatable, ClothSimulator.ClothObject, ClothSimulator.ClothObjectBuilder, SoftBodyTranslatable> {
|
public interface SoftBodyTranslatable extends SimulationProvider<ClothSimulatable, ClothSimulator.ClothObject, ClothSimulator.ClothObjectBuilder, SoftBodyTranslatable> {
|
||||||
public static final List<ClothSimulatable> TRACKING_SIMULATION_SUBJECTS = Lists.newArrayList();
|
public static final List<ClothSimulatable> TRACKING_SIMULATION_SUBJECTS = Lists.newArrayList();
|
||||||
|
|||||||
@@ -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<T extends AbstractClientPlayer> extends PlayerPatch<T> 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 <SIM extends PhysicsSimulator<?, ?, ?, ?, ?>> Optional<SIM> getSimulator(SimulationTypes<?, ?, ?, ?, ?, SIM> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
83
src/main/java/com/tiedup/remake/rig/patch/EntityPatch.java
Normal file
83
src/main/java/com/tiedup/remake/rig/patch/EntityPatch.java
Normal file
@@ -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<T extends Entity> {
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -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<T extends LivingEntity> extends EntityPatch<T> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<LocalPlayer> {
|
|
||||||
|
|
||||||
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<? extends StaticAnimation> currentPlaying = this.firstPersonLayer.animationPlayer.getRealAnimation();
|
|
||||||
|
|
||||||
boolean noPovAnimation = this.getClientAnimator().iterVisibleLayersUntilFalse(layer -> {
|
|
||||||
if (layer.isOff()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<DirectStaticAnimation> optPovAnimation = layer.animationPlayer.getRealAnimation().get().getProperty(ClientAnimationProperties.POV_ANIMATION);
|
|
||||||
Optional<PovSettings> 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<? extends StaticAnimation> 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<? extends StaticAnimation> 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<? extends StaticAnimation> 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<? extends StaticAnimation> 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<? extends StaticAnimation> 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<? extends StaticAnimation> nextFirstPersonAnimation, AssetAccessor<? extends StaticAnimation> originalAnimation, LivingEntityPatch<?> entitypatch, float transitionTimeModifier) {
|
|
||||||
Optional<PovSettings> 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
17
src/main/java/com/tiedup/remake/rig/patch/MobPatch.java
Normal file
17
src/main/java/com/tiedup/remake/rig/patch/MobPatch.java
Normal file
@@ -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<T extends Mob> extends LivingEntityPatch<T> {
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
}
|
||||||
@@ -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<KEY, B extends SimulationObjectBuilder, PV extends SimulationProvider<O, T, B, PV>, O, T extends SimulationObject<B, PV, O>> {
|
||||||
|
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<T> getRunningObject(KEY key);
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
<SIM extends PhysicsSimulator<?, ?, ?, ?, ?>> Optional<SIM> getSimulator(SimulationTypes<?, ?, ?, ?, ?, SIM> simulationType);
|
||||||
|
}
|
||||||
@@ -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<B extends SimulationObjectBuilder, PV extends SimulationProvider<O, ?, B, PV>, O> {
|
||||||
|
/**
|
||||||
|
* An abstract method to specify the parameters needed to build SimulationObject
|
||||||
|
*/
|
||||||
|
public abstract class SimulationObjectBuilder {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<OWN, OBJ extends SimulationObject<?, ?, ?>, BUILDER extends SimulationObjectBuilder, P extends SimulationProvider<OWN, OBJ, BUILDER, P>> {
|
||||||
|
public OBJ createSimulationData(@Nullable P provider, OWN simOwner, BUILDER simBuilder);
|
||||||
|
}
|
||||||
@@ -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<KEY, O, PV extends SimulationProvider<O, DATA, B, PV>, B extends SimulationObject.SimulationObjectBuilder, DATA extends SimulationObject<B, PV, O>, SIM extends PhysicsSimulator<KEY, B, PV, O, DATA>> {
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public static final SimulationTypes<ResourceLocation, ClothSimulatable, SoftBodyTranslatable, ClothSimulator.ClothObjectBuilder, ClothSimulator.ClothObject, ClothSimulator> CLOTH = new SimulationTypes<> () {};
|
||||||
|
public static final SimulationTypes<Joint, InverseKinematicsSimulatable, InverseKinematicsProvider, InverseKinematicsSimulator.InverseKinematicsBuilder, InverseKinematicsSimulator.InverseKinematicsObject, InverseKinematicsSimulator> INVERSE_KINEMATICS = new SimulationTypes<> () {};
|
||||||
|
}
|
||||||
@@ -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).
|
||||||
|
*
|
||||||
|
* <p>Non utilisé en TiedUp (pas de combat, pas de weapon IK).
|
||||||
|
* Conservé comme interface vide pour que {@code StaticAnimation
|
||||||
|
* implements InverseKinematicsProvider} compile.</p>
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
*
|
||||||
|
* <p>Conservé comme shell vide pour que les imports StaticAnimation +
|
||||||
|
* AnimationProperty compilent. Les nested types sont des stubs sans
|
||||||
|
* logique.</p>
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
*
|
||||||
|
* <p>Réactivation future (hors scope V1) : réintroduire l'implémentation
|
||||||
|
* complète EF + gérer IrisComputeShaderSetup pour compat shader packs.</p>
|
||||||
|
*/
|
||||||
|
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).
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/main/java/com/tiedup/remake/rig/util/ExtendableEnum.java
Normal file
11
src/main/java/com/tiedup/remake/rig/util/ExtendableEnum.java
Normal file
@@ -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();
|
||||||
|
}
|
||||||
@@ -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<T extends ExtendableEnum> {
|
||||||
|
private final Int2ObjectMap<T> enumMapByOrdinal = new Int2ObjectLinkedOpenHashMap<>();
|
||||||
|
private final Map<String, T> enumMapByName = Maps.newLinkedHashMap();
|
||||||
|
private final Map<String, Class<?>> enums = Maps.newConcurrentMap();
|
||||||
|
private final String enumName;
|
||||||
|
private int lastOrdinal = 0;
|
||||||
|
|
||||||
|
public ExtendableEnumManager(String enumName) {
|
||||||
|
this.enumName = enumName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerEnumCls(String modid, Class<? extends ExtendableEnum> 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<String> 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<T> universalValues() {
|
||||||
|
return this.enumMapByOrdinal.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toTranslated(ExtendableEnum e) {
|
||||||
|
return Component.translatable(TiedUpRigConstants.MODID + "." + this.enumName + "." + ParseUtil.toLowerCase(e.toString())).getString();
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/main/java/com/tiedup/remake/rig/util/HitEntityList.java
Normal file
19
src/main/java/com/tiedup/remake/rig/util/HitEntityList.java
Normal file
@@ -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<Priority> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
254
src/main/java/com/tiedup/remake/rig/util/InstantiateInvoker.java
Normal file
254
src/main/java/com/tiedup/remake/rig/util/InstantiateInvoker.java
Normal file
@@ -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<String, Class<?>> PRIMITIVE_KEYWORDS = HashBiMap.create();
|
||||||
|
private static final BiMap<Class<?>, Class<?>> RETURN_TYPE_MAPPER = HashBiMap.create();
|
||||||
|
private static final Map<Class<?>, Function<String, Object>> 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<? extends Armature> 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<? extends Armature> 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<String, Object> 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<String, Object> decoder) {
|
||||||
|
STRING_TO_OBJECT_PARSER.put(clz, decoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> Result<T> invoke(String invocationCommand, @Nullable Class<T> hint) throws Exception {
|
||||||
|
if (invocationCommand.matches("\\(.+\\)") || invocationCommand.matches("\\(.+\\)\\#.+")) { // invoke instance
|
||||||
|
return (Result<T>)invokeInstance(invocationCommand, hint);
|
||||||
|
} else if (invocationCommand.matches("\\[.+\\]") || invocationCommand.matches("\\[.+\\]\\#.+")) { // invoke array
|
||||||
|
return (Result<T>)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<T> type = (Class<T>)PRIMITIVE_KEYWORDS.get(sType);
|
||||||
|
return Result.of(type, (T)STRING_TO_OBJECT_PARSER.get(type).apply(sValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<T> type = (Class<T>)Class.forName(sType);
|
||||||
|
|
||||||
|
if (STRING_TO_OBJECT_PARSER.containsKey(type)) {
|
||||||
|
if (RETURN_TYPE_MAPPER.containsKey(type)) {
|
||||||
|
return Result.of((Class<T>)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 <T> Result<T> 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<T>)type, (T)constructor.newInstance(oArgs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param hint has a higher priority than class specified in invocation command
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> Result<T[]> 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<T> 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<T[]>)type.arrayType(), resultArray.toArray(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] splitExceptWrapper(String sArgs, char keyword, boolean skipWrapper) {
|
||||||
|
List<String> 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<T> {
|
||||||
|
final Class<T> type;
|
||||||
|
final T result;
|
||||||
|
|
||||||
|
Result(Class<T> type, T result) {
|
||||||
|
this.type = type;
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Result<T> of(Class<T> type, T value) {
|
||||||
|
return new Result<>(type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<T> getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getResult() {
|
||||||
|
return this.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/main/java/com/tiedup/remake/rig/util/MutableBoolean.java
Normal file
48
src/main/java/com/tiedup/remake/rig/util/MutableBoolean.java
Normal file
@@ -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<MutableBoolean> {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<T> {
|
||||||
|
void encode(T obj, FriendlyByteBuf buffer);
|
||||||
|
|
||||||
|
T decode(FriendlyByteBuf buffer);
|
||||||
|
|
||||||
|
public static final PacketBufferCodec<Boolean> 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> 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> 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> 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> 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> 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 <T> PacketBufferCodec<TagKey<T>> tagKey(ResourceKey<Registry<T>> registry) {
|
||||||
|
return new PacketBufferCodec<>() {
|
||||||
|
@Override public void encode(TagKey<T> tagKey, FriendlyByteBuf buffer) {
|
||||||
|
buffer.writeResourceLocation(tagKey.registry().location());
|
||||||
|
buffer.writeResourceLocation(tagKey.location());
|
||||||
|
}
|
||||||
|
@Override public TagKey<T> decode(FriendlyByteBuf buffer) {
|
||||||
|
ResourceLocation reg = buffer.readResourceLocation();
|
||||||
|
ResourceLocation tagName = buffer.readResourceLocation();
|
||||||
|
return TagKey.create(ResourceKey.createRegistryKey(reg), tagName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/main/java/com/tiedup/remake/rig/util/TimePairList.java
Normal file
49
src/main/java/com/tiedup/remake/rig/util/TimePairList.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user