mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2025-02-05 22:31:26 +01:00
[BLEEDING] Add simple hover check.
This commit is contained in:
parent
91420f9edf
commit
9850a0e3bb
@ -99,6 +99,11 @@ public class MovingConfig extends ACheckConfig {
|
|||||||
public final long survivalFlyVLFreeze;
|
public final long survivalFlyVLFreeze;
|
||||||
public final ActionList survivalFlyActions;
|
public final ActionList survivalFlyActions;
|
||||||
|
|
||||||
|
public final boolean sfHoverCheck;
|
||||||
|
public final int sfHoverTicks;
|
||||||
|
public final boolean sfHoverFallDamage;
|
||||||
|
public final double sfHoverViolation;
|
||||||
|
|
||||||
// Special tolerance values:
|
// Special tolerance values:
|
||||||
public final double noFallyOnGround;
|
public final double noFallyOnGround;
|
||||||
public final double yOnGround;
|
public final double yOnGround;
|
||||||
@ -151,6 +156,11 @@ public class MovingConfig extends ACheckConfig {
|
|||||||
survivalFlyVLFreeze = data.getLong(ConfPaths.MOVING_SURVIVALFLY_VLFREEZE, 2000L);
|
survivalFlyVLFreeze = data.getLong(ConfPaths.MOVING_SURVIVALFLY_VLFREEZE, 2000L);
|
||||||
survivalFlyActions = data.getOptimizedActionList(ConfPaths.MOVING_SURVIVALFLY_ACTIONS, Permissions.MOVING_SURVIVALFLY);
|
survivalFlyActions = data.getOptimizedActionList(ConfPaths.MOVING_SURVIVALFLY_ACTIONS, Permissions.MOVING_SURVIVALFLY);
|
||||||
|
|
||||||
|
sfHoverCheck = data.getBoolean(ConfPaths.MOVING_SURVIVALFLY_HOVER_CHECK);
|
||||||
|
sfHoverTicks = data.getInt(ConfPaths.MOVING_SURVIVALFLY_HOVER_TICKS);
|
||||||
|
sfHoverFallDamage = data.getBoolean(ConfPaths.MOVING_SURVIVALFLY_HOVER_FALLDAMAGE);
|
||||||
|
sfHoverViolation = data.getDouble(ConfPaths.MOVING_SURVIVALFLY_HOVER_SFVIOLATION);
|
||||||
|
|
||||||
yOnGround = data.getDouble(ConfPaths.MOVING_YONGROUND, 0.001, 2.0, 0.0626); // sqrt(1/256), see: NetServerHandler.
|
yOnGround = data.getDouble(ConfPaths.MOVING_YONGROUND, 0.001, 2.0, 0.0626); // sqrt(1/256), see: NetServerHandler.
|
||||||
noFallyOnGround = data.getDouble(ConfPaths.MOVING_NOFALL_YONGROUND, 0.001, 2.0, 0.3);
|
noFallyOnGround = data.getDouble(ConfPaths.MOVING_NOFALL_YONGROUND, 0.001, 2.0, 0.3);
|
||||||
// ystep is set to 0.45 by default, for stairs / steps.
|
// ystep is set to 0.45 by default, for stairs / steps.
|
||||||
|
@ -127,6 +127,8 @@ public class MovingData extends ACheckData {
|
|||||||
* Last valid y distance covered by a move. Integer.MAX_VALUE indicates "not set".
|
* Last valid y distance covered by a move. Integer.MAX_VALUE indicates "not set".
|
||||||
*/
|
*/
|
||||||
public double sfLastYDist = Double.MAX_VALUE;
|
public double sfLastYDist = Double.MAX_VALUE;
|
||||||
|
/** A value <0 means not hovering at all. */
|
||||||
|
public int sfHoverTicks = -1;
|
||||||
public int sfFlyOnIce;
|
public int sfFlyOnIce;
|
||||||
public long sfCobwebTime;
|
public long sfCobwebTime;
|
||||||
public double sfCobwebVL;
|
public double sfCobwebVL;
|
||||||
@ -157,6 +159,7 @@ public class MovingData extends ACheckData {
|
|||||||
clearNoFallData();
|
clearNoFallData();
|
||||||
sfHorizontalBuffer = 0;
|
sfHorizontalBuffer = 0;
|
||||||
toWasReset = fromWasReset = false; // TODO: true maybe
|
toWasReset = fromWasReset = false; // TODO: true maybe
|
||||||
|
sfHoverTicks = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -182,6 +185,7 @@ public class MovingData extends ACheckData {
|
|||||||
// keep jump phase.
|
// keep jump phase.
|
||||||
sfHorizontalBuffer = Math.min(0, sfHorizontalBuffer);
|
sfHorizontalBuffer = Math.min(0, sfHorizontalBuffer);
|
||||||
toWasReset = fromWasReset = false; // TODO: true maybe
|
toWasReset = fromWasReset = false; // TODO: true maybe
|
||||||
|
sfHoverTicks = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,13 +2,16 @@ package fr.neatmonster.nocheatplus.checks.moving;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Server;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.entity.Vehicle;
|
import org.bukkit.entity.Vehicle;
|
||||||
@ -42,6 +45,10 @@ import fr.neatmonster.nocheatplus.checks.combined.BedLeave;
|
|||||||
import fr.neatmonster.nocheatplus.checks.combined.Combined;
|
import fr.neatmonster.nocheatplus.checks.combined.Combined;
|
||||||
import fr.neatmonster.nocheatplus.checks.combined.CombinedData;
|
import fr.neatmonster.nocheatplus.checks.combined.CombinedData;
|
||||||
import fr.neatmonster.nocheatplus.compat.MCAccess;
|
import fr.neatmonster.nocheatplus.compat.MCAccess;
|
||||||
|
import fr.neatmonster.nocheatplus.components.IData;
|
||||||
|
import fr.neatmonster.nocheatplus.components.IHaveCheckType;
|
||||||
|
import fr.neatmonster.nocheatplus.components.IRemoveData;
|
||||||
|
import fr.neatmonster.nocheatplus.components.TickListener;
|
||||||
import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager;
|
import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager;
|
||||||
import fr.neatmonster.nocheatplus.permissions.Permissions;
|
import fr.neatmonster.nocheatplus.permissions.Permissions;
|
||||||
import fr.neatmonster.nocheatplus.utilities.BlockCache;
|
import fr.neatmonster.nocheatplus.utilities.BlockCache;
|
||||||
@ -73,7 +80,7 @@ import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
|
|||||||
*
|
*
|
||||||
* @see MovingEvent
|
* @see MovingEvent
|
||||||
*/
|
*/
|
||||||
public class MovingListener extends CheckListener{
|
public class MovingListener extends CheckListener implements TickListener, IRemoveData, IHaveCheckType{
|
||||||
|
|
||||||
private static final class MoveInfo{
|
private static final class MoveInfo{
|
||||||
public final BlockCache cache;
|
public final BlockCache cache;
|
||||||
@ -144,6 +151,8 @@ public class MovingListener extends CheckListener{
|
|||||||
*/
|
*/
|
||||||
private final Map<String, PlayerMoveEvent> processingEvents = new HashMap<String, PlayerMoveEvent>();
|
private final Map<String, PlayerMoveEvent> processingEvents = new HashMap<String, PlayerMoveEvent>();
|
||||||
|
|
||||||
|
private final Set<String> hoverTicks = new LinkedHashSet<String>(30);
|
||||||
|
|
||||||
public MovingListener() {
|
public MovingListener() {
|
||||||
super(CheckType.MOVING);
|
super(CheckType.MOVING);
|
||||||
}
|
}
|
||||||
@ -351,7 +360,8 @@ public class MovingListener extends CheckListener{
|
|||||||
final Player player = event.getPlayer();
|
final Player player = event.getPlayer();
|
||||||
|
|
||||||
// Store the event for monitor level checks.
|
// Store the event for monitor level checks.
|
||||||
processingEvents.put(player.getName(), event);
|
final String playerName = player.getName();
|
||||||
|
processingEvents.put(playerName, event);
|
||||||
|
|
||||||
// Ignore players in vehicles.
|
// Ignore players in vehicles.
|
||||||
if (player.isInsideVehicle()) return;
|
if (player.isInsideVehicle()) return;
|
||||||
@ -445,6 +455,16 @@ public class MovingListener extends CheckListener{
|
|||||||
&& cc.survivalFlyCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_SURVIVALFLY) && !player.hasPermission(Permissions.MOVING_SURVIVALFLY)){
|
&& cc.survivalFlyCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_SURVIVALFLY) && !player.hasPermission(Permissions.MOVING_SURVIVALFLY)){
|
||||||
// If he is handled by the survival fly check, execute it.
|
// If he is handled by the survival fly check, execute it.
|
||||||
newTo = survivalFly.check(player, pFrom, pTo, data, cc);
|
newTo = survivalFly.check(player, pFrom, pTo, data, cc);
|
||||||
|
if (newTo == null){
|
||||||
|
if (cc.sfHoverCheck && !data.toWasReset && !pTo.isOnGround()){
|
||||||
|
// Start counting ticks.
|
||||||
|
hoverTicks.add(playerName);
|
||||||
|
data.sfHoverTicks = 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
data.sfHoverTicks = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Check NoFall if no reset is done.
|
// Check NoFall if no reset is done.
|
||||||
if (cc.noFallCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_NOFALL) && !player.hasPermission(Permissions.MOVING_NOFALL)) {
|
if (cc.noFallCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_NOFALL) && !player.hasPermission(Permissions.MOVING_NOFALL)) {
|
||||||
if (passableTo != null){
|
if (passableTo != null){
|
||||||
@ -466,10 +486,15 @@ public class MovingListener extends CheckListener{
|
|||||||
else if (cc.creativeFlyCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_CREATIVEFLY)){
|
else if (cc.creativeFlyCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_CREATIVEFLY)){
|
||||||
// If the player is handled by the creative fly check, execute it.
|
// If the player is handled by the creative fly check, execute it.
|
||||||
newTo = creativeFly.check(player, pFrom, pTo, data, cc);
|
newTo = creativeFly.check(player, pFrom, pTo, data, cc);
|
||||||
|
data.sfHoverTicks = -1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
data.clearFlyData();
|
||||||
}
|
}
|
||||||
else data.clearFlyData();
|
|
||||||
}
|
}
|
||||||
else data.clearFlyData();
|
else{
|
||||||
|
data.clearFlyData();
|
||||||
|
}
|
||||||
|
|
||||||
if (newTo == null && cc.morePacketsCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_MOREPACKETS) && !player.hasPermission(Permissions.MOVING_MOREPACKETS)) {
|
if (newTo == null && cc.morePacketsCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_MOREPACKETS) && !player.hasPermission(Permissions.MOVING_MOREPACKETS)) {
|
||||||
// If he hasn't been stopped by any other check and is handled by the more packets check, execute it.
|
// If he hasn't been stopped by any other check and is handled by the more packets check, execute it.
|
||||||
@ -751,6 +776,7 @@ public class MovingListener extends CheckListener{
|
|||||||
Combined.resetYawRate(player, ref.getYaw(), System.currentTimeMillis(), true);
|
Combined.resetYawRate(player, ref.getYaw(), System.currentTimeMillis(), true);
|
||||||
data.resetTeleported();
|
data.resetTeleported();
|
||||||
processingEvents.remove(player.getName());
|
processingEvents.remove(player.getName());
|
||||||
|
hoverTicks.remove(player.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -924,6 +950,15 @@ public class MovingListener extends CheckListener{
|
|||||||
// TODO: re-think: more fine grained reset?
|
// TODO: re-think: more fine grained reset?
|
||||||
data.resetPositions(loc);
|
data.resetPositions(loc);
|
||||||
}
|
}
|
||||||
|
// Reset hover ticks until a better method is used.
|
||||||
|
if (MovingConfig.getConfig(player).sfHoverCheck){
|
||||||
|
// Start as if hovering already.
|
||||||
|
data.sfHoverTicks = 0;
|
||||||
|
hoverTicks.add(player.getName());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
data.sfHoverTicks = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
@ -975,4 +1010,85 @@ public class MovingListener extends CheckListener{
|
|||||||
public void onPlayerToggleSneak(final PlayerToggleSneakEvent event){
|
public void onPlayerToggleSneak(final PlayerToggleSneakEvent event){
|
||||||
survivalFly.setReallySneaking(event.getPlayer(), event.isSneaking());
|
survivalFly.setReallySneaking(event.getPlayer(), event.isSneaking());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void onTick(final int tick, final long timeLast) {
|
||||||
|
// Hover checks !
|
||||||
|
if (hoverTicks.isEmpty()) return; // Seldom or not ?
|
||||||
|
final Server server = Bukkit.getServer();
|
||||||
|
final MoveInfo info;
|
||||||
|
if (parkedInfo.isEmpty()) info = new MoveInfo(mcAccess);
|
||||||
|
else info = parkedInfo.remove(parkedInfo.size() - 1);
|
||||||
|
final List<String> rem = new ArrayList<String>(hoverTicks.size()); // Pessimistic.
|
||||||
|
for (final String playerName : hoverTicks){
|
||||||
|
final Player player = server.getPlayerExact(playerName);
|
||||||
|
if (player == null || !player.isOnline()){
|
||||||
|
rem.add(playerName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final MovingData data = MovingData.getData(player);
|
||||||
|
if (data.sfHoverTicks < 0){
|
||||||
|
rem.add(playerName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (checkHover(player, data, info)){
|
||||||
|
rem.add(playerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parkedInfo.add(info);
|
||||||
|
hoverTicks.removeAll(rem);
|
||||||
|
rem.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final boolean checkHover(final Player player, final MovingData data, final MoveInfo info) {
|
||||||
|
final MovingConfig cc = MovingConfig.getConfig(player);
|
||||||
|
// Check if enabled at all.
|
||||||
|
if (!cc.sfHoverCheck) return true;
|
||||||
|
// Check if player is on ground.
|
||||||
|
final Location loc = player.getLocation();
|
||||||
|
info.set(player, loc, null, cc.yOnGround);
|
||||||
|
final boolean res;
|
||||||
|
if (info.from.isOnGround() || info.from.isResetCond() || info.from.isAboveLadder() || info.from.isAboveStairs()){
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
data.sfHoverTicks ++;
|
||||||
|
if (data.sfHoverTicks > cc.sfHoverTicks){
|
||||||
|
handleHoverViolation(player, loc, cc, data);
|
||||||
|
// Assume the player might still be hovering.
|
||||||
|
res = false;
|
||||||
|
data.sfHoverTicks = 0;
|
||||||
|
}
|
||||||
|
else res = false;
|
||||||
|
}
|
||||||
|
info.cleanup();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final void handleHoverViolation(final Player player, final Location loc, final MovingConfig cc, final MovingData data) {
|
||||||
|
// Check nofall damage (!).
|
||||||
|
if (cc.sfHoverFallDamage && noFall.isEnabled(player)){
|
||||||
|
// Consider adding 3/3.5 to fall distance if fall distance > 0?
|
||||||
|
noFall.checkDamage(player, data, loc.getY());
|
||||||
|
}
|
||||||
|
// Delegate violation handling.
|
||||||
|
survivalFly.handleHoverViolation(player, loc, cc, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CheckType getCheckType() {
|
||||||
|
// TODO: this is for the hover check only...
|
||||||
|
return CheckType.MOVING_SURVIVALFLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IData removeData(String playerName) {
|
||||||
|
hoverTicks.remove(playerName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeAllData() {
|
||||||
|
hoverTicks.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,6 +489,40 @@ public class SurvivalFly extends Check {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final void handleHoverViolation(final Player player, final Location loc, final MovingConfig cc, final MovingData data) {
|
||||||
|
data.survivalFlyVL += cc.sfHoverViolation;
|
||||||
|
|
||||||
|
// TODO: Extra options for set-back / kick, like vl?
|
||||||
|
data.sfVLTime = System.currentTimeMillis();
|
||||||
|
final ViolationData vd = new ViolationData(this, player, data.survivalFlyVL, cc.sfHoverViolation, cc.survivalFlyActions);
|
||||||
|
if (vd.needsParameters()) {
|
||||||
|
vd.setParameter(ParameterName.LOCATION_FROM, String.format(Locale.US, "%.2f, %.2f, %.2f", loc.getX(), loc.getY(), loc.getZ()));
|
||||||
|
vd.setParameter(ParameterName.LOCATION_TO, "(HOVER)");
|
||||||
|
vd.setParameter(ParameterName.DISTANCE, "0.0(HOVER)");
|
||||||
|
vd.setParameter(ParameterName.TAGS, "hover");
|
||||||
|
}
|
||||||
|
if (executeActions(vd)) {
|
||||||
|
// Set-back or kick.
|
||||||
|
if (data.hasSetBack()){
|
||||||
|
data.clearAccounting();
|
||||||
|
data.sfJumpPhase = 0;
|
||||||
|
data.sfLastYDist = Double.MAX_VALUE;
|
||||||
|
data.toWasReset = false;
|
||||||
|
data.fromWasReset = false;
|
||||||
|
player.teleport(data.getSetBack(loc));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// Solve by extra actions ? Special case (probably never happens)?
|
||||||
|
player.kickPlayer("Hovering?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First split-off. Not strictly accounting only, actually.<br>
|
* First split-off. Not strictly accounting only, actually.<br>
|
||||||
|
@ -496,6 +496,12 @@ public abstract class ConfPaths {
|
|||||||
public static final String MOVING_SURVIVALFLY_EXTENDED_VACC = MOVING_SURVIVALFLY_EXTENDED + "vertical-accounting";
|
public static final String MOVING_SURVIVALFLY_EXTENDED_VACC = MOVING_SURVIVALFLY_EXTENDED + "vertical-accounting";
|
||||||
public static final String MOVING_SURVIVALFLY_VLFREEZE = MOVING_SURVIVALFLY + "vlfreeze";
|
public static final String MOVING_SURVIVALFLY_VLFREEZE = MOVING_SURVIVALFLY + "vlfreeze";
|
||||||
public static final String MOVING_SURVIVALFLY_ACTIONS = MOVING_SURVIVALFLY + "actions";
|
public static final String MOVING_SURVIVALFLY_ACTIONS = MOVING_SURVIVALFLY + "actions";
|
||||||
|
|
||||||
|
private static final String MOVING_SURVIVALFLY_HOVER = MOVING_SURVIVALFLY + "hover.";
|
||||||
|
public static final String MOVING_SURVIVALFLY_HOVER_CHECK = MOVING_SURVIVALFLY_HOVER + "active";
|
||||||
|
public static final String MOVING_SURVIVALFLY_HOVER_TICKS = MOVING_SURVIVALFLY_HOVER + "ticks";
|
||||||
|
public static final String MOVING_SURVIVALFLY_HOVER_FALLDAMAGE = MOVING_SURVIVALFLY_HOVER + "falldamage";
|
||||||
|
public static final String MOVING_SURVIVALFLY_HOVER_SFVIOLATION = MOVING_SURVIVALFLY_HOVER + "sfviolation";
|
||||||
|
|
||||||
// Special (to be sorted in or factored out).
|
// Special (to be sorted in or factored out).
|
||||||
public static final String MOVING_NOFALL_YONGROUND = MOVING_NOFALL + "yonground";
|
public static final String MOVING_NOFALL_YONGROUND = MOVING_NOFALL + "yonground";
|
||||||
|
@ -25,7 +25,9 @@ public class DefaultConfig extends ConfigFile {
|
|||||||
* NCP build needed for this config.
|
* NCP build needed for this config.
|
||||||
* (Should only increment with changing or removing paths.)
|
* (Should only increment with changing or removing paths.)
|
||||||
*/
|
*/
|
||||||
public static final int buildNumber = 314;
|
public static final int buildNumber = 315; // TODO: Check jenkins...
|
||||||
|
|
||||||
|
// TODO: auto input full version or null to an extra variable or several [fail safe for other syntax checking]?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new default configuration.
|
* Instantiates a new default configuration.
|
||||||
@ -387,6 +389,12 @@ public class DefaultConfig extends ConfigFile {
|
|||||||
set(ConfPaths.MOVING_SURVIVALFLY_ACTIONS,
|
set(ConfPaths.MOVING_SURVIVALFLY_ACTIONS,
|
||||||
"log:flyshort:3:5:f cancel vl>100 log:flyshort:0:5:if cancel vl>400 log:flylong:0:5:cif cancel vl>1000 log:flylong:0:5:cif cancel cmd:kickfly");
|
"log:flyshort:3:5:f cancel vl>100 log:flyshort:0:5:if cancel vl>400 log:flylong:0:5:cif cancel vl>1000 log:flylong:0:5:cif cancel cmd:kickfly");
|
||||||
|
|
||||||
|
// sf / hover check.
|
||||||
|
set(ConfPaths.MOVING_SURVIVALFLY_HOVER_CHECK, true);
|
||||||
|
set(ConfPaths.MOVING_SURVIVALFLY_HOVER_TICKS, 80);
|
||||||
|
set(ConfPaths.MOVING_SURVIVALFLY_HOVER_FALLDAMAGE, true);
|
||||||
|
set(ConfPaths.MOVING_SURVIVALFLY_HOVER_SFVIOLATION, 500);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dP"8 d8 ,e,
|
* dP"8 d8 ,e,
|
||||||
* C8b Y d88 888,8, " 888 8e e88 888 dP"Y
|
* C8b Y d88 888,8, " 888 8e e88 888 dP"Y
|
||||||
|
Loading…
Reference in New Issue
Block a user