WIP: initial epic fight core extraction (Phase 0)
83 files forkés d'Epic Fight (~18k LOC). Base non-compilable en l'état.
Contenu extrait :
- math/ — OpenMatrix4f, Vec3f/4f/2f, QuaternionUtils, MathUtils, ...
- armature/ — Armature, Joint, JointTransform, HumanoidArmature
- anim/ — Animator, ServerAnimator, ClientAnimator, LivingMotion, ...
- anim/types/ — StaticAnimation, DynamicAnimation, MovementAnimation, LinkAnimation,
ConcurrentLinkAnimation, LayerOffAnimation, EntityState
- anim/client/ — Layer, ClientAnimator, JointMask
- mesh/ — SkinnedMesh, SingleGroupVertexBuilder, Mesh, HumanoidMesh, ...
- cloth/ — AbstractSimulator, ClothSimulator (dépendance transitive de StaticMesh)
- asset/ — JsonAssetLoader, AssetAccessor
- patch/ — EntityPatch, LivingEntityPatch, PlayerPatch, ClientPlayerPatch
- util/ — ParseUtil, TypeFlexibleHashMap
- exception/ — AssetLoadingException
- event/ — PatchedRenderersEvent, PrepareModelEvent, RegisterResourceLayersEvent
- render/ — TiedUpRenderTypes
Headers GPLv3 + attribution injectés sur tous les .java.
Package declarations fixées sur Armature.java et TiedUpRenderTypes.java.
115 imports résiduels à résoudre manuellement :
- yesman.epicfight.main (EpicFightMod, EpicFightSharedConstants) — 30
- yesman.epicfight.gameasset (Animations, Armatures, EpicFightSounds) — 12
- yesman.epicfight.api.physics + physics.ik (combat physics) — 16
- yesman.epicfight.network.* (combat packets) — 13
- yesman.epicfight.world.* (combat entity logic) — 10
- yesman.epicfight.config.ClientConfig — 3
- yesman.epicfight.skill, .client.gui, .particle, .collider — divers combat/UI
Stratégie fix (2-3 sem manuel) : strip usage combat, stubs pour refs
core (EpicFightMod → TiedUpMod, SharedConstants → TiedUpRigConstants,
ClientConfig → TiedUpAnimationConfig).
This commit is contained in:
270
src/main/java/com/tiedup/remake/rig/armature/Armature.java
Normal file
270
src/main/java/com/tiedup/remake/rig/armature/Armature.java
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* 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.armature;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import com.tiedup.remake.rig.armature.Joint;
|
||||
import com.tiedup.remake.rig.armature.JointTransform;
|
||||
import com.tiedup.remake.rig.anim.Pose;
|
||||
import com.tiedup.remake.rig.asset.JsonAssetLoader;
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
import yesman.epicfight.main.EpicFightMod;
|
||||
import yesman.epicfight.main.EpicFightSharedConstants;
|
||||
|
||||
public class Armature {
|
||||
private final String name;
|
||||
private final Int2ObjectMap<Joint> jointById;
|
||||
private final Map<String, Joint> jointByName;
|
||||
private final Map<String, Joint.HierarchicalJointAccessor> pathIndexMap;
|
||||
private final int jointCount;
|
||||
private final OpenMatrix4f[] poseMatrices;
|
||||
public final Joint rootJoint;
|
||||
|
||||
public Armature(String name, int jointNumber, Joint rootJoint, Map<String, Joint> jointMap) {
|
||||
this.name = name;
|
||||
this.jointCount = jointNumber;
|
||||
this.rootJoint = rootJoint;
|
||||
this.jointByName = jointMap;
|
||||
this.jointById = new Int2ObjectOpenHashMap<>();
|
||||
this.pathIndexMap = Maps.newHashMap();
|
||||
|
||||
this.jointByName.values().forEach((joint) -> {
|
||||
this.jointById.put(joint.getId(), joint);
|
||||
});
|
||||
|
||||
this.poseMatrices = OpenMatrix4f.allocateMatrixArray(this.jointCount);
|
||||
}
|
||||
|
||||
protected Joint getOrLogException(Map<String, Joint> jointMap, String name) {
|
||||
if (!jointMap.containsKey(name)) {
|
||||
if (EpicFightSharedConstants.IS_DEV_ENV) {
|
||||
EpicFightMod.LOGGER.debug("Cannot find the joint named " + name + " in " + this.getClass().getCanonicalName());
|
||||
}
|
||||
|
||||
return Joint.EMPTY;
|
||||
}
|
||||
|
||||
return jointMap.get(name);
|
||||
}
|
||||
|
||||
public void setPose(Pose pose) {
|
||||
this.getPoseTransform(this.rootJoint, new OpenMatrix4f(), pose, this.poseMatrices, false);
|
||||
}
|
||||
|
||||
public void bakeOriginMatrices() {
|
||||
this.rootJoint.initOriginTransform(new OpenMatrix4f());
|
||||
}
|
||||
|
||||
public OpenMatrix4f[] getPoseMatrices() {
|
||||
return this.poseMatrices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param applyOriginTransform if you need a final pose of the animations, give it false.
|
||||
*/
|
||||
public OpenMatrix4f[] getPoseAsTransformMatrix(Pose pose, boolean applyOriginTransform) {
|
||||
OpenMatrix4f[] jointMatrices = new OpenMatrix4f[this.jointCount];
|
||||
this.getPoseTransform(this.rootJoint, new OpenMatrix4f(), pose, jointMatrices, applyOriginTransform);
|
||||
return jointMatrices;
|
||||
}
|
||||
|
||||
private void getPoseTransform(Joint joint, OpenMatrix4f parentTransform, Pose pose, OpenMatrix4f[] jointMatrices, boolean applyOriginTransform) {
|
||||
OpenMatrix4f result = pose.orElseEmpty(joint.getName()).getAnimationBoundMatrix(joint, parentTransform);
|
||||
jointMatrices[joint.getId()] = result;
|
||||
|
||||
for (Joint joints : joint.getSubJoints()) {
|
||||
this.getPoseTransform(joints, result, pose, jointMatrices, applyOriginTransform);
|
||||
}
|
||||
|
||||
if (applyOriginTransform) {
|
||||
result.mulBack(joint.getToOrigin());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inapposite past perfect
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.21.1")
|
||||
public OpenMatrix4f getBindedTransformFor(Pose pose, Joint joint) {
|
||||
return this.getBoundTransformByJointIndex(pose, this.searchPathIndex(joint.getName()).createAccessTicket(this.rootJoint));
|
||||
}
|
||||
|
||||
public OpenMatrix4f getBoundTransformFor(Pose pose, Joint joint) {
|
||||
return this.getBoundTransformByJointIndex(pose, this.searchPathIndex(joint.getName()).createAccessTicket(this.rootJoint));
|
||||
}
|
||||
|
||||
public OpenMatrix4f getBoundTransformByJointIndex(Pose pose, Joint.AccessTicket pathIndices) {
|
||||
return this.getBoundJointTransformRecursively(pose, this.rootJoint, new OpenMatrix4f(), pathIndices);
|
||||
}
|
||||
|
||||
private OpenMatrix4f getBoundJointTransformRecursively(Pose pose, Joint joint, OpenMatrix4f parentTransform, Joint.AccessTicket pathIndices) {
|
||||
JointTransform jt = pose.orElseEmpty(joint.getName());
|
||||
OpenMatrix4f result = jt.getAnimationBoundMatrix(joint, parentTransform);
|
||||
|
||||
return pathIndices.hasNext() ? this.getBoundJointTransformRecursively(pose, pathIndices.next(), result, pathIndices) : result;
|
||||
}
|
||||
|
||||
public boolean hasJoint(String name) {
|
||||
return this.jointByName.containsKey(name);
|
||||
}
|
||||
|
||||
public Joint searchJointById(int id) {
|
||||
return this.jointById.get(id);
|
||||
}
|
||||
|
||||
public Joint searchJointByName(String name) {
|
||||
return this.jointByName.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search and record joint path from root to terminal
|
||||
*
|
||||
* @param terminalJointName
|
||||
* @return
|
||||
*/
|
||||
public Joint.HierarchicalJointAccessor searchPathIndex(String terminalJointName) {
|
||||
return this.searchPathIndex(this.rootJoint, terminalJointName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search and record joint path to terminal
|
||||
*
|
||||
* @param start
|
||||
* @param terminalJointName
|
||||
* @return
|
||||
*/
|
||||
public Joint.HierarchicalJointAccessor searchPathIndex(Joint start, String terminalJointName) {
|
||||
String signature = start.getName() + "-" + terminalJointName;
|
||||
|
||||
if (this.pathIndexMap.containsKey(signature)) {
|
||||
return this.pathIndexMap.get(signature);
|
||||
} else {
|
||||
Joint.HierarchicalJointAccessor.Builder pathBuilder = start.searchPath(Joint.HierarchicalJointAccessor.builder(), terminalJointName);
|
||||
Joint.HierarchicalJointAccessor accessor;
|
||||
|
||||
if (pathBuilder == null) {
|
||||
throw new IllegalArgumentException("Failed to get joint path index for " + terminalJointName);
|
||||
} else {
|
||||
accessor = pathBuilder.build();
|
||||
this.pathIndexMap.put(signature, accessor);
|
||||
}
|
||||
|
||||
return accessor;
|
||||
}
|
||||
}
|
||||
|
||||
public void gatherAllJointsInPathToTerminal(String terminalJointName, Collection<String> jointsInPath) {
|
||||
if (!this.jointByName.containsKey(terminalJointName)) {
|
||||
throw new NoSuchElementException("No " + terminalJointName + " joint in this armature!");
|
||||
}
|
||||
|
||||
Joint.HierarchicalJointAccessor pathIndices = this.searchPathIndex(terminalJointName);
|
||||
Joint.AccessTicket accessTicket = pathIndices.createAccessTicket(this.rootJoint);
|
||||
|
||||
Joint joint = this.rootJoint;
|
||||
jointsInPath.add(joint.getName());
|
||||
|
||||
while (accessTicket.hasNext()) {
|
||||
jointsInPath.add(accessTicket.next().getName());
|
||||
}
|
||||
}
|
||||
|
||||
public int getJointNumber() {
|
||||
return this.jointCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Armature deepCopy() {
|
||||
Map<String, Joint> oldToNewJoint = Maps.newHashMap();
|
||||
oldToNewJoint.put("empty", Joint.EMPTY);
|
||||
|
||||
Joint newRoot = this.copyHierarchy(this.rootJoint, oldToNewJoint);
|
||||
newRoot.initOriginTransform(new OpenMatrix4f());
|
||||
Armature newArmature = null;
|
||||
|
||||
// Uses reflection to keep the type of copied armature
|
||||
try {
|
||||
Constructor<? extends Armature> constructor = this.getClass().getConstructor(String.class, int.class, Joint.class, Map.class);
|
||||
newArmature = constructor.newInstance(this.name, this.jointCount, newRoot, oldToNewJoint);
|
||||
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
throw new IllegalStateException("Armature copy failed! " + e);
|
||||
}
|
||||
|
||||
return newArmature;
|
||||
}
|
||||
|
||||
private Joint copyHierarchy(Joint joint, Map<String, Joint> oldToNewJoint) {
|
||||
if (joint == Joint.EMPTY) {
|
||||
return Joint.EMPTY;
|
||||
}
|
||||
|
||||
Joint newJoint = new Joint(joint.getName(), joint.getId(), joint.getLocalTransform());
|
||||
oldToNewJoint.put(joint.getName(), newJoint);
|
||||
|
||||
for (Joint subJoint : joint.getSubJoints()) {
|
||||
newJoint.addSubJoints(this.copyHierarchy(subJoint, oldToNewJoint));
|
||||
}
|
||||
|
||||
return newJoint;
|
||||
}
|
||||
|
||||
public JsonObject toJsonObject() {
|
||||
JsonObject root = new JsonObject();
|
||||
JsonObject armature = new JsonObject();
|
||||
|
||||
JsonArray jointNamesArray = new JsonArray();
|
||||
JsonArray jointHierarchy = new JsonArray();
|
||||
|
||||
this.jointById.int2ObjectEntrySet().stream().sorted((entry1, entry2) -> Integer.compare(entry1.getIntKey(), entry2.getIntKey())).forEach((entry) -> jointNamesArray.add(entry.getValue().getName()));
|
||||
armature.add("joints", jointNamesArray);
|
||||
armature.add("hierarchy", jointHierarchy);
|
||||
|
||||
exportJoint(jointHierarchy, this.rootJoint, true);
|
||||
|
||||
root.add("armature", armature);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private static void exportJoint(JsonArray parent, Joint joint, boolean root) {
|
||||
JsonObject jointJson = new JsonObject();
|
||||
jointJson.addProperty("name", joint.getName());
|
||||
|
||||
JsonArray transformMatrix = new JsonArray();
|
||||
OpenMatrix4f localMatrixInBlender = new OpenMatrix4f(joint.getLocalTransform());
|
||||
|
||||
if (root) {
|
||||
localMatrixInBlender.mulFront(OpenMatrix4f.invert(JsonAssetLoader.BLENDER_TO_MINECRAFT_COORD, null));
|
||||
}
|
||||
|
||||
localMatrixInBlender.transpose();
|
||||
localMatrixInBlender.toList().forEach(transformMatrix::add);
|
||||
jointJson.add("transform", transformMatrix);
|
||||
parent.add(jointJson);
|
||||
|
||||
if (!joint.getSubJoints().isEmpty()) {
|
||||
JsonArray children = new JsonArray();
|
||||
jointJson.add("children", children);
|
||||
joint.getSubJoints().forEach((joint$2) -> exportJoint(children, joint$2, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.armature;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.tiedup.remake.rig.armature.Joint;
|
||||
import com.tiedup.remake.rig.armature.Armature;
|
||||
import com.tiedup.remake.rig.armature.types.HumanLikeArmature;
|
||||
|
||||
public class HumanoidArmature extends Armature implements HumanLikeArmature {
|
||||
public final Joint thighR;
|
||||
public final Joint legR;
|
||||
public final Joint kneeR;
|
||||
public final Joint thighL;
|
||||
public final Joint legL;
|
||||
public final Joint kneeL;
|
||||
public final Joint torso;
|
||||
public final Joint chest;
|
||||
public final Joint head;
|
||||
public final Joint shoulderR;
|
||||
public final Joint armR;
|
||||
public final Joint handR;
|
||||
public final Joint toolR;
|
||||
public final Joint elbowR;
|
||||
public final Joint shoulderL;
|
||||
public final Joint armL;
|
||||
public final Joint handL;
|
||||
public final Joint toolL;
|
||||
public final Joint elbowL;
|
||||
|
||||
public HumanoidArmature(String name, int jointNumber, Joint rootJoint, Map<String, Joint> jointMap) {
|
||||
super(name, jointNumber, rootJoint, jointMap);
|
||||
|
||||
this.thighR = this.getOrLogException(jointMap, "Thigh_R");
|
||||
this.legR = this.getOrLogException(jointMap, "Leg_R");
|
||||
this.kneeR = this.getOrLogException(jointMap, "Knee_R");
|
||||
this.thighL = this.getOrLogException(jointMap, "Thigh_L");
|
||||
this.legL = this.getOrLogException(jointMap, "Leg_L");
|
||||
this.kneeL = this.getOrLogException(jointMap, "Knee_L");
|
||||
this.torso = this.getOrLogException(jointMap, "Torso");
|
||||
this.chest = this.getOrLogException(jointMap, "Chest");
|
||||
this.head = this.getOrLogException(jointMap, "Head");
|
||||
this.shoulderR = this.getOrLogException(jointMap, "Shoulder_R");
|
||||
this.armR = this.getOrLogException(jointMap, "Arm_R");
|
||||
this.handR = this.getOrLogException(jointMap, "Hand_R");
|
||||
this.toolR = this.getOrLogException(jointMap, "Tool_R");
|
||||
this.elbowR = this.getOrLogException(jointMap, "Elbow_R");
|
||||
this.shoulderL = this.getOrLogException(jointMap, "Shoulder_L");
|
||||
this.armL = this.getOrLogException(jointMap, "Arm_L");
|
||||
this.handL = this.getOrLogException(jointMap, "Hand_L");
|
||||
this.toolL = this.getOrLogException(jointMap, "Tool_L");
|
||||
this.elbowL = this.getOrLogException(jointMap, "Elbow_L");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint leftToolJoint() {
|
||||
return this.toolL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint rightToolJoint() {
|
||||
return this.toolR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint backToolJoint() {
|
||||
return this.chest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint leftHandJoint() {
|
||||
return this.handL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint rightHandJoint() {
|
||||
return this.handR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint leftArmJoint() {
|
||||
return this.armL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint rightArmJoint() {
|
||||
return this.armR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint leftLegJoint() {
|
||||
return this.legL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint rightLegJoint() {
|
||||
return this.legR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint leftThighJoint() {
|
||||
return this.thighL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint rightThighJoint() {
|
||||
return this.thighR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joint headJoint() {
|
||||
return this.head;
|
||||
}
|
||||
}
|
||||
278
src/main/java/com/tiedup/remake/rig/armature/Joint.java
Normal file
278
src/main/java/com/tiedup/remake/rig/armature/Joint.java
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import com.tiedup.remake.rig.armature.Armature;
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
|
||||
public class Joint {
|
||||
public static final Joint EMPTY = new Joint("empty", -1, new OpenMatrix4f());
|
||||
|
||||
private final List<Joint> subJoints = Lists.newArrayList();
|
||||
private final int jointId;
|
||||
private final String jointName;
|
||||
private final OpenMatrix4f localTransform;
|
||||
private final OpenMatrix4f toOrigin = new OpenMatrix4f();
|
||||
|
||||
public Joint(String name, int jointId, OpenMatrix4f localTransform) {
|
||||
this.jointId = jointId;
|
||||
this.jointName = name;
|
||||
this.localTransform = localTransform.unmodifiable();
|
||||
}
|
||||
|
||||
public void addSubJoints(Joint... joints) {
|
||||
for (Joint joint : joints) {
|
||||
if (!this.subJoints.contains(joint)) {
|
||||
this.subJoints.add(joint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeSubJoints(Joint... joints) {
|
||||
for (Joint joint : joints) {
|
||||
this.subJoints.remove(joint);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Joint> getAllJoints() {
|
||||
List<Joint> list = Lists.newArrayList();
|
||||
this.getSubJoints(list);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public void iterSubJoints(Consumer<Joint> iterTask) {
|
||||
iterTask.accept(this);
|
||||
|
||||
for (Joint joint : this.subJoints) {
|
||||
joint.iterSubJoints(iterTask);
|
||||
}
|
||||
}
|
||||
|
||||
private void getSubJoints(List<Joint> list) {
|
||||
list.add(this);
|
||||
|
||||
for (Joint joint : this.subJoints) {
|
||||
joint.getSubJoints(list);
|
||||
}
|
||||
}
|
||||
|
||||
public void initOriginTransform(OpenMatrix4f parentTransform) {
|
||||
OpenMatrix4f modelTransform = OpenMatrix4f.mul(parentTransform, this.localTransform, null);
|
||||
OpenMatrix4f.invert(modelTransform, this.toOrigin);
|
||||
|
||||
for (Joint joint : this.subJoints) {
|
||||
joint.initOriginTransform(modelTransform);
|
||||
}
|
||||
}
|
||||
|
||||
public OpenMatrix4f getLocalTransform() {
|
||||
return this.localTransform;
|
||||
}
|
||||
|
||||
public OpenMatrix4f getToOrigin() {
|
||||
return this.toOrigin;
|
||||
}
|
||||
|
||||
public List<Joint> getSubJoints() {
|
||||
return this.subJoints;
|
||||
}
|
||||
|
||||
// Null if index out of range
|
||||
@Nullable
|
||||
public Joint getSubJoint(int index) {
|
||||
if (index < 0 || this.subJoints.size() <= index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.subJoints.get(index);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.jointName;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return this.jointId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof Joint joint) {
|
||||
return this.jointName.equals(joint.jointName) && this.jointId == joint.jointId;
|
||||
} else {
|
||||
return super.equals(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.jointName.hashCode() ^ this.jointId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the method that memorize path search results. {@link Armature#searchPathIndex(Joint, String)}
|
||||
*
|
||||
* @param builder
|
||||
* @param jointName
|
||||
* @return
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public HierarchicalJointAccessor.Builder searchPath(HierarchicalJointAccessor.Builder builder, String jointName) {
|
||||
if (jointName.equals(this.getName())) {
|
||||
return builder;
|
||||
} else {
|
||||
int i = 0;
|
||||
|
||||
for (Joint subJoint : this.subJoints) {
|
||||
HierarchicalJointAccessor.Builder nextBuilder = subJoint.searchPath(builder.append(i), jointName);
|
||||
i++;
|
||||
|
||||
if (nextBuilder != null) {
|
||||
return nextBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\nid: " + this.jointId);
|
||||
sb.append("\nname: " + this.jointName);
|
||||
sb.append("\nlocal transform: " + this.localTransform);
|
||||
sb.append("\nto origin: " + this.toOrigin);
|
||||
sb.append("\nchildren: [");
|
||||
|
||||
int idx = 0;
|
||||
|
||||
for (Joint joint : this.subJoints) {
|
||||
idx++;
|
||||
sb.append(joint.jointName);
|
||||
|
||||
if (idx != this.subJoints.size()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("]\n");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String printIncludingChildren() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.toString());
|
||||
|
||||
for (Joint joint : this.subJoints) {
|
||||
sb.append(joint.printIncludingChildren());
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static class HierarchicalJointAccessor {
|
||||
private Queue<Integer> indicesToTerminal;
|
||||
private final String signature;
|
||||
|
||||
private HierarchicalJointAccessor(Builder builder) {
|
||||
this.indicesToTerminal = builder.indicesToTerminal;
|
||||
this.signature = builder.signature;
|
||||
}
|
||||
|
||||
public AccessTicket createAccessTicket(Joint rootJoint) {
|
||||
return new AccessTicket(this.indicesToTerminal, rootJoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof HierarchicalJointAccessor accessor) {
|
||||
this.signature.equals(accessor.signature);
|
||||
}
|
||||
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.signature.hashCode();
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder(new LinkedList<> (), "");
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Queue<Integer> indicesToTerminal;
|
||||
private String signature;
|
||||
|
||||
private Builder(Queue<Integer> indicesToTerminal, String signature) {
|
||||
this.indicesToTerminal = indicesToTerminal;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public Builder append(int index) {
|
||||
String signatureNext;
|
||||
|
||||
if (this.indicesToTerminal.isEmpty()) {
|
||||
signatureNext = this.signature + String.valueOf(index);
|
||||
} else {
|
||||
signatureNext = this.signature + "-" + String.valueOf(index);
|
||||
}
|
||||
|
||||
Queue<Integer> nextQueue = new LinkedList<> (this.indicesToTerminal);
|
||||
nextQueue.add(index);
|
||||
|
||||
return new Builder(nextQueue, signatureNext);
|
||||
}
|
||||
|
||||
public HierarchicalJointAccessor build() {
|
||||
return new HierarchicalJointAccessor(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class AccessTicket implements Iterator<Joint> {
|
||||
Queue<Integer> accecssStack;
|
||||
Joint joint;
|
||||
|
||||
private AccessTicket(Queue<Integer> indicesToTerminal, Joint rootJoint) {
|
||||
this.accecssStack = new LinkedList<> (indicesToTerminal);
|
||||
this.joint = rootJoint;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return !this.accecssStack.isEmpty();
|
||||
}
|
||||
|
||||
public Joint next() {
|
||||
if (this.hasNext()) {
|
||||
int nextIndex = this.accecssStack.poll();
|
||||
this.joint = this.joint.subJoints.get(nextIndex);
|
||||
} else {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
return this.joint;
|
||||
}
|
||||
}
|
||||
}
|
||||
215
src/main/java/com/tiedup/remake/rig/armature/JointTransform.java
Normal file
215
src/main/java/com/tiedup/remake/rig/armature/JointTransform.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.joml.Quaternionf;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
import com.tiedup.remake.rig.math.AnimationTransformEntry;
|
||||
import com.tiedup.remake.rig.math.MathUtils;
|
||||
import com.tiedup.remake.rig.math.MatrixOperation;
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
import com.tiedup.remake.rig.math.Vec3f;
|
||||
|
||||
public class JointTransform {
|
||||
public static final String ANIMATION_TRANSFORM = "animation_transform";
|
||||
public static final String JOINT_LOCAL_TRANSFORM = "joint_local_transform";
|
||||
public static final String PARENT = "parent";
|
||||
public static final String RESULT1 = "front_result";
|
||||
public static final String RESULT2 = "overwrite_rotation";
|
||||
|
||||
public static class TransformEntry {
|
||||
public final MatrixOperation multiplyFunction;
|
||||
public final JointTransform transform;
|
||||
|
||||
public TransformEntry(MatrixOperation multiplyFunction, JointTransform transform) {
|
||||
this.multiplyFunction = multiplyFunction;
|
||||
this.transform = transform;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<String, TransformEntry> entries = Maps.newHashMap();
|
||||
private final Vec3f translation;
|
||||
private final Vec3f scale;
|
||||
private final Quaternionf rotation;
|
||||
|
||||
public JointTransform(Vec3f translation, Quaternionf rotation, Vec3f scale) {
|
||||
this.translation = translation;
|
||||
this.rotation = rotation;
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public Vec3f translation() {
|
||||
return this.translation;
|
||||
}
|
||||
|
||||
public Quaternionf rotation() {
|
||||
return this.rotation;
|
||||
}
|
||||
|
||||
public Vec3f scale() {
|
||||
return this.scale;
|
||||
}
|
||||
|
||||
public void clearTransform() {
|
||||
this.translation.set(0.0F, 0.0F, 0.0F);
|
||||
this.rotation.set(0.0F, 0.0F, 0.0F, 1.0F);
|
||||
this.scale.set(1.0F, 1.0F, 1.0F);
|
||||
}
|
||||
|
||||
public JointTransform copy() {
|
||||
return JointTransform.empty().copyFrom(this);
|
||||
}
|
||||
|
||||
public JointTransform copyFrom(JointTransform jt) {
|
||||
Vec3f newV = jt.translation();
|
||||
Quaternionf newQ = jt.rotation();
|
||||
Vec3f newS = jt.scale;
|
||||
this.translation.set(newV);
|
||||
this.rotation.set(newQ);
|
||||
this.scale.set(newS);
|
||||
this.entries.putAll(jt.entries);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void jointLocal(JointTransform transform, MatrixOperation multiplyFunction) {
|
||||
this.entries.put(JOINT_LOCAL_TRANSFORM, new TransformEntry(multiplyFunction, this.mergeIfExist(JOINT_LOCAL_TRANSFORM, transform)));
|
||||
}
|
||||
|
||||
public void parent(JointTransform transform, MatrixOperation multiplyFunction) {
|
||||
this.entries.put(PARENT, new TransformEntry(multiplyFunction, this.mergeIfExist(PARENT, transform)));
|
||||
}
|
||||
|
||||
public void animationTransform(JointTransform transform, MatrixOperation multiplyFunction) {
|
||||
this.entries.put(ANIMATION_TRANSFORM, new TransformEntry(multiplyFunction, this.mergeIfExist(ANIMATION_TRANSFORM, transform)));
|
||||
}
|
||||
|
||||
public void frontResult(JointTransform transform, MatrixOperation multiplyFunction) {
|
||||
this.entries.put(RESULT1, new TransformEntry(multiplyFunction, this.mergeIfExist(RESULT1, transform)));
|
||||
}
|
||||
|
||||
public void overwriteRotation(JointTransform transform) {
|
||||
this.entries.put(RESULT2, new TransformEntry(OpenMatrix4f::mul, this.mergeIfExist(RESULT2, transform)));
|
||||
}
|
||||
|
||||
public JointTransform mergeIfExist(String entryName, JointTransform transform) {
|
||||
if (this.entries.containsKey(entryName)) {
|
||||
TransformEntry transformEntry = this.entries.get(entryName);
|
||||
return JointTransform.mul(transform, transformEntry.transform, transformEntry.multiplyFunction);
|
||||
}
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
public OpenMatrix4f getAnimationBoundMatrix(Joint joint, OpenMatrix4f parentTransform) {
|
||||
AnimationTransformEntry animationTransformEntry = new AnimationTransformEntry();
|
||||
|
||||
for (Map.Entry<String, TransformEntry> entry : this.entries.entrySet()) {
|
||||
animationTransformEntry.put(entry.getKey(), entry.getValue().transform.toMatrix(), entry.getValue().multiplyFunction);
|
||||
}
|
||||
|
||||
animationTransformEntry.put(ANIMATION_TRANSFORM, this.toMatrix(), OpenMatrix4f::mul);
|
||||
animationTransformEntry.put(JOINT_LOCAL_TRANSFORM, joint.getLocalTransform());
|
||||
animationTransformEntry.put(PARENT, parentTransform);
|
||||
|
||||
return animationTransformEntry.getResult();
|
||||
}
|
||||
|
||||
public OpenMatrix4f toMatrix() {
|
||||
return new OpenMatrix4f().translate(this.translation).mulBack(OpenMatrix4f.fromQuaternion(this.rotation)).scale(this.scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("translation:%s, rotation:%s, scale:%s %d entries ", this.translation, this.rotation, this.scale, this.entries.size());
|
||||
}
|
||||
|
||||
public static JointTransform interpolateTransform(JointTransform prev, JointTransform next, float progression, JointTransform dest) {
|
||||
if (dest == null) {
|
||||
dest = JointTransform.empty();
|
||||
}
|
||||
|
||||
MathUtils.lerpVector(prev.translation, next.translation, progression, dest.translation);
|
||||
MathUtils.lerpQuaternion(prev.rotation, next.rotation, progression, dest.rotation);
|
||||
MathUtils.lerpVector(prev.scale, next.scale, progression, dest.scale);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
public static JointTransform interpolate(JointTransform prev, JointTransform next, float progression) {
|
||||
return interpolate(prev, next, progression, null);
|
||||
}
|
||||
|
||||
public static JointTransform interpolate(JointTransform prev, JointTransform next, float progression, JointTransform dest) {
|
||||
if (dest == null) {
|
||||
dest = JointTransform.empty();
|
||||
}
|
||||
|
||||
if (prev == null || next == null) {
|
||||
dest.clearTransform();
|
||||
return dest;
|
||||
}
|
||||
|
||||
progression = Mth.clamp(progression, 0.0F, 1.0F);
|
||||
interpolateTransform(prev, next, progression, dest);
|
||||
dest.entries.clear();
|
||||
|
||||
for (Map.Entry<String, TransformEntry> entry : prev.entries.entrySet()) {
|
||||
JointTransform transform = next.entries.containsKey(entry.getKey()) ? next.entries.get(entry.getKey()).transform : JointTransform.empty();
|
||||
dest.entries.put(entry.getKey(), new TransformEntry(entry.getValue().multiplyFunction, interpolateTransform(entry.getValue().transform, transform, progression, null)));
|
||||
}
|
||||
|
||||
for (Map.Entry<String, TransformEntry> entry : next.entries.entrySet()) {
|
||||
if (!dest.entries.containsKey(entry.getKey())) {
|
||||
dest.entries.put(entry.getKey(), new TransformEntry(entry.getValue().multiplyFunction, interpolateTransform(JointTransform.empty(), entry.getValue().transform, progression, null)));
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
public static JointTransform fromMatrixWithoutScale(OpenMatrix4f matrix) {
|
||||
return new JointTransform(matrix.toTranslationVector(), matrix.toQuaternion(), new Vec3f(1.0F, 1.0F, 1.0F));
|
||||
}
|
||||
|
||||
public static JointTransform translation(Vec3f vec) {
|
||||
return JointTransform.translationRotation(vec, new Quaternionf(0.0F, 0.0F, 0.0F, 1.0F));
|
||||
}
|
||||
|
||||
public static JointTransform rotation(Quaternionf quat) {
|
||||
return JointTransform.translationRotation(new Vec3f(0.0F, 0.0F, 0.0F), quat);
|
||||
}
|
||||
|
||||
public static JointTransform scale(Vec3f vec) {
|
||||
return new JointTransform(new Vec3f(0.0F, 0.0F, 0.0F), new Quaternionf(0.0F, 0.0F, 0.0F, 1.0F), vec);
|
||||
}
|
||||
|
||||
public static JointTransform fromMatrix(OpenMatrix4f matrix) {
|
||||
return new JointTransform(matrix.toTranslationVector(), matrix.toQuaternion(), matrix.toScaleVector());
|
||||
}
|
||||
|
||||
public static JointTransform translationRotation(Vec3f vec, Quaternionf quat) {
|
||||
return new JointTransform(vec, quat, new Vec3f(1.0F, 1.0F, 1.0F));
|
||||
}
|
||||
|
||||
public static JointTransform mul(JointTransform left, JointTransform right, MatrixOperation operation) {
|
||||
return JointTransform.fromMatrix(operation.mul(left.toMatrix(), right.toMatrix(), null));
|
||||
}
|
||||
|
||||
public static JointTransform fromPrimitives(float locX, float locY, float locZ, float quatX, float quatY, float quatZ, float quatW, float scaX, float scaY, float scaZ) {
|
||||
return new JointTransform(new Vec3f(locX, locY, locZ), new Quaternionf(quatX, quatY, quatZ, quatW), new Vec3f(scaX, scaY, scaZ));
|
||||
}
|
||||
|
||||
public static JointTransform empty() {
|
||||
return new JointTransform(new Vec3f(0.0F, 0.0F, 0.0F), new Quaternionf(0.0F, 0.0F, 0.0F, 1.0F), new Vec3f(1.0F, 1.0F, 1.0F));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.armature.types;
|
||||
|
||||
import com.tiedup.remake.rig.armature.Joint;
|
||||
|
||||
/**
|
||||
* This class is not being used by Epic Fight, but is left to meet various purposes of developers
|
||||
* Also presents developers which joints are necessary when an armature would be Human-like
|
||||
*/
|
||||
public interface HumanLikeArmature extends ToolHolderArmature {
|
||||
public Joint leftHandJoint();
|
||||
public Joint rightHandJoint();
|
||||
public Joint leftArmJoint();
|
||||
public Joint rightArmJoint();
|
||||
public Joint leftLegJoint();
|
||||
public Joint rightLegJoint();
|
||||
public Joint leftThighJoint();
|
||||
public Joint rightThighJoint();
|
||||
public Joint headJoint();
|
||||
}
|
||||
Reference in New Issue
Block a user