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)
279 lines
6.5 KiB
Java
279 lines
6.5 KiB
Java
/*
|
|
* 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.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;
|
|
}
|
|
}
|
|
}
|