mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-09-03 10:50:27 +02:00
commit
d5c7bb7d27
|
@ -0,0 +1,173 @@
|
|||
package fr.neatmonster.nocheatplus.utilities.ds;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* More cows, more fun: Copy on write for a LinkedHashMap (optimized for fast reading from any thread).
|
||||
* <hr>
|
||||
* This does not allow access-ordered maps, use Collections.synchronizedMap(LinkedHashMap...) for that case.
|
||||
* @author dev1mc
|
||||
*
|
||||
*/
|
||||
public class LinkedHashMapCOW<K, V> implements Map<K, V> {
|
||||
|
||||
private LinkedHashMap<K, V> map;
|
||||
|
||||
private final int initialCapacity;
|
||||
private final float loadFactor;
|
||||
|
||||
/**
|
||||
* Uses: 16, 0.75f, false (default settings, insertion ordered).
|
||||
*/
|
||||
public LinkedHashMapCOW() {
|
||||
this(16, 0.75f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses extra: 0.75f, false (default settings, insertion ordered).
|
||||
* @param initialCapacity
|
||||
*/
|
||||
public LinkedHashMapCOW(int initialCapacity) {
|
||||
this(initialCapacity, 0.75f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses extra: false (default settings, insertion ordered).
|
||||
* @param initialCapacity
|
||||
* @param loadFactor
|
||||
*/
|
||||
public LinkedHashMapCOW(int initialCapacity, float loadFactor) {
|
||||
this.initialCapacity = initialCapacity;
|
||||
this.loadFactor = loadFactor;
|
||||
this.map = new LinkedHashMap<K, V>(initialCapacity, loadFactor, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses: 16, 0.75f, false (default settings, insertion ordered).
|
||||
* @param map
|
||||
*/
|
||||
public LinkedHashMapCOW(Map<K, V> map) {
|
||||
this();
|
||||
this.map.putAll(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not synchronized: return a copy of the internal map.
|
||||
* @return
|
||||
*/
|
||||
private LinkedHashMap<K, V> copyMap() {
|
||||
final LinkedHashMap<K, V> newMap = new LinkedHashMap<K, V>(initialCapacity, loadFactor, false);
|
||||
newMap.putAll(this.map);
|
||||
return newMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
synchronized (this) {
|
||||
this.map.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return this.map.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return this.map.containsValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmodifiable version of the EntrySet. Entry.setValue might be possible, but dangerous :p
|
||||
*/
|
||||
@Override
|
||||
public Set<java.util.Map.Entry<K, V>> entrySet() {
|
||||
return Collections.unmodifiableSet(map.entrySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
// NOTE: If accessOrder can be true, there needs to be synchronization here, defeating any purpose, better use Collections.synchronizedMap(LinkedHashMap...) for that case.
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmodifiable version of the KeySet.
|
||||
*/
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return Collections.unmodifiableSet(map.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(final K key, final V value) {
|
||||
final V out;
|
||||
synchronized (this) {
|
||||
final LinkedHashMap<K, V> newMap = copyMap();
|
||||
out = newMap.put(key, value);
|
||||
this.map = newMap;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(final Map<? extends K, ? extends V> m) {
|
||||
synchronized (this) {
|
||||
final LinkedHashMap<K, V> newMap = copyMap();
|
||||
newMap.putAll(m);
|
||||
this.map = newMap;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(final Object key) {
|
||||
final V out;
|
||||
synchronized (this) {
|
||||
final LinkedHashMap<K, V> newMap = copyMap();
|
||||
out = newMap.remove(key);
|
||||
this.map = newMap;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all given keys.<br>
|
||||
* Not the most efficient implementation, copying the map and then removing
|
||||
* keys, but still better than iterating remove(key).
|
||||
*
|
||||
* @param keys
|
||||
*/
|
||||
public void removeAll(final Collection<K> keys) {
|
||||
synchronized (this) {
|
||||
final LinkedHashMap<K, V> newMap = copyMap();
|
||||
for (final K key : keys) {
|
||||
newMap.remove(key);
|
||||
}
|
||||
this.map = newMap;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmodifiable version of the values (Collection).
|
||||
*/
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return Collections.unmodifiableCollection(map.values());
|
||||
}
|
||||
|
||||
}
|
|
@ -210,12 +210,6 @@ public class MCAccessBukkit implements MCAccess, BlockPropertiesSetup{
|
|||
BlockProperties.setBlockFlags(mat, BlockProperties.getBlockFlags(mat) | flags);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
|
|
|
@ -145,12 +145,6 @@ public class MCAccessCB2512 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
switch(mat){
|
||||
|
|
|
@ -145,12 +145,6 @@ public class MCAccessCB2545 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
switch(mat){
|
||||
|
|
|
@ -146,13 +146,6 @@ public class MCAccessCB2602 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
switch(mat){
|
||||
|
|
|
@ -147,12 +147,6 @@ public class MCAccessCB2645 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
switch(mat){
|
||||
|
|
|
@ -149,12 +149,6 @@ public class MCAccessCB2691 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
switch(mat){
|
||||
|
|
|
@ -147,12 +147,6 @@ public class MCAccessCB2763 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
// TODO: TEST: return mat.hasGravity();
|
||||
|
|
|
@ -147,12 +147,6 @@ public class MCAccessCB2794 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
// TODO: Test/check.
|
||||
|
|
|
@ -148,12 +148,6 @@ public class MCAccessCB2808 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
// TODO: Test/check.
|
||||
|
|
|
@ -149,12 +149,6 @@ public class MCAccessCB2882 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
// TODO: Test/check.
|
||||
|
|
|
@ -149,12 +149,6 @@ public class MCAccessCB2922 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
// TODO: Test/check.
|
||||
|
|
|
@ -149,12 +149,6 @@ public class MCAccessCB3026 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
// TODO: Test/check.
|
||||
|
|
|
@ -168,12 +168,6 @@ public class MCAccessCB3043 implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
// TODO: Test/check.
|
||||
|
|
|
@ -170,12 +170,6 @@ public class MCAccessCBDev implements MCAccess{
|
|||
mcPlayer.dead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKeepAliveTime(final Player player) {
|
||||
// TODO: Implement if possible.
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity(final Material mat) {
|
||||
// TODO: Test/check.
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package fr.neatmonster.nocheatplus.net.protocollib;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.JoinLeaveListener;
|
||||
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.LinkedHashMapCOW;
|
||||
|
||||
/**
|
||||
* Prevent extremely fast ticking by just sending packets that don't do anything
|
||||
* new and also don't trigger moving events in CraftBukkit.
|
||||
*
|
||||
* @author dev1mc
|
||||
*
|
||||
*/
|
||||
public class FlyingFrequency extends PacketAdapter implements Listener, JoinLeaveListener {
|
||||
|
||||
// TODO: Configuration.
|
||||
// TODO: Optimized options (receive only, other?).
|
||||
// TODO: Async version ?
|
||||
|
||||
private final Map<String, ActionFrequency> freqMap = new LinkedHashMapCOW<String, ActionFrequency>();
|
||||
|
||||
public FlyingFrequency(Plugin plugin) {
|
||||
// PacketPlayInFlying[3, legacy: 10]
|
||||
super(plugin, PacketType.Play.Client.FLYING); // TODO: How does POS and POS_LOOK relate/translate?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playerJoins(Player player) {
|
||||
getFreq(player.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playerLeaves(Player player) {
|
||||
freqMap.remove(player.getName());
|
||||
}
|
||||
|
||||
private ActionFrequency getFreq(final String name) {
|
||||
final ActionFrequency freq = this.freqMap.get(name);
|
||||
if (freq != null) {
|
||||
return freq;
|
||||
} else {
|
||||
final ActionFrequency newFreq = new ActionFrequency(5, 1000);
|
||||
this.freqMap.put(name, newFreq);
|
||||
return newFreq;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceiving(final PacketEvent event) {
|
||||
// TODO: Add several (at least has look + has pos individually, maybe none/onground)
|
||||
final ActionFrequency freq = getFreq(event.getPlayer().getName());
|
||||
freq.add(System.currentTimeMillis(), 1f);
|
||||
if (freq.score(1f) > 300) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package fr.neatmonster.nocheatplus.net.protocollib;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.JoinLeaveListener;
|
||||
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
|
||||
|
||||
/**
|
||||
* Prevent extremely fast ticking by just sending packets that don't do anything
|
||||
* new and also don't trigger moving events in CraftBukkit.
|
||||
*
|
||||
* @author dev1mc
|
||||
*
|
||||
*/
|
||||
public class MoveFrequency extends PacketAdapter implements Listener, JoinLeaveListener {
|
||||
|
||||
// TODO: Optimized options (receive only, other?).
|
||||
// TODO: Async version ?
|
||||
|
||||
// private static Collection<PacketType> getPacketTypes() {
|
||||
// final Collection<PacketType> packetTypes = PacketType.fromName("C03PacketPlayer");
|
||||
// if (packetTypes.isEmpty()) {
|
||||
// throw new RuntimeException("Packet types not available.");
|
||||
// }
|
||||
// return packetTypes;
|
||||
// }
|
||||
|
||||
private Map<String, ActionFrequency> freqMap = new LinkedHashMap<String, ActionFrequency>();
|
||||
|
||||
public MoveFrequency(Plugin plugin) {
|
||||
// PacketPlayInFlying[3, legacy: 10]
|
||||
super(plugin, PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, 3)); //getPacketTypes());
|
||||
// TODO: Try to get packet by name first + legacy first.
|
||||
}
|
||||
|
||||
private ActionFrequency addName(String name) {
|
||||
Map<String, ActionFrequency> freqMap = new HashMap<String, ActionFrequency>(this.freqMap);
|
||||
ActionFrequency freq = new ActionFrequency(5, 1000);
|
||||
freqMap.put(name, freq);
|
||||
this.freqMap = freqMap;
|
||||
return freq;
|
||||
}
|
||||
|
||||
private void removeName(String name) {
|
||||
Map<String, ActionFrequency> freq = new HashMap<String, ActionFrequency>(this.freqMap);
|
||||
freq.remove(name);
|
||||
this.freqMap = freq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playerJoins(Player player) {
|
||||
addName(player.getName()); // Could spare that one.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playerLeaves(Player player) {
|
||||
removeName(player.getName());
|
||||
}
|
||||
|
||||
private ActionFrequency getFreq(String name) {
|
||||
ActionFrequency freq = this.freqMap.get(name);
|
||||
if (freq == null) {
|
||||
return addName(name);
|
||||
} else {
|
||||
return freq;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceiving(PacketEvent event) {
|
||||
// TODO: Add several (at least has look + has pos individually, maybe none/onground)
|
||||
ActionFrequency freq = getFreq(event.getPlayer().getName());
|
||||
freq.add(System.currentTimeMillis(), 1f);
|
||||
if (freq.score(1f) > 300) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package fr.neatmonster.nocheatplus.net.protocollib;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -11,6 +13,7 @@ import com.comphenix.protocol.events.PacketAdapter;
|
|||
|
||||
import fr.neatmonster.nocheatplus.components.DisableListener;
|
||||
import fr.neatmonster.nocheatplus.logging.LogUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.StringUtil;
|
||||
|
||||
/**
|
||||
* Quick and dirty ProtocolLib setup.
|
||||
|
@ -24,14 +27,30 @@ public class ProtocolLibComponent implements DisableListener{
|
|||
public ProtocolLibComponent(Plugin plugin) {
|
||||
// Register with ProtocolLib
|
||||
final ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
LogUtil.logInfo("[NoCheatPlus] ProtocolLib seems to be available.");
|
||||
try {
|
||||
PacketAdapter adapter = new MoveFrequency(plugin);
|
||||
protocolManager.addPacketListener(adapter);
|
||||
registeredPacketAdapters.add(adapter);
|
||||
} catch (Throwable t) {
|
||||
LogUtil.logWarning("[NoCheatPlus] Could not register some packet-level hook.");
|
||||
LogUtil.logWarning(t); // TODO: Maybe temporary.
|
||||
LogUtil.logInfo("[NoCheatPlus] ProtocolLib seems to be available, attempt to add packet level hooks...");
|
||||
// Classes having a constructor with Plugin as argument.
|
||||
List<Class<? extends PacketAdapter>> adapterClasses = Arrays.asList(
|
||||
FlyingFrequency.class,
|
||||
SoundDistance.class // Need too: SPAWN_ENTITY_WEATHER, wither/dragon: WORLD_EVENT
|
||||
);
|
||||
// TODO: Configurability (INotifyConfig, method to set up hooks).
|
||||
for (Class<? extends PacketAdapter> clazz : adapterClasses) {
|
||||
try {
|
||||
// Construct a new instance using reflection.
|
||||
PacketAdapter adapter = clazz.getDeclaredConstructor(Plugin.class).newInstance(plugin);
|
||||
protocolManager.addPacketListener(adapter);
|
||||
registeredPacketAdapters.add(adapter);
|
||||
} catch (Throwable t) {
|
||||
LogUtil.logWarning("[NoCheatPlus] Could not register packet level hook: " + clazz.getSimpleName());
|
||||
LogUtil.logWarning(t); // TODO: Maybe temporary.
|
||||
}
|
||||
}
|
||||
if (!registeredPacketAdapters.isEmpty()) {
|
||||
List<String> names = new ArrayList<String>(registeredPacketAdapters.size());
|
||||
for (PacketAdapter adapter : registeredPacketAdapters) {
|
||||
names.add(adapter.getClass().getSimpleName());
|
||||
}
|
||||
LogUtil.logInfo("[NoCheatPlus] Available packet level hooks: " + StringUtil.join(names, " | "));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,13 +61,10 @@ public class ProtocolLibComponent implements DisableListener{
|
|||
try {
|
||||
protocolManager.removePacketListener(adapter);
|
||||
} catch (Throwable t) {
|
||||
LogUtil.logWarning("[NoCheatPlus] Failed to unregister protocol listener: " + adapter.getClass().getName());
|
||||
LogUtil.logWarning("[NoCheatPlus] Failed to unregister packet level hook: " + adapter.getClass().getName());
|
||||
}
|
||||
}
|
||||
registeredPacketAdapters.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
package fr.neatmonster.nocheatplus.net.protocollib;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
|
||||
import fr.neatmonster.nocheatplus.utilities.TrigUtil;
|
||||
|
||||
public class SoundDistance extends PacketAdapter {
|
||||
|
||||
// TODO: Will not be effective with 512 radius, if they add the patch by @Amranth.
|
||||
// TODO: For lower distances more packets might need to be intercepted.
|
||||
|
||||
/** Maximum distance for thunder effects (squared). */
|
||||
private static final double distSq = 512.0 * 512.0; // TODO: Maybe configurable.
|
||||
|
||||
private static final String[] effectNames = new String[] { // Prefix tree?
|
||||
"ambient.weather.thunder",
|
||||
"wither-spawn-sound-radius",
|
||||
"dragon-death-sound-radius"
|
||||
// other ?
|
||||
};
|
||||
|
||||
private static final boolean contains(final String ref) {
|
||||
for (int i = 0; i < effectNames.length; i++) {
|
||||
if (effectNames[i].equals(ref)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public SoundDistance(Plugin plugin) {
|
||||
super(plugin, PacketType.Play.Server.NAMED_SOUND_EFFECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSending(final PacketEvent event) {
|
||||
final PacketContainer packetContainer = event.getPacket();
|
||||
final Player player = event.getPlayer();
|
||||
|
||||
// Compare sound effect name.
|
||||
if (!contains(packetContainer.getStrings().read(0))) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Location loc = player.getLocation(); // TODO: Use getLocation(useLoc) [synced if async].
|
||||
|
||||
// Compare distance of player to the weather location.
|
||||
final StructureModifier<Integer> ints = packetContainer.getIntegers();
|
||||
if (TrigUtil.distanceSquared(ints.read(0) / 8, ints.read(2) / 8, loc.getX(), loc.getZ()) > distSq) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -54,7 +54,7 @@ public class ChatConfig extends AsyncCheckConfig {
|
|||
synchronized (worldsMap) {
|
||||
if (!worldsMap.containsKey(player.getWorld().getName()))
|
||||
worldsMap.put(player.getWorld().getName(),
|
||||
new ChatConfig(ConfigManager.getConfigFileSync(player.getWorld().getName())));
|
||||
new ChatConfig(ConfigManager.getConfigFile(player.getWorld().getName())));
|
||||
return worldsMap.get(player.getWorld().getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,8 +128,9 @@ public class GodMode extends Check {
|
|||
// Check for client side lag.
|
||||
final long now = System.currentTimeMillis();
|
||||
final long maxAge = cc.godModeLagMaxAge;
|
||||
long keepAlive = mcAccess.getKeepAliveTime(player);
|
||||
if (keepAlive > now || keepAlive == Long.MIN_VALUE){
|
||||
long keepAlive = Long.MIN_VALUE;
|
||||
// TODO: Get keepAlive from NetData, if available.
|
||||
if (keepAlive > now || keepAlive == Long.MIN_VALUE) {
|
||||
keepAlive = CheckUtils.guessKeepAliveTime(player, now, maxAge);
|
||||
}
|
||||
// TODO: else: still check the other time stamp ?
|
||||
|
|
|
@ -224,7 +224,6 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
|
|||
|
||||
boolean resetAll = false;
|
||||
|
||||
|
||||
if (event.hasItem()){
|
||||
final ItemStack item = event.getItem();
|
||||
final Material type = item.getType();
|
||||
|
@ -234,7 +233,7 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
|
|||
// It was a bow, the player starts to pull the string, remember this time.
|
||||
data.instantBowInteract = (data.instantBowInteract > 0 && now - data.instantBowInteract < 800) ? Math.min(System.currentTimeMillis(), data.instantBowInteract) : System.currentTimeMillis();
|
||||
}
|
||||
else if (type.isEdible() || type == Material.POTION) {
|
||||
else if (type.isEdible() || type == Material.POTION || type == Material.MILK_BUCKET) {
|
||||
final long now = System.currentTimeMillis();
|
||||
// It was food, the player starts to eat some food, remember this time and the type of food.
|
||||
data.instantEatFood = type;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package fr.neatmonster.nocheatplus.checks.moving;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
|
@ -9,25 +7,16 @@ import fr.neatmonster.nocheatplus.actions.ParameterName;
|
|||
import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.ViolationData;
|
||||
import fr.neatmonster.nocheatplus.net.NetStatic;
|
||||
import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
|
||||
|
||||
/**
|
||||
* The MorePackets check (previously called Speedhack check) will try to identify players that send more than the usual
|
||||
* The MorePackets check will try to identify players that send more than the usual
|
||||
* amount of move-packets to the server to be able to move faster than normal, without getting caught by the other
|
||||
* checks (flying/running).
|
||||
*
|
||||
* It monitors the number of packets sent to the server within 1 second and compares it to the "legal" number of packets
|
||||
* for that timeframe (22).
|
||||
*/
|
||||
public class MorePackets extends Check {
|
||||
|
||||
/**
|
||||
* The usual number of packets per timeframe.
|
||||
*
|
||||
* 20 would be for perfect internet connections, 22 is good enough.
|
||||
*/
|
||||
private final static int packetsPerTimeframe = 22;
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new more packets check.
|
||||
*/
|
||||
|
@ -35,31 +24,33 @@ public class MorePackets extends Check {
|
|||
super(CheckType.MOVING_MOREPACKETS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a player.
|
||||
*
|
||||
* Players get assigned a certain amount of "free" packets as a limit initially. Every move packet reduces that
|
||||
* limit by 1. If more than 1 second of time passed, the limit gets increased by 22 * time in seconds, up to 50 and
|
||||
* they get a new "setback" location. If the player reaches limit = 0 -> teleport them back to "setback". If there was
|
||||
* a long pause (maybe lag), limit may be up to 100.
|
||||
*
|
||||
* @param player
|
||||
* the player
|
||||
* @param from
|
||||
* the from
|
||||
* @param to
|
||||
* the to
|
||||
* @return the location
|
||||
*/
|
||||
/**
|
||||
* Check for speeding by sending too many packets. We assume 22 packets per
|
||||
* second to be legitimate, while 20 would be ideal. See
|
||||
* PlayerData.morePacketsFreq for the monitored amount of time and the
|
||||
* resolution. See NetStatic for the actual check code.
|
||||
*
|
||||
* @param player
|
||||
* the player
|
||||
* @param from
|
||||
* the from
|
||||
* @param to
|
||||
* the to
|
||||
* @return the location
|
||||
*/
|
||||
public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc) {
|
||||
// Take time once, first:
|
||||
final long time = System.currentTimeMillis();
|
||||
|
||||
|
||||
Location newTo = null;
|
||||
|
||||
// if (from.isSamePos(to)) {
|
||||
// // Ignore moves with "just look" for now.
|
||||
// // TODO: Extra ActionFrequency for "just look" + use to burn, maybe also check individually.
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// Ensure we have a set-back location.
|
||||
if (!data.hasMorePacketsSetBack()){
|
||||
// TODO: Check if other set-back is appropriate or if to set on other events.
|
||||
// TODO: Check if other set-back is appropriate or if to set/reset on other events.
|
||||
if (data.hasSetBack()) {
|
||||
data.setMorePacketsSetBack(data.getSetBack(to));
|
||||
}
|
||||
|
@ -67,66 +58,35 @@ public class MorePackets extends Check {
|
|||
data.setMorePacketsSetBack(from);
|
||||
}
|
||||
}
|
||||
|
||||
// Take a packet from the buffer.
|
||||
data.morePacketsBuffer--;
|
||||
|
||||
// Player used up buffer, they fail the check.
|
||||
if (data.morePacketsBuffer < 0) {
|
||||
data.morePacketsPackets = -data.morePacketsBuffer;
|
||||
|
||||
|
||||
// Check for a violation of the set limits.
|
||||
final double violation = NetStatic.morePacketsCheck(data.morePacketsFreq, time, 1f, cc.morePacketsEPSMax, cc.morePacketsEPSIdeal, data.morePacketsBurstFreq, cc.morePacketsBurstPackets, cc.morePacketsBurstDirect, cc.morePacketsBurstEPM);
|
||||
|
||||
// Process violation result.
|
||||
if (violation > 0.0) {
|
||||
|
||||
// Increment violation level.
|
||||
data.morePacketsVL = -data.morePacketsBuffer;
|
||||
|
||||
// Execute whatever actions are associated with this check and the violation level and find out if we should
|
||||
// cancel the event.
|
||||
if (executeActions(player, data.morePacketsVL, -data.morePacketsBuffer, MovingConfig.getConfig(player).morePacketsActions)){
|
||||
newTo = data.getMorePacketsSetBack();
|
||||
data.morePacketsVL = violation; // TODO: Accumulate somehow [e.g. always += 1, decrease with continuous moving without violation]?
|
||||
|
||||
// Violation handling.
|
||||
final ViolationData vd = new ViolationData(this, player, data.morePacketsVL, violation, cc.morePacketsActions);
|
||||
if (cc.debug || vd.needsParameters()) {
|
||||
vd.setParameter(ParameterName.PACKETS, Integer.toString(new Double(violation).intValue()));
|
||||
}
|
||||
|
||||
if (executeActions(vd)) {
|
||||
// Set to cancel the move.
|
||||
return data.getMorePacketsSetBack();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Update the set-back location. (CHANGED to only update, if not a violation.)
|
||||
// (Might update whenever newTo == null)
|
||||
data.setMorePacketsSetBack(from);
|
||||
}
|
||||
|
||||
if (data.morePacketsLastTime + 1000 < time) {
|
||||
// More than 1 second elapsed, but how many?
|
||||
final double seconds = (time - data.morePacketsLastTime) / 1000D;
|
||||
|
||||
// For each second, fill the buffer.
|
||||
data.morePacketsBuffer += packetsPerTimeframe * seconds;
|
||||
|
||||
// If there was a long pause (maybe server lag?), allow buffer to grow up to 100.
|
||||
if (seconds > 2) {
|
||||
if (data.morePacketsBuffer > 100) {
|
||||
data.morePacketsBuffer = 100;
|
||||
}
|
||||
} else if (data.morePacketsBuffer > 50) {
|
||||
// Only allow growth up to 50.
|
||||
data.morePacketsBuffer = 50;
|
||||
}
|
||||
// Set the new "last" time.
|
||||
data.morePacketsLastTime = time;
|
||||
|
||||
// Set the new "setback" location.
|
||||
if (newTo == null) {
|
||||
data.setMorePacketsSetBack(from);
|
||||
}
|
||||
} else if (data.morePacketsLastTime > time) {
|
||||
// Security check, maybe system time changed.
|
||||
data.morePacketsLastTime = time;
|
||||
}
|
||||
|
||||
if (newTo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Compose a new location based on coordinates of "newTo" and viewing direction of "event.getTo()" to allow the
|
||||
// player to look somewhere else despite getting pulled back by NoCheatPlus.
|
||||
return new Location(player.getWorld(), newTo.getX(), newTo.getY(), newTo.getZ(), to.getYaw(), to.getPitch());
|
||||
|
||||
// No set-back.
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<ParameterName, String> getParameterMap(final ViolationData violationData) {
|
||||
final Map<ParameterName, String> parameters = super.getParameterMap(violationData);
|
||||
parameters.put(ParameterName.PACKETS, String.valueOf(MovingData.getData(violationData.player).morePacketsPackets));
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package fr.neatmonster.nocheatplus.checks.moving;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -70,14 +68,17 @@ public class MorePacketsVehicle extends Check {
|
|||
|
||||
// Player used up buffer, they fail the check.
|
||||
if (data.morePacketsVehicleBuffer < 0) {
|
||||
data.morePacketsVehiclePackets = -data.morePacketsVehicleBuffer;
|
||||
|
||||
// Increment violation level.
|
||||
data.morePacketsVehicleVL = -data.morePacketsVehicleBuffer;
|
||||
|
||||
// Execute whatever actions are associated with this check and the violation level and find out if we should
|
||||
// cancel the event.
|
||||
if (executeActions(player, data.morePacketsVehicleVL, -data.morePacketsVehicleBuffer, cc.morePacketsVehicleActions)){
|
||||
final ViolationData vd = new ViolationData(this, player, data.morePacketsVehicleVL, -data.morePacketsVehicleBuffer, cc.morePacketsVehicleActions);
|
||||
if (cc.debug || vd.needsParameters()) {
|
||||
vd.setParameter(ParameterName.PACKETS, Integer.toString(-data.morePacketsVehicleBuffer));
|
||||
}
|
||||
if (executeActions(vd)){
|
||||
newTo = data.getMorePacketsVehicleSetBack();
|
||||
}
|
||||
}
|
||||
|
@ -91,34 +92,33 @@ public class MorePacketsVehicle extends Check {
|
|||
|
||||
// If there was a long pause (maybe server lag?), allow buffer to grow up to 100.
|
||||
if (seconds > 2) {
|
||||
if (data.morePacketsVehicleBuffer > 100)
|
||||
data.morePacketsVehicleBuffer = 100;
|
||||
} else if (data.morePacketsVehicleBuffer > 50)
|
||||
// Only allow growth up to 50.
|
||||
if (data.morePacketsVehicleBuffer > 100) {
|
||||
data.morePacketsVehicleBuffer = 100;
|
||||
}
|
||||
} else if (data.morePacketsVehicleBuffer > 50) {
|
||||
// Only allow growth up to 50.
|
||||
data.morePacketsVehicleBuffer = 50;
|
||||
|
||||
}
|
||||
|
||||
// Set the new "last" time.
|
||||
data.morePacketsVehicleLastTime = time;
|
||||
|
||||
// Set the new "setback" location.
|
||||
if (newTo == null)
|
||||
data.setMorePacketsVehicleSetBack(from);
|
||||
} else if (data.morePacketsVehicleLastTime > time)
|
||||
// Security check, maybe system time changed.
|
||||
if (newTo == null) {
|
||||
data.setMorePacketsVehicleSetBack(from);
|
||||
}
|
||||
} else if (data.morePacketsVehicleLastTime > time) {
|
||||
// Security check, maybe system time changed.
|
||||
data.morePacketsVehicleLastTime = time;
|
||||
}
|
||||
|
||||
if (newTo == null)
|
||||
return null;
|
||||
if (newTo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Compose a new location based on coordinates of "newTo" and viewing direction of "event.getTo()" to allow the
|
||||
// player to look somewhere else despite getting pulled back by NoCheatPlus.
|
||||
return new Location(player.getWorld(), newTo.getX(), newTo.getY(), newTo.getZ(), to.getYaw(), to.getPitch());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<ParameterName, String> getParameterMap(final ViolationData violationData) {
|
||||
final Map<ParameterName, String> parameters = super.getParameterMap(violationData);
|
||||
parameters.put(ParameterName.PACKETS, String.valueOf(MovingData.getData(violationData.player).morePacketsVehiclePackets));
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,13 @@ public class MovingConfig extends ACheckConfig {
|
|||
public final ActionList creativeFlyActions;
|
||||
|
||||
public final boolean morePacketsCheck;
|
||||
/** Assumed number of packets per second under ideal conditions. */
|
||||
public final float morePacketsEPSIdeal;
|
||||
/** The maximum number of packets per second that we accept. */
|
||||
public final float morePacketsEPSMax;
|
||||
public final float morePacketsBurstPackets;
|
||||
public final double morePacketsBurstDirect;
|
||||
public final double morePacketsBurstEPM;
|
||||
public final ActionList morePacketsActions;
|
||||
|
||||
public final boolean morePacketsVehicleCheck;
|
||||
|
@ -167,6 +174,11 @@ public class MovingConfig extends ACheckConfig {
|
|||
creativeFlyActions = config.getOptimizedActionList(ConfPaths.MOVING_CREATIVEFLY_ACTIONS, Permissions.MOVING_CREATIVEFLY);
|
||||
|
||||
morePacketsCheck = config.getBoolean(ConfPaths.MOVING_MOREPACKETS_CHECK);
|
||||
morePacketsEPSIdeal = config.getInt(ConfPaths.MOVING_MOREPACKETS_EPSIDEAL);
|
||||
morePacketsEPSMax = Math.max(morePacketsEPSIdeal, config.getInt(ConfPaths.MOVING_MOREPACKETS_EPSMAX));
|
||||
morePacketsBurstPackets = config.getInt(ConfPaths.MOVING_MOREPACKETS_BURST_EPM);
|
||||
morePacketsBurstDirect = config.getInt(ConfPaths.MOVING_MOREPACKETS_BURST_DIRECT);
|
||||
morePacketsBurstEPM = config.getInt(ConfPaths.MOVING_MOREPACKETS_BURST_EPM);
|
||||
morePacketsActions = config.getOptimizedActionList(ConfPaths.MOVING_MOREPACKETS_ACTIONS, Permissions.MOVING_MOREPACKETS);
|
||||
|
||||
morePacketsVehicleCheck = config.getBoolean(ConfPaths.MOVING_MOREPACKETSVEHICLE_CHECK);
|
||||
|
|
|
@ -14,6 +14,7 @@ import fr.neatmonster.nocheatplus.checks.access.ACheckData;
|
|||
import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory;
|
||||
import fr.neatmonster.nocheatplus.checks.access.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.utilities.ActionAccumulator;
|
||||
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
|
||||
import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
|
||||
|
||||
/**
|
||||
|
@ -122,7 +123,7 @@ public class MovingData extends ACheckData {
|
|||
/** 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>();
|
||||
public final List<Velocity> hVelQueued = new LinkedList<Velocity>();
|
||||
|
||||
// Coordinates.
|
||||
/** Last from coordinates. */
|
||||
|
@ -147,15 +148,15 @@ public class MovingData extends ACheckData {
|
|||
public boolean creativeFlyPreviousRefused;
|
||||
|
||||
// Data of the more packets check.
|
||||
public int morePacketsBuffer = 50;
|
||||
public long morePacketsLastTime;
|
||||
public int morePacketsPackets;
|
||||
/** Packet frequency count. */
|
||||
public final ActionFrequency morePacketsFreq = new ActionFrequency(10, 500);
|
||||
/** Burst count. */
|
||||
public final ActionFrequency morePacketsBurstFreq = new ActionFrequency(12, 5000);
|
||||
private Location morePacketsSetback = null;
|
||||
|
||||
// Data of the more packets vehicle check.
|
||||
public int morePacketsVehicleBuffer = 50;
|
||||
public long morePacketsVehicleLastTime;
|
||||
public int morePacketsVehiclePackets;
|
||||
private Location morePacketsVehicleSetback = null;
|
||||
/** Task id of the morepackets set-back task. */
|
||||
public int morePacketsVehicleTaskId = -1;
|
||||
|
|
|
@ -601,9 +601,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
|
|||
}
|
||||
|
||||
// Morepackets.
|
||||
// TODO: Also update counters if newTo == null?
|
||||
if (newTo == null && cc.morePacketsCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_MOREPACKETS) && !player.hasPermission(Permissions.MOVING_MOREPACKETS)) {
|
||||
// If it hasn't been stopped by any other check and is handled by the more packets check, execute it.
|
||||
// TODO: Still feed morepackets even if cancelled.
|
||||
newTo = morePackets.check(player, pFrom, pTo, data, cc);
|
||||
} else {
|
||||
// Otherwise we need to clear their data.
|
||||
|
@ -1003,7 +1003,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
|
|||
|
||||
double newVal = velocity.getY();
|
||||
boolean used = false;
|
||||
if (newVal >= 0D) {
|
||||
if (newVal >= 0D) { // TODO: Just >, not >=.
|
||||
used = true;
|
||||
if (data.verticalFreedom <= 0.001 && data.verticalVelocityCounter >= 0) {
|
||||
data.verticalVelocity = 0;
|
||||
|
|
|
@ -534,12 +534,6 @@ public class SurvivalFly extends Check {
|
|||
else {
|
||||
hAllowedDistance = walkSpeed * modSprint * cc.survivalFlySprintingSpeed / 100D;
|
||||
}
|
||||
|
||||
// Speeding bypass permission (can be combined with other bypasses).
|
||||
// TODO: How exactly to bring it on finally.
|
||||
if (checkPermissions && player.hasPermission(Permissions.MOVING_SURVIVALFLY_SPEEDING)) {
|
||||
hAllowedDistance *= cc.survivalFlySpeedingSpeed / 100D;
|
||||
}
|
||||
}
|
||||
|
||||
// Account for flowing liquids (only if needed).
|
||||
|
@ -550,6 +544,7 @@ public class SurvivalFly extends Check {
|
|||
}
|
||||
|
||||
// Short cut.
|
||||
// TODO: Check if a) early return makes sense and b) do it ofr all following parts.
|
||||
if (hDistance <= hAllowedDistance && !cc.debug) {
|
||||
// Shortcut for debug disabled.
|
||||
return hAllowedDistance;
|
||||
|
@ -566,6 +561,11 @@ public class SurvivalFly extends Check {
|
|||
hAllowedDistance *= 1.0D + 0.2D * (speedAmplifier + 1);
|
||||
}
|
||||
|
||||
// Speeding bypass permission (can be combined with other bypasses).
|
||||
if (checkPermissions && player.hasPermission(Permissions.MOVING_SURVIVALFLY_SPEEDING)) {
|
||||
hAllowedDistance *= cc.survivalFlySpeedingSpeed / 100D;
|
||||
}
|
||||
|
||||
return hAllowedDistance;
|
||||
}
|
||||
|
||||
|
@ -999,6 +999,7 @@ public class SurvivalFly extends Check {
|
|||
// if (vDistanceAboveLimit > 0) tags.add("vclimb");
|
||||
final double jumpHeight = 1.35 + (data.jumpAmplifier > 0 ? (0.6 + data.jumpAmplifier - 1.0) : 0.0);
|
||||
// TODO: ladders are ground !
|
||||
// TODO: yDistance < 0.0 ?
|
||||
if (yDistance > climbSpeed && !from.isOnGround(jumpHeight, 0D, 0D, BlockProperties.F_CLIMBABLE)) {
|
||||
// Ignore ladders. TODO: Check for false positives...
|
||||
tags.add("climbspeed");
|
||||
|
|
|
@ -122,13 +122,6 @@ public interface MCAccess {
|
|||
*/
|
||||
public void setDead(Player player, int deathTicks);
|
||||
|
||||
/**
|
||||
* Get timestamp of the keep-alive field (not only updated on keep-alive packets).
|
||||
* @param player The player for which to get the time.
|
||||
* @return Long.MIN_VALUE if not possible.
|
||||
*/
|
||||
public long getKeepAliveTime(Player player);
|
||||
|
||||
/**
|
||||
* Usually sand and gravel. Not for fastest access.
|
||||
* @param type
|
||||
|
|
|
@ -503,6 +503,12 @@ public abstract class ConfPaths {
|
|||
|
||||
private static final String MOVING_MOREPACKETS = MOVING + "morepackets.";
|
||||
public static final String MOVING_MOREPACKETS_CHECK = MOVING_MOREPACKETS + "active";
|
||||
public static final String MOVING_MOREPACKETS_EPSIDEAL = MOVING_MOREPACKETS + "epsideal";
|
||||
public static final String MOVING_MOREPACKETS_EPSMAX = MOVING_MOREPACKETS + "epsmax";
|
||||
private static final String MOVING_MOREPACKETS_BURST = MOVING_MOREPACKETS + "burst.";
|
||||
public static final String MOVING_MOREPACKETS_BURST_PACKETS = MOVING_MOREPACKETS_BURST + "packets";
|
||||
public static final String MOVING_MOREPACKETS_BURST_DIRECT = MOVING_MOREPACKETS_BURST + "directviolation";
|
||||
public static final String MOVING_MOREPACKETS_BURST_EPM = MOVING_MOREPACKETS_BURST + "epmviolation";
|
||||
public static final String MOVING_MOREPACKETS_ACTIONS = MOVING_MOREPACKETS + "actions";
|
||||
|
||||
private static final String MOVING_MOREPACKETSVEHICLE = MOVING + "morepacketsvehicle.";
|
||||
|
|
|
@ -3,6 +3,7 @@ package fr.neatmonster.nocheatplus.config;
|
|||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
@ -30,7 +31,7 @@ public class ConfigManager {
|
|||
};
|
||||
|
||||
/** The map containing the configuration files per world. */
|
||||
private static final Map<String, ConfigFile> worldsMap = new HashMap<String, ConfigFile>();
|
||||
private static Map<String, ConfigFile> worldsMap = new LinkedHashMap<String, ConfigFile>();
|
||||
|
||||
private static final WorldConfigProvider<ConfigFile> worldConfigProvider = new WorldConfigProvider<ConfigFile>() {
|
||||
|
||||
|
@ -118,7 +119,7 @@ public class ConfigManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the configuration file.
|
||||
* Gets the configuration file. Can be called from any thread.
|
||||
*
|
||||
* @return the configuration file
|
||||
*/
|
||||
|
@ -129,13 +130,15 @@ public class ConfigManager {
|
|||
/**
|
||||
* (Synchronized version).
|
||||
* @return
|
||||
* @deprecated getConfigFile() is thread-safe now.
|
||||
*/
|
||||
@Deprecated
|
||||
public static synchronized ConfigFile getConfigFileSync() {
|
||||
return getConfigFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configuration file.
|
||||
* Gets the configuration file. Can be called from any thread.
|
||||
*
|
||||
* @param worldName
|
||||
* the world name
|
||||
|
@ -146,14 +149,17 @@ public class ConfigManager {
|
|||
if (configFile != null){
|
||||
return configFile;
|
||||
}
|
||||
// Expensive only once, for the rest of runtime the file is returned fast.
|
||||
// Expensive only once per world, for the rest of the runtime the file is returned fast.
|
||||
synchronized(ConfigManager.class){
|
||||
// Need to check again.
|
||||
if (worldsMap.containsKey(worldName)){
|
||||
return worldsMap.get(worldName);
|
||||
}
|
||||
final ConfigFile globalConfig = getConfigFile();
|
||||
worldsMap.put(worldName, globalConfig);
|
||||
// Copy the whole map with the default configuration set for this world.
|
||||
final Map<String, ConfigFile> newWorldsMap = new LinkedHashMap<String, ConfigFile>(ConfigManager.worldsMap);
|
||||
final ConfigFile globalConfig = newWorldsMap.get(null);
|
||||
newWorldsMap.put(worldName, globalConfig);
|
||||
ConfigManager.worldsMap = newWorldsMap;
|
||||
return globalConfig;
|
||||
}
|
||||
}
|
||||
|
@ -162,13 +168,15 @@ public class ConfigManager {
|
|||
* (Synchronized version).
|
||||
* @param worldName
|
||||
* @return
|
||||
* @deprecated getConfigFile() is thread-safe now.
|
||||
*/
|
||||
@Deprecated
|
||||
public static synchronized ConfigFile getConfigFileSync(final String worldName) {
|
||||
return getConfigFile(worldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the configuration manager.
|
||||
* Initializes the configuration manager. Must be called in the main thread.
|
||||
*
|
||||
* @param plugin
|
||||
* the instance of NoCheatPlus
|
||||
|
|
|
@ -355,6 +355,11 @@ public class DefaultConfig extends ConfigFile {
|
|||
"log:flyshort:3:5:f cancel vl>100 log:flyshort:0:5:if cancel vl>400 log:flylong:0:5:cif cancel");
|
||||
|
||||
set(ConfPaths.MOVING_MOREPACKETS_CHECK, true);
|
||||
set(ConfPaths.MOVING_MOREPACKETS_EPSIDEAL, 20);
|
||||
set(ConfPaths.MOVING_MOREPACKETS_EPSMAX, 22);
|
||||
set(ConfPaths.MOVING_MOREPACKETS_BURST_PACKETS, 40);
|
||||
set(ConfPaths.MOVING_MOREPACKETS_BURST_DIRECT, 30);
|
||||
set(ConfPaths.MOVING_MOREPACKETS_BURST_EPM, 120);
|
||||
set(ConfPaths.MOVING_MOREPACKETS_ACTIONS, "cancel vl>10 log:morepackets:0:2:if cancel vl>100 log:morepackets:0:2:if cancel cmd:kickpackets");
|
||||
|
||||
set(ConfPaths.MOVING_MOREPACKETSVEHICLE_CHECK, true);
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
package fr.neatmonster.nocheatplus.net;
|
||||
|
||||
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
|
||||
/**
|
||||
* Static method utility for networking related stuff.
|
||||
* <hr>
|
||||
* Not sure about final location and naming... and content :p.
|
||||
* @author dev1mc
|
||||
*
|
||||
*/
|
||||
public class NetStatic {
|
||||
|
||||
/**
|
||||
* Packet-cheating check, for catching clients that send more packets than
|
||||
* allowed. Intention is to have a more accurate check than just preventing
|
||||
* "extreme spamming".
|
||||
*
|
||||
* @param packetFreq
|
||||
* Records the packets. This check will update packetFreq
|
||||
* according to the given time and packets.
|
||||
* @param time
|
||||
* Milliseconds time to update the ActionFrequency instance with.
|
||||
* @param packets
|
||||
* Amount to add to packetFreq with time.
|
||||
* @param maxPackets
|
||||
* The amount of packets per second (!), that is considered
|
||||
* legitimate.
|
||||
* @param idealPackets
|
||||
* The "ideal" amount of packets per second. Used for "burning"
|
||||
* time frames by setting them to this amount.
|
||||
* @param burstFreq Counting burst events, should be covering a minute or so.
|
||||
* @param burstPackets Packets in the first time window to add to burst count.
|
||||
* @param burstEPM Events per minute to trigger a burst violation.
|
||||
* @return The violation amount, i.e. "count above limit", 0.0 if no violation.
|
||||
*/
|
||||
public static double morePacketsCheck(final ActionFrequency packetFreq, final long time, final float packets, final float maxPackets, final float idealPackets, final ActionFrequency burstFreq, final float burstPackets, final double burstDirect, final double burstEPM) {
|
||||
// Pull down stuff.
|
||||
final long winDur = packetFreq.bucketDuration();
|
||||
final int winNum = packetFreq.numberOfBuckets();
|
||||
// Add packet to frequency count.
|
||||
packetFreq.add(time, packets);
|
||||
// TODO: Add a per-bucket violation AF (once first bucket > thresh => pbvAF.add(now, 1f) + if total score > xyz => extra violation).
|
||||
|
||||
// Fill up all "used" time windows (minimum we can do without other events).
|
||||
final float burnScore = (float) idealPackets * (float) winDur / 1000f;
|
||||
// Find index.
|
||||
int burnStart;
|
||||
int empty = 0;
|
||||
boolean used = false;
|
||||
for (burnStart = 1; burnStart < winNum; burnStart ++) {
|
||||
if (packetFreq.bucketScore(burnStart) > 0f) {
|
||||
// TODO: burnStart ++; Fill up all ? ~ e.g. what with filled up half?
|
||||
if (used) {
|
||||
for (int j = burnStart; j < winNum; j ++) {
|
||||
if (packetFreq.bucketScore(j) == 0f) {
|
||||
empty += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Burn time windows based on other activity counting [e.g. same resolution ActinFrequency with keep-alive].
|
||||
|
||||
// Adjust empty based on server side lag, this makes the check more strict.
|
||||
if (empty > 0) {
|
||||
// TODO: Consider to add a config flag for skipping the lag adaption (e.g. strict).
|
||||
final float lag = TickTask.getLag(winDur * winNum, true);
|
||||
// TODO: Consider increasing the allowed maximum, for extreme server-side lag.
|
||||
empty = Math.min(empty, (int) Math.round((lag - 1f) * winNum));
|
||||
}
|
||||
|
||||
final double fullCount;
|
||||
if (burnStart < winNum) {
|
||||
// Assume all following time windows are burnt.
|
||||
// TODO: empty score + trailing score !? max with trailing buckets * ideal (!)
|
||||
final float trailing = Math.max(packetFreq.trailingScore(burnStart, 1f), burnScore * (winNum - burnStart - empty));
|
||||
final float leading = packetFreq.leadingScore(burnStart, 1f);
|
||||
fullCount = leading + trailing;
|
||||
} else {
|
||||
// All time windows are used.
|
||||
fullCount = packetFreq.score(1f);
|
||||
}
|
||||
|
||||
double violation = (double) fullCount - (double) (maxPackets * winNum * winDur / 1000f);
|
||||
final float burst = packetFreq.bucketScore(0);
|
||||
if (burst > burstPackets) {
|
||||
// TODO: Account for "just now lag", i.e. time until first occupied one > 0.
|
||||
burstFreq.add(time, 1f); // TODO: Remove float packets or do this properly.
|
||||
violation = Math.max(violation, burst - burstDirect);
|
||||
violation = Math.max(violation, burstEPM * (double) (burstFreq.bucketDuration() * burstFreq.numberOfBuckets()) / 60000.0 - (double) burstFreq.score(0f));
|
||||
}
|
||||
return Math.max(0.0, violation);
|
||||
}
|
||||
|
||||
}
|
|
@ -280,6 +280,12 @@ public class TrigUtil {
|
|||
final double dz = Math.abs(z1 - z2);
|
||||
return dx * dx + dy * dy + dz * dz;
|
||||
}
|
||||
|
||||
public static final double distanceSquared(final double x1, final double z1, final double x2, final double z2) {
|
||||
final double dx = Math.abs(x1 - x2);
|
||||
final double dz = Math.abs(z1 - z2);
|
||||
return dx * dx + dz * dz;
|
||||
}
|
||||
|
||||
/**
|
||||
* 2D-distance in x-z plane.
|
||||
|
|
Loading…
Reference in New Issue
Block a user