use of com.abilityapi.sequenceapi.SequenceContext in project guardian by ichorpowered.
the class FlightCheck method getSequence.
@Override
public SequenceBlueprint<Event> getSequence(final Detection detection) {
final Double analysisTime = detection.getContentContainer().get(ContentKeys.ANALYSIS_TIME).orElse(GuardianValue.empty()).getDirect().orElse(0d) / 0.05;
final Double analysisIntercept = detection.getContentContainer().get(ContentKeys.ANALYSIS_INTERCEPT).orElse(GuardianValue.empty()).getDirect().orElse(0d);
final Double minimumTickRate = detection.getContentContainer().get(ContentKeys.ANALYSIS_MINIMUM_TICK).orElse(GuardianValue.empty()).getDirect().orElse(0d) / 0.05;
final Double maximumTickRate = detection.getContentContainer().get(ContentKeys.ANALYSIS_MAXIMUM_TICK).orElse(GuardianValue.empty()).getDirect().orElse(0d) / 0.05;
return new GuardianSequenceBuilder().capture(new ControlCapture(detection.getPlugin(), detection)).capture(new AltitudeCapture(detection.getPlugin(), detection)).capture(new MaterialCapture(detection.getPlugin(), detection)).capture(new PotionEffectCapture(detection.getPlugin(), detection)).observe(MoveEntityEvent.class).after().delay(analysisTime.intValue()).condition(sequenceContext -> {
final GuardianPlayerEntry<Player> entityEntry = sequenceContext.get(CommonContextKeys.ENTITY_ENTRY);
final Summary summary = sequenceContext.get(CommonContextKeys.SUMMARY);
final GuardianCaptureRegistry captureRegistry = sequenceContext.get(CommonContextKeys.CAPTURE_REGISTRY);
final long lastActionTime = sequenceContext.get(CommonContextKeys.LAST_ACTION_TIME);
summary.set(SequenceReport.class, new SequenceReport(false, Origin.source(sequenceContext.getRoot()).owner(entityEntry).build()));
if (!entityEntry.getEntity(Player.class).isPresent())
return false;
final Player player = entityEntry.getEntity(Player.class).get();
/*
* Capture Collection
*/
final CaptureContainer captureContainer = captureRegistry.getContainer();
final Optional<Location> initial = captureContainer.get(GuardianSequence.INITIAL_LOCATION);
final Optional<Double> effectLiftAmplifier = captureContainer.get(PotionEffectCapture.VERTICAL_SPEED_MODIFIER);
final Optional<Double> materialSpeedAmplifier = captureContainer.get(MaterialCapture.SPEED_MODIFIER);
final Optional<Double> altitude = captureContainer.get(AltitudeCapture.RELATIVE_ALTITUDE);
final Optional<Map<String, Integer>> materialStateTicks = captureContainer.get(MaterialCapture.ACTIVE_MATERIAL_TICKS);
final Optional<Map<String, Integer>> controlStateTicks = captureContainer.get(ControlCapture.ACTIVE_CONTROL_TICKS);
if (!initial.isPresent() || !materialSpeedAmplifier.isPresent() || !altitude.isPresent() || !materialStateTicks.isPresent())
return false;
final Value<Double> playerBoxWidth = ContentUtil.getFirst(ContentKeys.BOX_PLAYER_WIDTH, entityEntry, detection.getContentContainer()).orElse(GuardianValue.empty());
final Value<Double> playerBoxHeight = ContentUtil.getFirst(ContentKeys.BOX_PLAYER_HEIGHT, entityEntry, detection.getContentContainer()).orElse(GuardianValue.empty());
final Value<Double> playerBoxSafety = ContentUtil.getFirst(ContentKeys.BOX_PLAYER_SAFETY, entityEntry, detection.getContentContainer()).orElse(GuardianValue.empty());
final double playerWidth = playerBoxWidth.getDirect().orElse(1.2) + playerBoxSafety.getDirect().orElse(0.05);
final double playerHeight = playerBoxHeight.getDirect().orElse(1.8) + playerBoxSafety.getDirect().orElse(0.05);
final boolean isSneaking = player.get(Keys.IS_SNEAKING).isPresent() && player.get(Keys.IS_SNEAKING).get();
final BoundingBox playerBox = WorldUtil.getBoundingBox(playerWidth, isSneaking ? (playerHeight - 0.15) : playerHeight);
long current = System.currentTimeMillis();
// Gets the average time between now and the last action.
double averageActionTime = ((current - lastActionTime) / 1000) / 0.05;
if (averageActionTime < minimumTickRate) {
detection.getLogger().warn("The server may be overloaded. A check could not be completed.");
return false;
} else if (averageActionTime > maximumTickRate) {
return false;
}
if (player.get(Keys.VEHICLE).isPresent() || (player.get(Keys.IS_FLYING).isPresent() && player.get(Keys.IS_FLYING).get()) || player.getLocation().getY() < 1)
return false;
final double intercept = analysisIntercept + (effectLiftAmplifier.orElse(0d) / analysisTime);
// Gets the players vertical displacement in the world.
final double verticalDisplacement = ((player.getLocation().getY() - initial.get().getY()) == 0) ? intercept : player.getLocation().getY() - initial.get().getY();
// Gets the players relative altitude to the ground.
final double averageAltitude = altitude.get() / averageActionTime;
// Gets the time the player is on solid ground or a liquid.
final int solidMaterialTime = materialStateTicks.get().get(MaterialCapture.SOLID);
final int liquidMaterialTime = materialStateTicks.get().get(MaterialCapture.LIQUID);
// Gets the time the player is using flight.
final int flightControlTime = controlStateTicks.get().get(ControlCapture.FLY);
if (verticalDisplacement <= 1 || averageAltitude <= 1 || WorldUtil.containsBlocksUnder(player.getLocation(), playerBox, 1d) || solidMaterialTime > 1 || liquidMaterialTime > 1 || flightControlTime > 1)
return false;
if (((verticalDisplacement / averageAltitude) + averageAltitude) > intercept) {
// ------------------------- DEBUG -----------------------------
System.out.println(player.getName() + " has been caught using fly hacks. (" + ((verticalDisplacement / averageAltitude) + averageAltitude) + ")");
// -------------------------------------------------------------
SequenceReport report = new SequenceReport(true, Origin.source(sequenceContext.getRoot()).owner(entityEntry).build());
report.put("type", "Flight");
report.put("information", Collections.singletonList("Gained altitude over " + ((verticalDisplacement / averageAltitude) + averageAltitude) + "."));
report.put("initial_location", initial.get());
report.put("final_location", player.getLocation());
report.put("severity", ((verticalDisplacement / averageAltitude) + averageAltitude) / (verticalDisplacement + averageAltitude));
summary.set(SequenceReport.class, report);
return true;
}
return false;
}, ConditionType.NORMAL).build(SequenceContext.builder().owner(detection).root(this).build());
}
use of com.abilityapi.sequenceapi.SequenceContext in project guardian by ichorpowered.
the class GuardianSequence method applyObserve.
@Override
public boolean applyObserve(final Event event, final SequenceContext sequenceContext) {
final PlayerEntry entityEntry = sequenceContext.get(CommonContextKeys.ENTITY_ENTRY);
final Player player = entityEntry.getEntity(Player.class).orElse(Sponge.getServer().getPlayer(entityEntry.getUniqueId()).orElse(null));
if (player == null)
return false;
final SequenceContext mergedContext = SequenceContext.from(sequenceContext).custom(CommonContextKeys.LAST_ACTION_TIME, super.getLastActionTime()).custom(CommonContextKeys.CAPTURE_REGISTRY, this.captureRegistry).custom(CommonContextKeys.SUMMARY, this.summary).build();
if (this.getState().equals(State.INACTIVE)) {
this.captureRegistry.getContainer().offerIfEmpty(GuardianValue.builder(GuardianSequence.INITIAL_LOCATION).defaultElement(player.getLocation()).element(player.getLocation()).create());
}
return super.applyObserve(event, mergedContext);
}
use of com.abilityapi.sequenceapi.SequenceContext in project guardian by ichorpowered.
the class GuardianSequence method applyAfter.
@Override
public final Tristate applyAfter(SequenceContext sequenceContext) {
final PlayerEntry entityEntry = sequenceContext.get(CommonContextKeys.ENTITY_ENTRY);
final Player player = entityEntry.getEntity(Player.class).orElse(Sponge.getServer().getPlayer(entityEntry.getUniqueId()).orElse(null));
if (player == null)
return Tristate.FALSE;
final SequenceContext mergedContext = SequenceContext.from(sequenceContext).custom(CommonContextKeys.LAST_ACTION_TIME, super.getLastActionTime()).custom(CommonContextKeys.CAPTURE_REGISTRY, this.captureRegistry).custom(CommonContextKeys.SUMMARY, this.summary).build();
if (this.getState().equals(State.INACTIVE)) {
this.captureRegistry.getContainer().offerIfEmpty(GuardianValue.builder(GuardianSequence.INITIAL_LOCATION).defaultElement(player.getLocation()).element(player.getLocation()).create());
}
return super.applyAfter(mergedContext);
}
use of com.abilityapi.sequenceapi.SequenceContext in project guardian by ichorpowered.
the class GuardianSequenceBuilder method build.
@Override
public final SequenceBlueprint<Event> build(final SequenceContext buildContext) {
return new SequenceBlueprint<Event>() {
@Override
public final Sequence<Event> create(final Event rootEvent, final SequenceContext createContext) {
final SequenceContext modifiedContext = SequenceContext.from(createContext).custom(CommonContextKeys.TRIGGER_CLASS, this.getTrigger()).custom(CommonContextKeys.TRIGGER_INSTANCE, rootEvent).merge(buildContext).build();
final GuardianCaptureRegistry captureRegistry = new GuardianCaptureRegistry(modifiedContext.get(CommonContextKeys.ENTITY_ENTRY));
GuardianSequenceBuilder.this.captures.forEach(capture -> captureRegistry.put(modifiedContext.getId(), capture.getClass(), capture));
return new GuardianSequence(rootEvent, modifiedContext, this, captureRegistry, GuardianSequenceBuilder.this.actions);
}
@Override
public final Class<? extends Event> getTrigger() {
if (GuardianSequenceBuilder.this.actions.isEmpty())
throw new NoSuchElementException("Sequence could not be established without an initial observer action.");
if (GuardianSequenceBuilder.this.actions.get(0) instanceof ObserverAction) {
return ((ObserverAction<Event>) GuardianSequenceBuilder.this.actions.get(0)).getEventClass();
} else
throw new ClassCastException("Sequence could not be established without an initial observer action.");
}
@Override
public SequenceContext getContext() {
return buildContext;
}
@Override
public int hashCode() {
return Objects.hash(buildContext.getOwner(), buildContext.getRoot(), getTrigger());
}
@Override
public boolean equals(final Object other) {
if (this == other)
return true;
if (other == null || !(other instanceof SequenceBlueprint<?>))
return false;
final SequenceBlueprint<?> that = (SequenceBlueprint<?>) other;
return Objects.equals(buildContext.getOwner(), that.getContext().getOwner()) && Objects.equals(buildContext.getRoot(), that.getContext().getRoot()) && Objects.equals(getTrigger(), that.getTrigger());
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("owner", buildContext.getOwner()).add("root", buildContext.getRoot()).add("trigger", getTrigger()).toString();
}
};
}
use of com.abilityapi.sequenceapi.SequenceContext in project guardian by ichorpowered.
the class HorizontalSpeedCheck method getSequence.
@Override
public SequenceBlueprint<Event> getSequence(final Detection detection) {
final Double analysisTime = detection.getContentContainer().get(ContentKeys.ANALYSIS_TIME).orElse(GuardianValue.empty()).getDirect().orElse(0d) / 0.05;
final Double analysisIntercept = detection.getContentContainer().get(ContentKeys.ANALYSIS_INTERCEPT).orElse(GuardianValue.empty()).getDirect().orElse(0d);
final Double minimumTickRate = detection.getContentContainer().get(ContentKeys.ANALYSIS_MINIMUM_TICK).orElse(GuardianValue.empty()).getDirect().orElse(0d) / 0.05;
final Double maximumTickRate = detection.getContentContainer().get(ContentKeys.ANALYSIS_MAXIMUM_TICK).orElse(GuardianValue.empty()).getDirect().orElse(0d) / 0.05;
return new GuardianSequenceBuilder().capture(new ControlCapture(detection.getPlugin(), detection)).capture(new MaterialCapture(detection.getPlugin(), detection)).capture(new PotionEffectCapture(detection.getPlugin(), detection)).observe(MoveEntityEvent.class).after().delay(analysisTime.intValue()).condition(sequenceContext -> {
final GuardianPlayerEntry<Player> entityEntry = sequenceContext.get(CommonContextKeys.ENTITY_ENTRY);
final Summary summary = sequenceContext.get(CommonContextKeys.SUMMARY);
final GuardianCaptureRegistry captureRegistry = sequenceContext.get(CommonContextKeys.CAPTURE_REGISTRY);
final long lastActionTime = sequenceContext.get(CommonContextKeys.LAST_ACTION_TIME);
summary.set(SequenceReport.class, new SequenceReport(false, Origin.source(sequenceContext.getRoot()).owner(entityEntry).build()));
if (!entityEntry.getEntity(Player.class).isPresent())
return false;
final Player player = entityEntry.getEntity(Player.class).get();
/*
* Capture Collection
*/
final CaptureContainer captureContainer = captureRegistry.getContainer();
final Optional<Location> initial = captureContainer.get(GuardianSequence.INITIAL_LOCATION);
final Optional<Double> effectSpeedAmplifier = captureContainer.get(PotionEffectCapture.HORIZONTAL_SPEED_MODIFIER);
final Optional<Double> materialSpeedAmplifier = captureContainer.get(MaterialCapture.SPEED_MODIFIER);
final Optional<Double> horizontalOffset = captureContainer.get(ControlCapture.HORIZONTAL_DISTANCE);
final Optional<Map<String, Integer>> activeControls = captureContainer.get(ControlCapture.ACTIVE_CONTROL_TICKS);
if (!initial.isPresent() || !materialSpeedAmplifier.isPresent() || !horizontalOffset.isPresent())
return false;
long current = System.currentTimeMillis();
// Gets the average between now and the last action.
final double averageActionTime = ((current - lastActionTime) / 1000) / 0.05;
if (averageActionTime < minimumTickRate) {
detection.getLogger().warn("The server may be overloaded. A check could not be completed.");
return false;
} else if (averageActionTime > maximumTickRate) {
return false;
}
if (player.get(Keys.VEHICLE).isPresent())
return false;
double intercept = analysisIntercept + (effectSpeedAmplifier.orElse(0d) / analysisTime);
final Optional<Map.Entry<String, Integer>> validControlTicks = activeControls.get().entrySet().stream().max(Comparator.comparingInt(Map.Entry::getValue));
// Gets the players horizontal displacement in the world.
final double horizontalDisplacement = Math.abs((player.getLocation().getX() - initial.get().getX()) + (player.getLocation().getZ() - initial.get().getZ()));
// Gets the percentage of the displacement that is the most important.
final double maximumHorizontalDisplacement = validControlTicks.map(entry -> horizontalDisplacement * (entry.getValue() / averageActionTime)).orElse(horizontalDisplacement);
// Gets the players maximum horizontal speed in the world, for this analysis.
final double maximumHorizontalSpeed = (((horizontalOffset.get() * materialSpeedAmplifier.get()) / 2) / averageActionTime) + intercept;
if (horizontalDisplacement <= 1 || maximumHorizontalDisplacement < 1 || maximumHorizontalSpeed < 1)
return false;
if (maximumHorizontalDisplacement > maximumHorizontalSpeed) {
// ------------------------- DEBUG -----------------------------
System.out.println(player.getName() + " has been caught using horizontal speed hacks. (" + (maximumHorizontalDisplacement - maximumHorizontalSpeed) + ")");
// -------------------------------------------------------------
SequenceReport report = new SequenceReport(true, Origin.source(sequenceContext.getRoot()).owner(entityEntry).build());
report.put("type", "Horizontal Speed");
report.put("information", Collections.singletonList("Overshot maximum movement by " + (maximumHorizontalDisplacement - maximumHorizontalSpeed) + "."));
report.put("initial_location", initial.get());
report.put("final_location", player.getLocation());
report.put("severity", (maximumHorizontalDisplacement - maximumHorizontalSpeed) / maximumHorizontalDisplacement);
summary.set(SequenceReport.class, report);
return true;
}
return false;
}, ConditionType.NORMAL).build(SequenceContext.builder().owner(detection).root(this).build());
}
Aggregations