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{
data.hVelActive.clear(); // TODO: test/check !
data.clearActiveHVel(); // TODO: test/check !
}
final boolean sprinting = time <= data.timeSprinting + cc.sprintingGrace;

View File

@ -1,9 +1,6 @@
package fr.neatmonster.nocheatplus.checks.moving;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.bukkit.Location;
@ -123,10 +120,8 @@ public class MovingData extends ACheckData {
public double verticalFreedom;
public double verticalVelocity;
public int verticalVelocityUsed = 0;
/** Active velocity entries (horizontal distance). */
public final List<Velocity> hVelActive = new LinkedList<Velocity>();
/** Queued velocity entries (horizontal distance). */
public final List<Velocity> hVelQueued = new LinkedList<Velocity>();
/** Horizontal velocity modeled as an axis (always positive) */
private final AxisVelocity hVel = new AxisVelocity();
// Coordinates.
/** Last from coordinates. */
@ -524,16 +519,14 @@ public class MovingData extends ACheckData {
* @param vel
*/
public void addHorizontalVelocity(final Velocity vel) {
// TODO: Might merge entries !
hVelQueued.add(vel);
hVel.add(vel);
}
/**
* Currently only applies to horizontal velocity.
*/
public void removeAllVelocity() {
hVelActive.clear();
hVelQueued.clear();
hVel.clear();
}
/**
@ -542,28 +535,22 @@ public class MovingData extends ACheckData {
* @param tick All velocity added before this tick gets removed.
*/
public void removeInvalidVelocity(final int tick) {
// TODO: Also merge entries here, or just on adding?
Iterator<Velocity> it;
// Active.
it = hVelActive.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 = hVelQueued.iterator();
while (it.hasNext()) {
final Velocity vel = it.next();
if (vel.actCount <= 0 || vel.tick < tick) {
// System.out.println("Invalidate queued: " + vel);
it.remove();
}
}
hVel.removeInvalid(tick);
}
/**
* Clear only active horizontal velocity.
*/
public void clearActiveHVel() {
hVel.clearActive();
}
public boolean hasActiveHVel() {
return hVel.hasActive();
}
public boolean hasQueuedHVel() {
return hVel.hasQueued();
}
/**
@ -571,44 +558,31 @@ public class MovingData extends ACheckData {
*/
public void velocityTick() {
// Horizontal velocity (intermediate concept).
// 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 : 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 --;
}
hVel.tick();
// Vertical velocity (old concept).
if (verticalVelocity <= 0.09D) {
verticalVelocityUsed ++;
verticalVelocityCounter--;
}
else if (verticalVelocityCounter > 0) {
verticalVelocityUsed ++;
verticalFreedom += verticalVelocity;
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 .
} else if (verticalFreedom > 0.001D) {
if (verticalVelocityUsed == 1 && verticalVelocity > 1.0) {
// Workarounds.
verticalVelocityUsed = 0;
verticalVelocity = 0;
verticalFreedom = 0;
}
else{
// Counter has run out, now reduce the vertical freedom over time.
verticalVelocityUsed ++;
verticalFreedom *= 0.93D;
}
}
if (verticalVelocity <= 0.09D) {
verticalVelocityUsed ++;
verticalVelocityCounter--;
}
else if (verticalVelocityCounter > 0) {
verticalVelocityUsed ++;
verticalFreedom += verticalVelocity;
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 .
} else if (verticalFreedom > 0.001D) {
if (verticalVelocityUsed == 1 && verticalVelocity > 1.0) {
// Workarounds.
verticalVelocityUsed = 0;
verticalVelocity = 0;
verticalFreedom = 0;
}
else{
// Counter has run out, now reduce the vertical freedom over time.
verticalVelocityUsed ++;
verticalFreedom *= 0.93D;
}
}
}
/**
@ -616,12 +590,7 @@ public class MovingData extends ACheckData {
* @return
*/
public double getHorizontalFreedom() {
// TODO: model/calculate it as accurate as possible...
double f = 0;
for (final Velocity vel : hVelActive) {
f += vel.value;
}
return f;
return hVel.getFreedom();
}
/**
@ -633,19 +602,22 @@ public class MovingData extends ACheckData {
* @return
*/
public double useHorizontalVelocity(final double amount) {
final Iterator<Velocity> it = hVelQueued.iterator();
double used = 0;
while (it.hasNext()) {
final Velocity vel = it.next();
used += vel.value;
hVelActive.add(vel);
it.remove();
if (used >= amount) {
break;
}
}
// TODO: Add to sum.
return used;
return hVel.use(amount);
}
/**
* Debugging.
* @param builder
*/
public void addHorizontalVelocity(final StringBuilder builder) {
if (hVel.hasActive()) {
builder.append("\n" + " horizontal velocity (active):");
hVel.addActive(builder);
}
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.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
@ -205,7 +204,7 @@ public class SurvivalFly extends Check {
hFreedom = res[2];
}
else{
data.hVelActive.clear();
data.clearActiveHVel();
hFreedom = 0.0;
if (resetFrom && data.bunnyhopDelay <= 6) {
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 !?).
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.)
// TODO: speed effects ?
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?
// Invalidate used horizontal velocity.
// System.out.println("*** INVALIDATE ON SPEED");
data.hVelActive.clear();
data.clearActiveHVel();
// if (data.horizontalVelocityUsed > cc.velocityGraceTicks) {
// data.horizontalFreedom = 0;
// data.horizontalVelocityCounter = 0;
@ -1408,14 +1407,7 @@ public class SurvivalFly extends Check {
// 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);
// }
if (!data.hVelActive.isEmpty()) {
builder.append("\n" + " horizontal velocity (active):");
addVeloctiy(builder, data.hVelActive);
}
if (!data.hVelQueued.isEmpty()) {
builder.append("\n" + " horizontal velocity (queued):");
addVeloctiy(builder, data.hVelQueued);
}
data.addHorizontalVelocity(builder);
if (!resetFrom && !resetTo) {
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());
}
private void addVeloctiy(final StringBuilder builder, final List<Velocity> entries) {
for (final Velocity vel: entries) {
builder.append(" ");
builder.append(vel);
}
}
}