Refactor horizontal velocity to use an abstract AxisVelocity class.

AxisVelocity will later represent per-axis velocity accounting for both
directions along an axis.

There have been no changes to the functionality, so it still only
accounts for positive values.
This commit is contained in:
asofold 2014-08-23 23:10:41 +02:00
parent 53c0d9584c
commit 32a11f021a
4 changed files with 222 additions and 108 deletions

View File

@ -0,0 +1,157 @@
package fr.neatmonster.nocheatplus.checks.moving;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Velocity accounting for one axis (positive + negative direction).
* @author dev1mc
*
*/
public class AxisVelocity {
private final List<Velocity> queued = new ArrayList<Velocity>();
private final List<Velocity> active = new ArrayList<Velocity>();
public void add(Velocity vel) {
// TODO: Merging behavior?
queued.add(vel);
}
public boolean hasActive() {
return !active.isEmpty();
}
public boolean hasQueued() {
return !queued.isEmpty();
}
/**
* Called for moving events, increase age of velocity, decrease amounts, check which entries are invalid. Both horizontal and vertical.
*/
public void tick() {
// Decrease counts for active.
// TODO: Actual friction. Could pass as an argument (special value for not to be used).
// TODO: Consider removing already invalidated here.
for (final Velocity vel : active) {
vel.valCount --;
vel.sum += vel.value;
vel.value *= 0.93; // vel.frictionFactor;
// (Altered entries should be kept, since they get used right away.)
}
// Decrease counts for queued.
final Iterator<Velocity> it = queued.iterator();
while (it.hasNext()) {
it.next().actCount --;
}
}
/**
* Remove all velocity entries that are invalid. Checks both active and queued.
* <br>(This does not catch invalidation by speed / direction changing.)
* @param tick All velocity added before this tick gets removed.
*/
public void removeInvalid(final int tick) {
// TODO: Also merge entries here, or just on adding?
Iterator<Velocity> it;
// Active.
it = active.iterator();
while (it.hasNext()) {
final Velocity vel = it.next();
// TODO: 0.001 can be stretched somewhere else, most likely...
// TODO: Somehow use tick here too (actCount, valCount)?
if (vel.valCount <= 0 || vel.value <= 0.001) {
// System.out.prsintln("Invalidate active: " + vel);
it.remove();
}
}
// Queued.
it = queued.iterator();
while (it.hasNext()) {
final Velocity vel = it.next();
if (vel.actCount <= 0 || vel.tick < tick) {
// System.out.println("Invalidate queued: " + vel);
it.remove();
}
}
}
/**
* Get the sum of active velocity values.
* @return
*/
public double getFreedom() {
// TODO: model/calculate it as accurate as possible...
double f = 0;
for (final Velocity vel : active) {
f += vel.value;
}
return f;
}
/**
* Use all queued velocity until at least amount is matched.
* Amount is the horizontal distance that is to be covered by velocity (active has already been checked).
* <br>
* If the modeling changes (max instead of sum or similar), then this will be affected.
* @param amount The amount used.
* @return
*/
public double use(final double amount) {
final Iterator<Velocity> it = queued.iterator();
double used = 0;
while (it.hasNext()) {
final Velocity vel = it.next();
used += vel.value;
active.add(vel);
it.remove();
if (used >= amount) {
break;
}
}
// TODO: Add to sum.
return used;
}
public void clearActive() {
active.clear();
}
/**
* Clear active and queued velocity entries.
*/
public void clear() {
queued.clear();
active.clear();
}
/**
* Debugging.
* @param builder
*/
public void AddQueued(StringBuilder builder) {
addVeloctiy(builder, queued);
}
/**
* Debugging.
* @param builder
*/
public void addActive(StringBuilder builder) {
addVeloctiy(builder, active);
}
/**
* Debugging.
* @param builder
* @param entries
*/
private void addVeloctiy(final StringBuilder builder, final List<Velocity> entries) {
for (final Velocity vel: entries) {
builder.append(" ");
builder.append(vel);
}
}
}

View File

@ -96,7 +96,7 @@ public class CreativeFly extends Check {
} }
} }
else{ else{
data.hVelActive.clear(); // TODO: test/check ! data.clearActiveHVel(); // TODO: test/check !
} }
final boolean sprinting = time <= data.timeSprinting + cc.sprintingGrace; final boolean sprinting = time <= data.timeSprinting + cc.sprintingGrace;

View File

@ -1,9 +1,6 @@
package fr.neatmonster.nocheatplus.checks.moving; package fr.neatmonster.nocheatplus.checks.moving;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.bukkit.Location; import org.bukkit.Location;
@ -123,10 +120,8 @@ public class MovingData extends ACheckData {
public double verticalFreedom; public double verticalFreedom;
public double verticalVelocity; public double verticalVelocity;
public int verticalVelocityUsed = 0; public int verticalVelocityUsed = 0;
/** Active velocity entries (horizontal distance). */ /** Horizontal velocity modeled as an axis (always positive) */
public final List<Velocity> hVelActive = new LinkedList<Velocity>(); private final AxisVelocity hVel = new AxisVelocity();
/** Queued velocity entries (horizontal distance). */
public final List<Velocity> hVelQueued = new LinkedList<Velocity>();
// Coordinates. // Coordinates.
/** Last from coordinates. */ /** Last from coordinates. */
@ -524,16 +519,14 @@ public class MovingData extends ACheckData {
* @param vel * @param vel
*/ */
public void addHorizontalVelocity(final Velocity vel) { public void addHorizontalVelocity(final Velocity vel) {
// TODO: Might merge entries ! hVel.add(vel);
hVelQueued.add(vel);
} }
/** /**
* Currently only applies to horizontal velocity. * Currently only applies to horizontal velocity.
*/ */
public void removeAllVelocity() { public void removeAllVelocity() {
hVelActive.clear(); hVel.clear();
hVelQueued.clear();
} }
/** /**
@ -542,28 +535,22 @@ public class MovingData extends ACheckData {
* @param tick All velocity added before this tick gets removed. * @param tick All velocity added before this tick gets removed.
*/ */
public void removeInvalidVelocity(final int tick) { public void removeInvalidVelocity(final int tick) {
// TODO: Also merge entries here, or just on adding? hVel.removeInvalid(tick);
Iterator<Velocity> it; }
// Active.
it = hVelActive.iterator(); /**
while (it.hasNext()) { * Clear only active horizontal velocity.
final Velocity vel = it.next(); */
// TODO: 0.001 can be stretched somewhere else, most likely... public void clearActiveHVel() {
// TODO: Somehow use tick here too (actCount, valCount)? hVel.clearActive();
if (vel.valCount <= 0 || vel.value <= 0.001) { }
// System.out.prsintln("Invalidate active: " + vel);
it.remove(); public boolean hasActiveHVel() {
} return hVel.hasActive();
} }
// Queued.
it = hVelQueued.iterator(); public boolean hasQueuedHVel() {
while (it.hasNext()) { return hVel.hasQueued();
final Velocity vel = it.next();
if (vel.actCount <= 0 || vel.tick < tick) {
// System.out.println("Invalidate queued: " + vel);
it.remove();
}
}
} }
/** /**
@ -571,44 +558,31 @@ public class MovingData extends ACheckData {
*/ */
public void velocityTick() { public void velocityTick() {
// Horizontal velocity (intermediate concept). // Horizontal velocity (intermediate concept).
// Decrease counts for active. hVel.tick();
// TODO: Actual friction. Could pass as an argument (special value for not to be used).
// TODO: Consider removing already invalidated here.
for (final Velocity vel : hVelActive) {
vel.valCount --;
vel.sum += vel.value;
vel.value *= 0.93; // vel.frictionFactor;
// (Altered entries should be kept, since they get used right away.)
}
// Decrease counts for queued.
final Iterator<Velocity> it = hVelQueued.iterator();
while (it.hasNext()) {
it.next().actCount --;
}
// Vertical velocity (old concept). // Vertical velocity (old concept).
if (verticalVelocity <= 0.09D) { if (verticalVelocity <= 0.09D) {
verticalVelocityUsed ++; verticalVelocityUsed ++;
verticalVelocityCounter--; verticalVelocityCounter--;
} }
else if (verticalVelocityCounter > 0) { else if (verticalVelocityCounter > 0) {
verticalVelocityUsed ++; verticalVelocityUsed ++;
verticalFreedom += verticalVelocity; verticalFreedom += verticalVelocity;
verticalVelocity = Math.max(0.0, verticalVelocity -0.09); verticalVelocity = Math.max(0.0, verticalVelocity -0.09);
// TODO: Consider using up counter ? / better use velocity entries / even better use x,y,z entries right away . // TODO: Consider using up counter ? / better use velocity entries / even better use x,y,z entries right away .
} else if (verticalFreedom > 0.001D) { } else if (verticalFreedom > 0.001D) {
if (verticalVelocityUsed == 1 && verticalVelocity > 1.0) { if (verticalVelocityUsed == 1 && verticalVelocity > 1.0) {
// Workarounds. // Workarounds.
verticalVelocityUsed = 0; verticalVelocityUsed = 0;
verticalVelocity = 0; verticalVelocity = 0;
verticalFreedom = 0; verticalFreedom = 0;
} }
else{ else{
// Counter has run out, now reduce the vertical freedom over time. // Counter has run out, now reduce the vertical freedom over time.
verticalVelocityUsed ++; verticalVelocityUsed ++;
verticalFreedom *= 0.93D; verticalFreedom *= 0.93D;
} }
} }
} }
/** /**
@ -616,12 +590,7 @@ public class MovingData extends ACheckData {
* @return * @return
*/ */
public double getHorizontalFreedom() { public double getHorizontalFreedom() {
// TODO: model/calculate it as accurate as possible... return hVel.getFreedom();
double f = 0;
for (final Velocity vel : hVelActive) {
f += vel.value;
}
return f;
} }
/** /**
@ -633,19 +602,22 @@ public class MovingData extends ACheckData {
* @return * @return
*/ */
public double useHorizontalVelocity(final double amount) { public double useHorizontalVelocity(final double amount) {
final Iterator<Velocity> it = hVelQueued.iterator(); return hVel.use(amount);
double used = 0; }
while (it.hasNext()) {
final Velocity vel = it.next(); /**
used += vel.value; * Debugging.
hVelActive.add(vel); * @param builder
it.remove(); */
if (used >= amount) { public void addHorizontalVelocity(final StringBuilder builder) {
break; if (hVel.hasActive()) {
} builder.append("\n" + " horizontal velocity (active):");
} hVel.addActive(builder);
// TODO: Add to sum. }
return used; if (hVel.hasQueued()) {
builder.append("\n" + " horizontal velocity (queued):");
hVel.AddQueued(builder);
}
} }
/** /**

View File

@ -2,7 +2,6 @@ package fr.neatmonster.nocheatplus.checks.moving;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
@ -205,7 +204,7 @@ public class SurvivalFly extends Check {
hFreedom = res[2]; hFreedom = res[2];
} }
else{ else{
data.hVelActive.clear(); data.clearActiveHVel();
hFreedom = 0.0; hFreedom = 0.0;
if (resetFrom && data.bunnyhopDelay <= 6) { if (resetFrom && data.bunnyhopDelay <= 6) {
data.bunnyhopDelay = 0; data.bunnyhopDelay = 0;
@ -224,7 +223,7 @@ public class SurvivalFly extends Check {
} }
// Prevent players from sprinting if they're moving backwards (allow buffers to cover up !?). // Prevent players from sprinting if they're moving backwards (allow buffers to cover up !?).
if (sprinting && data.lostSprintCount == 0 && !cc.assumeSprint && hDistance > walkSpeed && data.hVelActive.isEmpty()) { if (sprinting && data.lostSprintCount == 0 && !cc.assumeSprint && hDistance > walkSpeed && !data.hasActiveHVel()) {
// (Ignore some cases, in order to prevent false positives.) // (Ignore some cases, in order to prevent false positives.)
// TODO: speed effects ? // TODO: speed effects ?
if (TrigUtil.isMovingBackwards(xDistance, zDistance, from.getYaw()) && !player.hasPermission(Permissions.MOVING_SURVIVALFLY_SPRINTING)) { if (TrigUtil.isMovingBackwards(xDistance, zDistance, from.getYaw()) && !player.hasPermission(Permissions.MOVING_SURVIVALFLY_SPRINTING)) {
@ -475,7 +474,7 @@ public class SurvivalFly extends Check {
// TODO: Should there be other side conditions? // TODO: Should there be other side conditions?
// Invalidate used horizontal velocity. // Invalidate used horizontal velocity.
// System.out.println("*** INVALIDATE ON SPEED"); // System.out.println("*** INVALIDATE ON SPEED");
data.hVelActive.clear(); data.clearActiveHVel();
// if (data.horizontalVelocityUsed > cc.velocityGraceTicks) { // if (data.horizontalVelocityUsed > cc.velocityGraceTicks) {
// data.horizontalFreedom = 0; // data.horizontalFreedom = 0;
// data.horizontalVelocityCounter = 0; // data.horizontalVelocityCounter = 0;
@ -1408,14 +1407,7 @@ public class SurvivalFly extends Check {
// if (data.horizontalVelocityCounter > 0 || data.horizontalFreedom >= 0.001) { // if (data.horizontalVelocityCounter > 0 || data.horizontalFreedom >= 0.001) {
// builder.append("\n" + player.getName() + " horizontal freedom: " + StringUtil.fdec3.format(data.horizontalFreedom) + " (counter=" + data.horizontalVelocityCounter +"/used="+data.horizontalVelocityUsed); // builder.append("\n" + player.getName() + " horizontal freedom: " + StringUtil.fdec3.format(data.horizontalFreedom) + " (counter=" + data.horizontalVelocityCounter +"/used="+data.horizontalVelocityUsed);
// } // }
if (!data.hVelActive.isEmpty()) { data.addHorizontalVelocity(builder);
builder.append("\n" + " horizontal velocity (active):");
addVeloctiy(builder, data.hVelActive);
}
if (!data.hVelQueued.isEmpty()) {
builder.append("\n" + " horizontal velocity (queued):");
addVeloctiy(builder, data.hVelQueued);
}
if (!resetFrom && !resetTo) { if (!resetFrom && !resetTo) {
if (cc.survivalFlyAccountingV && data.vDistAcc.count() > data.vDistAcc.bucketCapacity()) builder.append("\n" + " vacc=" + data.vDistAcc.toInformalString()); if (cc.survivalFlyAccountingV && data.vDistAcc.count() > data.vDistAcc.bucketCapacity()) builder.append("\n" + " vacc=" + data.vDistAcc.toInformalString());
} }
@ -1430,11 +1422,4 @@ public class SurvivalFly extends Check {
System.out.print(builder.toString()); System.out.print(builder.toString());
} }
private void addVeloctiy(final StringBuilder builder, final List<Velocity> entries) {
for (final Velocity vel: entries) {
builder.append(" ");
builder.append(vel);
}
}
} }