mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2025-01-15 03:51:20 +01:00
Optimize TickTask (reduce footprint of copying), code formatting.
This commit is contained in:
parent
0118f4334f
commit
27913a758d
@ -1,6 +1,5 @@
|
||||
package fr.neatmonster.nocheatplus.utilities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
@ -32,14 +31,16 @@ public class TickTask implements Runnable {
|
||||
public CheckType checkType;
|
||||
public String playerName;
|
||||
private final int hashCode;
|
||||
public PermissionUpdateEntry(final String playerName, final CheckType checkType){
|
||||
public PermissionUpdateEntry(final String playerName, final CheckType checkType) {
|
||||
this.playerName = playerName;
|
||||
this.checkType = checkType;
|
||||
hashCode = playerName.hashCode() ^ checkType.hashCode();
|
||||
}
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof PermissionUpdateEntry)) return false;
|
||||
if (!(obj instanceof PermissionUpdateEntry)) {
|
||||
return false;
|
||||
}
|
||||
final PermissionUpdateEntry other = (PermissionUpdateEntry) obj;
|
||||
return playerName.equals(other.playerName) && checkType.equals(other.checkType);
|
||||
}
|
||||
@ -51,11 +52,15 @@ public class TickTask implements Runnable {
|
||||
|
||||
public static final int lagMaxTicks = 80;
|
||||
|
||||
/** Lock for accessing permissionUpdates. */
|
||||
private static final Object permissionLock = new Object();
|
||||
/** Permissions to update: player name -> check type. */
|
||||
private static final Set<PermissionUpdateEntry> permissionUpdates = new LinkedHashSet<PermissionUpdateEntry>(50);
|
||||
private static Set<PermissionUpdateEntry> permissionUpdates = new LinkedHashSet<PermissionUpdateEntry>(50);
|
||||
|
||||
/** Lock for delayedActions. */
|
||||
private static final Object actionLock = new Object();
|
||||
/** Actions to execute. */
|
||||
private static final List<ViolationData> delayedActions = new LinkedList<ViolationData>();
|
||||
private static List<ViolationData> delayedActions = new LinkedList<ViolationData>();
|
||||
|
||||
/** Tick listeners to call every tick. */
|
||||
private static final Set<TickListener> tickListeners = new LinkedHashSet<TickListener>();
|
||||
@ -88,7 +93,7 @@ public class TickTask implements Runnable {
|
||||
protected static boolean locked = true;
|
||||
|
||||
static{
|
||||
for (int i = 0; i < spikeDurations.length; i++){
|
||||
for (int i = 0; i < spikeDurations.length; i++) {
|
||||
spikes[i] = new ActionFrequency(3, 1000L * 60L * 20L);
|
||||
}
|
||||
}
|
||||
@ -100,13 +105,15 @@ public class TickTask implements Runnable {
|
||||
*/
|
||||
public static void executeActions() {
|
||||
final List<ViolationData> copyActions;
|
||||
synchronized (delayedActions) {
|
||||
if (delayedActions.isEmpty()) return;
|
||||
copyActions = new ArrayList<ViolationData>(delayedActions);
|
||||
delayedActions.clear();
|
||||
synchronized (actionLock) {
|
||||
if (delayedActions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
copyActions = delayedActions;
|
||||
delayedActions = new LinkedList<ViolationData>();
|
||||
}
|
||||
for (int i = 0; i < copyActions.size(); i++){
|
||||
copyActions.get(i).executeActions();
|
||||
for (final ViolationData vd : copyActions) {
|
||||
vd.executeActions();
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,25 +122,31 @@ public class TickTask implements Runnable {
|
||||
* Note: Only call from the main thread!
|
||||
*/
|
||||
public static void updatePermissions() {
|
||||
final List<PermissionUpdateEntry> copyPermissions;
|
||||
synchronized (permissionUpdates) {
|
||||
if (permissionUpdates.isEmpty()) return;
|
||||
copyPermissions = new ArrayList<PermissionUpdateEntry>(permissionUpdates);
|
||||
permissionUpdates.clear();
|
||||
final Set<PermissionUpdateEntry> copyPermissions;
|
||||
synchronized (permissionLock) {
|
||||
if (permissionUpdates.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
copyPermissions = permissionUpdates;
|
||||
permissionUpdates = new LinkedHashSet<PermissionUpdateEntry>(50);
|
||||
}
|
||||
for (int i = 0; i < copyPermissions.size(); i++){
|
||||
final PermissionUpdateEntry entry = copyPermissions.get(i);
|
||||
for (final PermissionUpdateEntry entry : copyPermissions) {
|
||||
final Player player = DataManager.getPlayer(entry.playerName); // Might use exact name by contract.
|
||||
if (player == null || !player.isOnline()) continue;
|
||||
if (player == null || !player.isOnline()) {
|
||||
continue;
|
||||
}
|
||||
final String[] perms = entry.checkType.getConfigFactory().getConfig(player).getCachePermissions();
|
||||
if (perms == null) continue;
|
||||
if (perms == null) {
|
||||
continue;
|
||||
}
|
||||
final ICheckData data = entry.checkType.getDataFactory().getData(player);
|
||||
for (int j = 0; j < perms.length; j ++){
|
||||
for (int j = 0; j < perms.length; j ++) {
|
||||
final String permission = perms[j];
|
||||
data.setCachedPermission(permission, player.hasPermission(permission));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Public static access methods
|
||||
/**
|
||||
* Access method to request permission updates.<br>
|
||||
@ -141,9 +154,11 @@ public class TickTask implements Runnable {
|
||||
* @param playerName
|
||||
* @param checkType
|
||||
*/
|
||||
public static void requestPermissionUpdate(final String playerName, final CheckType checkType){
|
||||
synchronized(permissionUpdates){
|
||||
if (locked) return;
|
||||
public static void requestPermissionUpdate(final String playerName, final CheckType checkType) {
|
||||
synchronized(permissionLock) {
|
||||
if (locked) {
|
||||
return;
|
||||
}
|
||||
permissionUpdates.add(new PermissionUpdateEntry(playerName, checkType));
|
||||
}
|
||||
}
|
||||
@ -154,8 +169,10 @@ public class TickTask implements Runnable {
|
||||
* @param actions
|
||||
*/
|
||||
public static void requestActionsExecution(final ViolationData actions) {
|
||||
synchronized (delayedActions) {
|
||||
if (locked) return;
|
||||
synchronized (actionLock) {
|
||||
if (locked) {
|
||||
return;
|
||||
}
|
||||
delayedActions.add(actions);
|
||||
}
|
||||
}
|
||||
@ -168,13 +185,15 @@ public class TickTask implements Runnable {
|
||||
* <li>For OnDemandTickListenerS, setRegistered(true) will get called if not locked.</li>
|
||||
* @param listener
|
||||
*/
|
||||
public static void addTickListener(TickListener listener){
|
||||
public static void addTickListener(TickListener listener) {
|
||||
synchronized (tickListeners) {
|
||||
if (locked) return; // TODO: Boolean return value ?
|
||||
if (!tickListeners.contains(listener)){
|
||||
if (locked) {
|
||||
return; // TODO: Boolean return value ?
|
||||
}
|
||||
if (!tickListeners.contains(listener)) {
|
||||
tickListeners.add(listener);
|
||||
}
|
||||
if (listener instanceof OnDemandTickListener){
|
||||
if (listener instanceof OnDemandTickListener) {
|
||||
((OnDemandTickListener) listener).setRegistered(true);
|
||||
}
|
||||
}
|
||||
@ -189,9 +208,9 @@ public class TickTask implements Runnable {
|
||||
* @param listener
|
||||
* @return If previously contained.
|
||||
*/
|
||||
public static boolean removeTickListener(TickListener listener){
|
||||
public static boolean removeTickListener(TickListener listener) {
|
||||
synchronized (tickListeners) {
|
||||
if (listener instanceof OnDemandTickListener){
|
||||
if (listener instanceof OnDemandTickListener) {
|
||||
((OnDemandTickListener) listener).setRegistered(false);
|
||||
}
|
||||
return tickListeners.remove(listener);
|
||||
@ -208,15 +227,15 @@ public class TickTask implements Runnable {
|
||||
public static void removeAllTickListeners() {
|
||||
synchronized (tickListeners) {
|
||||
// Gracefully set OnDemandTickListeners to unregistered.
|
||||
for (final TickListener listener : tickListeners){
|
||||
if (listener instanceof OnDemandTickListener){
|
||||
for (final TickListener listener : tickListeners) {
|
||||
if (listener instanceof OnDemandTickListener) {
|
||||
try{
|
||||
final OnDemandTickListener odtl = (OnDemandTickListener) listener;
|
||||
if (odtl.isRegistered()){ // Could use the flag, but this is better.
|
||||
if (odtl.isRegistered()) { // Could use the flag, but this is better.
|
||||
odtl.setRegistered(false);
|
||||
}
|
||||
}
|
||||
catch(Throwable t){
|
||||
catch(Throwable t) {
|
||||
// Unlikely.
|
||||
LogUtil.logWarning("[NoCheatPlus] Failed to set OnDemandTickListener to unregistered state: " + t.getClass().getSimpleName());
|
||||
LogUtil.logWarning(t);
|
||||
@ -233,7 +252,7 @@ public class TickTask implements Runnable {
|
||||
* NOTE: Can be called from other threads.
|
||||
* @return The current tick count.
|
||||
*/
|
||||
public static final int getTick(){
|
||||
public static final int getTick() {
|
||||
return tick;
|
||||
}
|
||||
|
||||
@ -241,7 +260,7 @@ public class TickTask implements Runnable {
|
||||
* Get the time at which the task was started.
|
||||
* @return
|
||||
*/
|
||||
public static final long getTimeStart(){
|
||||
public static final long getTimeStart() {
|
||||
return timeStart;
|
||||
}
|
||||
|
||||
@ -249,7 +268,7 @@ public class TickTask implements Runnable {
|
||||
* Time when last time processing was finished.
|
||||
* @return
|
||||
*/
|
||||
public static final long getTimeLast(){
|
||||
public static final long getTimeLast() {
|
||||
return timeLast;
|
||||
}
|
||||
|
||||
@ -259,7 +278,7 @@ public class TickTask implements Runnable {
|
||||
* @param ms Past milliseconds to cover. A longer period of time may be used, up to two times if ms > lagMaxTicks * 50.
|
||||
* @return Lag factor (1.0 = 20 tps, 2.0 = 10 tps), excluding the current tick.
|
||||
*/
|
||||
public static final float getLag(final long ms){
|
||||
public static final float getLag(final long ms) {
|
||||
return getLag(ms, false);
|
||||
}
|
||||
|
||||
@ -270,16 +289,18 @@ public class TickTask implements Runnable {
|
||||
* @param exact If to include the currently running tick, if possible. Should only be set to true, if called from the main thread (or while the main thread is blocked).
|
||||
* @return Lag factor (1.0 = 20 tps, 2.0 = 10 tps).
|
||||
*/
|
||||
public static final float getLag(final long ms, final boolean exact){
|
||||
if (ms < 0){
|
||||
public static final float getLag(final long ms, final boolean exact) {
|
||||
if (ms < 0) {
|
||||
// Account for freezing (i.e. check timeLast, might be an extra method)!
|
||||
return getLag(0, exact);
|
||||
}
|
||||
else if (ms > lagMaxCoveredMs){
|
||||
else if (ms > lagMaxCoveredMs) {
|
||||
return getLag(lagMaxCoveredMs, exact);
|
||||
}
|
||||
final int tick = TickTask.tick;
|
||||
if (tick == 0) return 1f;
|
||||
if (tick == 0) {
|
||||
return 1f;
|
||||
}
|
||||
final int add = ms > 0 && (ms % 50) == 0 ? 0 : 1;
|
||||
// TODO: Consider: Put "exact" block here, subtract a tick if appropriate?
|
||||
final int totalTicks = Math.min(tick, add + (int) (ms / 50));
|
||||
@ -288,17 +309,19 @@ public class TickTask implements Runnable {
|
||||
long covered = maxTick * 50;
|
||||
|
||||
// Only count fully covered:
|
||||
if (totalTicks > lagMaxTicks){
|
||||
if (totalTicks > lagMaxTicks) {
|
||||
int maxTickSq = Math.min(lagMaxTicks, totalTicks / lagMaxTicks);
|
||||
if (lagMaxTicks * maxTickSq == totalTicks) maxTickSq -= 1;
|
||||
if (lagMaxTicks * maxTickSq == totalTicks) {
|
||||
maxTickSq -= 1;
|
||||
}
|
||||
sum += tickDurationsSq[maxTickSq - 1];
|
||||
covered += lagMaxTicks * 50 * maxTickSq;
|
||||
}
|
||||
|
||||
if (exact){
|
||||
if (exact) {
|
||||
// Attempt to count in the current tick.
|
||||
final long passed = System.currentTimeMillis() - timeLast;
|
||||
if (passed > 50){
|
||||
if (passed > 50) {
|
||||
// Only count in in the case of "overtime".
|
||||
covered += 50;
|
||||
sum += passed;
|
||||
@ -313,7 +336,7 @@ public class TickTask implements Runnable {
|
||||
* @deprecated What is moderate :) ?
|
||||
* @return
|
||||
*/
|
||||
public static final int getModerateLagSpikes(){
|
||||
public static final int getModerateLagSpikes() {
|
||||
spikes[0].update(System.currentTimeMillis());
|
||||
return (int) spikes[0].score(1f);
|
||||
}
|
||||
@ -323,7 +346,7 @@ public class TickTask implements Runnable {
|
||||
* @deprecated What is heavy :) ?
|
||||
* @return
|
||||
*/
|
||||
public static final int getHeavyLagSpikes(){
|
||||
public static final int getHeavyLagSpikes() {
|
||||
spikes[1].update(System.currentTimeMillis());
|
||||
return (int) spikes[1].score(1f);
|
||||
}
|
||||
@ -332,7 +355,7 @@ public class TickTask implements Runnable {
|
||||
* Get total number of lag spikes counted at all. This is the number of lag spikes with a duration above spikeDuations[0] which should be 150 ms. This is the score of spikes[0].
|
||||
* @return
|
||||
*/
|
||||
public static final int getNumberOfLagSpikes(){
|
||||
public static final int getNumberOfLagSpikes() {
|
||||
spikes[0].update(System.currentTimeMillis());
|
||||
return (int) spikes[0].score(1f);
|
||||
}
|
||||
@ -341,7 +364,7 @@ public class TickTask implements Runnable {
|
||||
* Get the stepping for lag spike duration tracking.
|
||||
* @return
|
||||
*/
|
||||
public static final long[] getLagSpikeDurations(){
|
||||
public static final long[] getLagSpikeDurations() {
|
||||
return Arrays.copyOf(spikeDurations, spikeDurations.length);
|
||||
}
|
||||
|
||||
@ -349,10 +372,10 @@ public class TickTask implements Runnable {
|
||||
* Get lag spike count according to getLagSpikeDurations() values. Entries of lower indexes contain the entries of higher indexes (so subtraction would be necessary to get spikes from...to).
|
||||
* @return
|
||||
*/
|
||||
public static final int[] getLagSpikes(){
|
||||
public static final int[] getLagSpikes() {
|
||||
final int[] out = new int[spikeDurations.length];
|
||||
final long now = System.currentTimeMillis();
|
||||
for (int i = 0; i < spikeDurations.length; i++){
|
||||
for (int i = 0; i < spikeDurations.length; i++) {
|
||||
spikes[i].update(now);
|
||||
out[i] = (int) spikes[i].score(1f);
|
||||
}
|
||||
@ -363,21 +386,27 @@ public class TickTask implements Runnable {
|
||||
* Check if new permission update requests and actions can be added.
|
||||
* @return True if locked.
|
||||
*/
|
||||
public boolean isLocked(){
|
||||
public boolean isLocked() {
|
||||
return locked;
|
||||
}
|
||||
|
||||
// Public methods for internal use.
|
||||
public static int start(final Plugin plugin){
|
||||
public static int start(final Plugin plugin) {
|
||||
cancel();
|
||||
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, new TickTask(), 1, 1);
|
||||
if (taskId != -1) timeStart = System.currentTimeMillis();
|
||||
else timeStart = 0;
|
||||
if (taskId != -1) {
|
||||
timeStart = System.currentTimeMillis();
|
||||
}
|
||||
else {
|
||||
timeStart = 0;
|
||||
}
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public static void cancel(){
|
||||
if (taskId == -1) return;
|
||||
public static void cancel() {
|
||||
if (taskId == -1) {
|
||||
return;
|
||||
}
|
||||
Bukkit.getScheduler().cancelTask(taskId);
|
||||
taskId = -1;
|
||||
}
|
||||
@ -387,18 +416,18 @@ public class TickTask implements Runnable {
|
||||
* NOTE: This is just a flag, no sync is done here.
|
||||
* @param locked
|
||||
*/
|
||||
public static void setLocked(boolean locked){
|
||||
public static void setLocked(boolean locked) {
|
||||
TickTask.locked = locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty queues (better call after setLocked(true)) and tickListeners.
|
||||
*/
|
||||
public static void purge(){
|
||||
synchronized (permissionUpdates) {
|
||||
public static void purge() {
|
||||
synchronized (permissionLock) {
|
||||
permissionUpdates.clear();
|
||||
}
|
||||
synchronized (delayedActions) {
|
||||
synchronized (actionLock) {
|
||||
delayedActions.clear();
|
||||
}
|
||||
synchronized (tickListeners) {
|
||||
@ -409,14 +438,14 @@ public class TickTask implements Runnable {
|
||||
/**
|
||||
* Reset tick and tick stats to 0 (!).
|
||||
*/
|
||||
public static void reset(){
|
||||
public static void reset() {
|
||||
tick = 0;
|
||||
timeLast = 0;
|
||||
for (int i = 0; i < lagMaxTicks; i++){
|
||||
for (int i = 0; i < lagMaxTicks; i++) {
|
||||
tickDurations[i] = 0;
|
||||
tickDurationsSq[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < spikeDurations.length; i++){
|
||||
for (int i = 0; i < spikeDurations.length; i++) {
|
||||
spikes[i].clear(0);
|
||||
}
|
||||
}
|
||||
@ -428,23 +457,24 @@ public class TickTask implements Runnable {
|
||||
*
|
||||
*/
|
||||
private final void notifyListeners() {
|
||||
final List<TickListener> copyListeners;
|
||||
// Copy for iterating, to allow reentrant registration while processing.
|
||||
final TickListener[] copyListeners;
|
||||
synchronized (tickListeners) {
|
||||
// Synchronized to allow concurrent adding and removal.
|
||||
// (Ignores the locked state while still running.)
|
||||
// TODO: Policy for locked state. Though locking should only happen during onDisable, so before / after the task is run anyway.
|
||||
if (tickListeners.isEmpty()){
|
||||
if (tickListeners.isEmpty()) {
|
||||
// Future purpose.
|
||||
return;
|
||||
}
|
||||
copyListeners = new ArrayList<TickListener>(tickListeners);
|
||||
}
|
||||
for (int i = 0; i < copyListeners.size(); i++){
|
||||
final TickListener listener = copyListeners.get(i);
|
||||
copyListeners = tickListeners.toArray(new TickListener[tickListeners.size()]);
|
||||
}
|
||||
for (int i = 0; i < copyListeners.length; i++) {
|
||||
final TickListener listener = copyListeners[i];
|
||||
try{
|
||||
listener.onTick(tick, timeLast);
|
||||
}
|
||||
catch(Throwable t){
|
||||
catch(Throwable t) {
|
||||
LogUtil.logSevere("[NoCheatPlus] (TickTask) TickListener generated an exception:");
|
||||
LogUtil.logSevere(t);
|
||||
}
|
||||
@ -469,37 +499,37 @@ public class TickTask implements Runnable {
|
||||
LogUtil.logWarning("[NoCheatPlus] System time ran backwards (" + timeLast + "->" + time + "), clear all data and history...");
|
||||
DataManager.clearData(CheckType.ALL);
|
||||
lastDur = 50;
|
||||
for (int i = 0; i < spikeDurations.length; i++){
|
||||
for (int i = 0; i < spikeDurations.length; i++) {
|
||||
spikes[i].clear(0);
|
||||
}
|
||||
}
|
||||
else if (tick > 0){
|
||||
else if (tick > 0) {
|
||||
lastDur = time - timeLast;
|
||||
}
|
||||
else{
|
||||
else {
|
||||
lastDur = 50;
|
||||
}
|
||||
|
||||
// Update sums of sums of tick durations.
|
||||
if (tick > 0 && (tick % lagMaxTicks) == 0){
|
||||
if (tick > 0 && (tick % lagMaxTicks) == 0) {
|
||||
final long sum = tickDurations[lagMaxTicks - 1];
|
||||
for (int i = 1; i < lagMaxTicks; i++){
|
||||
for (int i = 1; i < lagMaxTicks; i++) {
|
||||
tickDurationsSq[i] = tickDurationsSq[i - 1] + sum;
|
||||
}
|
||||
tickDurationsSq[0] = sum;
|
||||
}
|
||||
|
||||
// Update tick duration sums.
|
||||
for (int i = 1; i < lagMaxTicks; i++){
|
||||
for (int i = 1; i < lagMaxTicks; i++) {
|
||||
tickDurations[i] = tickDurations[i - 1] + lastDur;
|
||||
}
|
||||
tickDurations[0] = lastDur;
|
||||
|
||||
// Lag spikes counting. [Subject to adjustments!]
|
||||
if (lastDur > spikeDurations[0] && tick > 0){
|
||||
if (lastDur > spikeDurations[0] && tick > 0) {
|
||||
spikes[0].add(time, 1f);
|
||||
for (int i = 1; i < spikeDurations.length; i++){
|
||||
if (lastDur > spikeDurations[i]){
|
||||
for (int i = 1; i < spikeDurations.length; i++) {
|
||||
if (lastDur > spikeDurations[i]) {
|
||||
spikes[i].add(time, 1f);
|
||||
}
|
||||
else break;
|
||||
|
Loading…
Reference in New Issue
Block a user