Refactor rotation more

This commit is contained in:
fullwall 2022-04-25 22:29:26 +08:00
parent 8694603c85
commit 234c99b2af
3 changed files with 241 additions and 113 deletions

View File

@ -42,7 +42,7 @@ import net.citizensnpcs.trait.OcelotModifiers;
import net.citizensnpcs.trait.Poses;
import net.citizensnpcs.trait.Powered;
import net.citizensnpcs.trait.RabbitType;
import net.citizensnpcs.trait.RotationTrait;
import net.citizensnpcs.trait.SmoothRotationTrait;
import net.citizensnpcs.trait.Saddle;
import net.citizensnpcs.trait.ScoreboardTrait;
import net.citizensnpcs.trait.ScriptTrait;
@ -89,7 +89,7 @@ public class CitizensTraitFactory implements TraitFactory {
registerTrait(TraitInfo.create(Poses.class));
registerTrait(TraitInfo.create(Powered.class));
registerTrait(TraitInfo.create(RabbitType.class));
registerTrait(TraitInfo.create(RotationTrait.class));
registerTrait(TraitInfo.create(SmoothRotationTrait.class));
registerTrait(TraitInfo.create(Saddle.class));
registerTrait(TraitInfo.create(ScoreboardTrait.class));
registerTrait(TraitInfo.create(ScriptTrait.class));

View File

@ -1,111 +0,0 @@
package net.citizensnpcs.trait;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
@TraitName("rotationtrait")
public class RotationTrait extends Trait {
protected float maxPitchRotationPerTick = 10;
protected float maxYawRotationPerTick = 40;
protected boolean rotating;
protected double tx;
protected double ty;
protected double tz;
public RotationTrait() {
super("rotationtrait");
}
private double getEyeY() {
return NMS.getHeight(npc.getEntity());
}
protected float getTargetPitchDifference() {
double dx = tx - getX();
double dy = ty - (getY() + getEyeY());
double dz = tz - getZ();
double diag = Math.sqrt((float) (dx * dx + dz * dz));
return (float) -Math.toDegrees(Math.atan2(dy, diag));
}
protected float getTargetYawDifference() {
return (float) Math.toDegrees(Math.atan2(tz - getZ(), tx - getX())) - 90.0F;
}
private double getX() {
return npc.getStoredLocation().getX();
}
private double getY() {
return npc.getStoredLocation().getY();
}
private double getZ() {
return npc.getStoredLocation().getZ();
}
public void rotateToFace(Entity target) {
Location loc = target.getLocation();
loc.setY(loc.getY() + NMS.getHeight(target));
rotateToFace(loc);
}
public void rotateToFace(Location target) {
this.tx = target.getX();
this.ty = target.getY();
this.tz = target.getZ();
this.rotating = true;
}
protected float rotateTowards(float target, float current, float maxRotPerTick) {
float diff = Util.clamp(current - target);
return target + clamp(diff, -maxRotPerTick, maxRotPerTick);
}
@Override
public void run() {
if (!npc.isSpawned() || npc.getNavigator().isNavigating()) {
// npc.yHeadRot = Mth.rotateIfNecessary(npc.yHeadRot, npc.yBodyRot, 75);
return;
}
if (true) {
// npc.setXRot(0.0F);
}
if (this.rotating) {
this.rotating = false;
NMS.setHeadYaw(npc.getEntity(), Util.clamp(rotateTowards(NMS.getHeadYaw(npc.getEntity()),
getTargetYawDifference(), this.maxYawRotationPerTick)));
float d = Util.clamp(NMS.getHeadYaw(npc.getEntity()) - 40);
if (d > NMS.getYaw(npc.getEntity())) {
NMS.setBodyYaw(npc.getEntity(), d);
}
if (d != NMS.getYaw(npc.getEntity())) {
d = NMS.getHeadYaw(npc.getEntity()) + 40;
while (d >= 180F) {
d -= 360F;
}
while (d < -180F) {
d += 360F;
}
if (d < NMS.getYaw(npc.getEntity())) {
NMS.setBodyYaw(npc.getEntity(), d);
}
}
NMS.setPitch(npc.getEntity(), rotateTowards(npc.getStoredLocation().getPitch(), getTargetPitchDifference(),
this.maxPitchRotationPerTick));
}
}
public static float clamp(float var0, float var1, float var2) {
if (var0 < var1) {
return var1;
} else {
return var0 > var2 ? var2 : var0;
}
}
}

View File

@ -0,0 +1,239 @@
package net.citizensnpcs.trait;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.util.Vector;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.persistence.Persistable;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
@TraitName("smoothrotationtrait")
public class SmoothRotationTrait extends Trait {
@Persist
private Float defaultPitch;
@Persist(reify = true)
private final RotationParams globalParameters = new RotationParams();
private final SmoothRotationSession globalSession = new SmoothRotationSession(globalParameters);
public SmoothRotationTrait() {
super("smoothrotationtrait");
}
private double getEyeY() {
return NMS.getHeight(npc.getEntity());
}
public RotationParams getGlobalParameters() {
return globalParameters;
}
private double getX() {
return npc.getStoredLocation().getX();
}
private double getY() {
return npc.getStoredLocation().getY();
}
private double getZ() {
return npc.getStoredLocation().getZ();
}
public void rotateToFace(Entity target) {
Location loc = target.getLocation();
loc.setY(loc.getY() + NMS.getHeight(target));
rotateToFace(loc);
}
public void rotateToFace(Location target) {
this.globalSession.setTarget(target);
}
public void rotateToHave(float yaw, float pitch) {
Vector vector = new Vector(Math.cos(yaw) * Math.cos(pitch), Math.sin(pitch), Math.sin(yaw) * Math.cos(pitch))
.normalize();
rotateToFace(npc.getEntity().getLocation().clone().add(vector));
}
@Override
public void run() {
if (!npc.isSpawned() || npc.getNavigator().isNavigating()) {
// npc.yHeadRot = Mth.rotateIfNecessary(npc.yHeadRot, npc.yBodyRot, 75);
return;
}
if (!globalSession.hasTarget()) {
return;
}
EntityRotation rot = new EntityRotation(npc.getEntity());
globalSession.run(rot);
if (!globalSession.hasTarget()) {
rot.bodyYaw = rot.headYaw;
}
rot.apply(npc.getEntity());
}
public void setDefaultPitch(float pitch) {
defaultPitch = pitch;
}
public static class EntityRotation {
public float bodyYaw, headYaw, pitch;
public EntityRotation(Entity entity) {
this.bodyYaw = NMS.getYaw(entity);
this.headYaw = NMS.getHeadYaw(entity);
this.pitch = entity.getLocation().getPitch();
}
public void apply(Entity entity) {
NMS.setBodyYaw(entity, bodyYaw);
NMS.setHeadYaw(entity, headYaw);
NMS.setPitch(entity, pitch);
}
}
public static class RotationParams implements Persistable {
private boolean headOnly = false;
private boolean immediate = false;
private float maxPitchPerTick = 10;
private float maxYawPerTick = 40;
private final float[] pitchRange = { 0, 0 };
private final float[] yawRange = { 0, 0 };
public RotationParams headOnly(boolean headOnly) {
this.headOnly = headOnly;
return this;
}
public RotationParams immediate(boolean immediate) {
this.immediate = immediate;
return this;
}
@Override
public void load(DataKey key) {
if (key.keyExists("headOnly")) {
headOnly = key.getBoolean("headOnly");
}
if (key.keyExists("immediate")) {
immediate = key.getBoolean("immediate");
}
if (key.keyExists("maxPitchPerTick")) {
maxPitchPerTick = (float) key.getDouble("maxPitchPerTick");
}
if (key.keyExists("maxYawPerTick")) {
maxYawPerTick = (float) key.getDouble("maxYawPerTick");
}
}
public RotationParams maxPitchPerTick(float val) {
this.maxPitchPerTick = val;
return this;
}
public RotationParams maxYawPerTick(float val) {
this.maxYawPerTick = val;
return this;
}
public float rotateHeadYawTowards(int t, float yaw, float targetYaw) {
return rotateTowards(yaw, targetYaw, maxYawPerTick);
}
public float rotatePitchTowards(int t, float pitch, float targetPitch) {
return rotateTowards(pitch, targetPitch, maxPitchPerTick);
}/*
* public Vector3 SuperSmoothVector3Lerp( Vector3 pastPosition, Vector3 pastTargetPosition, Vector3 targetPosition, float time, float speed ){
Vector3 f = pastPosition - pastTargetPosition + (targetPosition - pastTargetPosition) / (speed * time);
return targetPosition - (targetPosition - pastTargetPosition) / (speed*time) + f * Mathf.Exp(-speed*time);
}
*/
private float rotateTowards(float target, float current, float maxRotPerTick) {
float diff = Util.clamp(current - target);
return target + clamp(diff, -maxRotPerTick, maxRotPerTick);
}
@Override
public void save(DataKey key) {
if (headOnly) {
key.setBoolean("headOnly", headOnly);
}
if (immediate) {
key.setBoolean("immediate", immediate);
}
if (maxPitchPerTick != 10) {
key.setDouble("maxPitchPerTick", maxPitchPerTick);
}
if (maxYawPerTick != 40) {
key.setDouble("maxYawPerTick", maxYawPerTick);
}
}
}
public class SmoothRotationSession {
private final RotationParams params;
private int t;
private double tx, ty, tz;
public SmoothRotationSession(RotationParams params) {
this.params = params;
}
private float getTargetPitch() {
double dx = tx - getX();
double dy = ty - (getY() + getEyeY());
double dz = tz - getZ();
double diag = Math.sqrt((float) (dx * dx + dz * dz));
return (float) -Math.toDegrees(Math.atan2(dy, diag));
}
private float getTargetYaw() {
return (float) Math.toDegrees(Math.atan2(tz - getZ(), tx - getX())) - 90.0F;
}
public boolean hasTarget() {
return t >= 0;
}
public void run(EntityRotation rot) {
if (!hasTarget())
return;
rot.headYaw = params.immediate ? getTargetYaw()
: Util.clamp(params.rotateHeadYawTowards(t, rot.headYaw, getTargetYaw()));
if (!params.headOnly) {
float d = Util.clamp(rot.headYaw - 35);
if (d > rot.bodyYaw) {
rot.bodyYaw = d;
}
if (d != rot.bodyYaw) {
d = Util.clamp(rot.headYaw + 35);
if (d < rot.bodyYaw) {
rot.bodyYaw = d;
}
}
}
rot.pitch = params.immediate ? getTargetPitch() : params.rotatePitchTowards(t, rot.pitch, getTargetPitch());
t++;
if (Math.abs(rot.pitch - getTargetPitch()) + Math.abs(rot.headYaw - getTargetYaw()) < 0.1) {
t = -1;
}
}
public void setTarget(Location target) {
tx = target.getX();
ty = target.getY();
tz = target.getZ();
t = 0;
}
}
private static float clamp(float orig, float min, float max) {
return Math.max(min, Math.min(max, orig));
}
}