mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-01-09 18:07:39 +01:00
commit
714330f694
@ -22,7 +22,7 @@ allprojects {
|
|||||||
wrapper.gradleVersion = "5.5.1"
|
wrapper.gradleVersion = "5.5.1"
|
||||||
|
|
||||||
group "com.djrapitops"
|
group "com.djrapitops"
|
||||||
version "4.9.3"
|
version "4.9.4"
|
||||||
|
|
||||||
test {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
|
@ -25,10 +25,7 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
import org.bukkit.event.player.*;
|
||||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
|
||||||
import org.bukkit.event.player.PlayerEvent;
|
|
||||||
import org.bukkit.event.player.PlayerMoveEvent;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -78,6 +75,7 @@ public class AFKListener implements Listener {
|
|||||||
if (ignored) {
|
if (ignored) {
|
||||||
AFK_TRACKER.hasIgnorePermission(uuid);
|
AFK_TRACKER.hasIgnorePermission(uuid);
|
||||||
ignorePermissionInfo.put(uuid, true);
|
ignorePermissionInfo.put(uuid, true);
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
ignorePermissionInfo.put(uuid, false);
|
ignorePermissionInfo.put(uuid, false);
|
||||||
}
|
}
|
||||||
@ -108,4 +106,9 @@ public class AFKListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
|
public void onLeave(PlayerQuitEvent event) {
|
||||||
|
ignorePermissionInfo.remove(event.getPlayer().getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -24,11 +24,9 @@ import com.djrapitops.plan.db.access.Executable;
|
|||||||
import com.djrapitops.plan.db.access.Query;
|
import com.djrapitops.plan.db.access.Query;
|
||||||
import com.djrapitops.plugin.utilities.Verify;
|
import com.djrapitops.plugin.utilities.Verify;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.*;
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Savepoint;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a database transaction.
|
* Represents a database transaction.
|
||||||
@ -37,6 +35,9 @@ import java.util.UUID;
|
|||||||
*/
|
*/
|
||||||
public abstract class Transaction {
|
public abstract class Transaction {
|
||||||
|
|
||||||
|
// SQLite version on 1.8.8 does not support savepoints, see createSavePoint() method
|
||||||
|
private static final AtomicBoolean SUPPORTS_SAVE_POINTS = new AtomicBoolean(true);
|
||||||
|
|
||||||
private SQLDB db;
|
private SQLDB db;
|
||||||
protected DBType dbType;
|
protected DBType dbType;
|
||||||
|
|
||||||
@ -75,6 +76,9 @@ public abstract class Transaction {
|
|||||||
|
|
||||||
private void manageFailure(Exception statementFail) {
|
private void manageFailure(Exception statementFail) {
|
||||||
String failMsg = getClass().getSimpleName() + " failed: " + statementFail.getMessage();
|
String failMsg = getClass().getSimpleName() + " failed: " + statementFail.getMessage();
|
||||||
|
if (!SUPPORTS_SAVE_POINTS.get()) {
|
||||||
|
throw new DBOpException(failMsg + ", additionally rollbacks are not supported on this server version.", statementFail);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (Verify.notNull(connection, savepoint)) {
|
if (Verify.notNull(connection, savepoint)) {
|
||||||
connection.rollback(savepoint);
|
connection.rollback(savepoint);
|
||||||
@ -105,12 +109,31 @@ public abstract class Transaction {
|
|||||||
private void initializeTransaction(SQLDB db) {
|
private void initializeTransaction(SQLDB db) {
|
||||||
try {
|
try {
|
||||||
this.connection = db.getConnection();
|
this.connection = db.getConnection();
|
||||||
this.savepoint = connection.setSavepoint();
|
createSavePoint();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DBOpException(getClass().getSimpleName() + " initialization failed: " + e.getMessage(), e);
|
throw new DBOpException(getClass().getSimpleName() + " initialization failed: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createSavePoint() throws SQLException {
|
||||||
|
try {
|
||||||
|
this.savepoint = connection.setSavepoint();
|
||||||
|
} catch (SQLFeatureNotSupportedException noSavePoints) {
|
||||||
|
SUPPORTS_SAVE_POINTS.set(false);
|
||||||
|
} catch (SQLException sqlException) {
|
||||||
|
handleUnsupportedSQLiteSavePoints(sqlException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUnsupportedSQLiteSavePoints(SQLException sqlException) throws SQLException {
|
||||||
|
String errorMsg = sqlException.getMessage();
|
||||||
|
if (errorMsg.contains("unsupported") && errorMsg.contains("savepoints")) {
|
||||||
|
SUPPORTS_SAVE_POINTS.set(false);
|
||||||
|
} else {
|
||||||
|
throw sqlException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected <T> T query(Query<T> query) {
|
protected <T> T query(Query<T> query) {
|
||||||
return query.executeQuery(db);
|
return query.executeQuery(db);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.system.afk;
|
package com.djrapitops.plan.system.afk;
|
||||||
|
|
||||||
import com.djrapitops.plan.data.container.Session;
|
|
||||||
import com.djrapitops.plan.system.cache.SessionCache;
|
import com.djrapitops.plan.system.cache.SessionCache;
|
||||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||||
@ -33,6 +32,7 @@ public class AFKTracker {
|
|||||||
private final Set<UUID> usedAFKCommand;
|
private final Set<UUID> usedAFKCommand;
|
||||||
private final Map<UUID, Long> lastMovement;
|
private final Map<UUID, Long> lastMovement;
|
||||||
private final PlanConfig config;
|
private final PlanConfig config;
|
||||||
|
private Long afkThresholdMs;
|
||||||
|
|
||||||
public AFKTracker(PlanConfig config) {
|
public AFKTracker(PlanConfig config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
@ -40,37 +40,41 @@ public class AFKTracker {
|
|||||||
lastMovement = new HashMap<>();
|
lastMovement = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getAfkThreshold() {
|
||||||
|
if (afkThresholdMs == null) {
|
||||||
|
afkThresholdMs = config.get(TimeSettings.AFK_THRESHOLD);
|
||||||
|
}
|
||||||
|
return afkThresholdMs;
|
||||||
|
}
|
||||||
|
|
||||||
public void hasIgnorePermission(UUID uuid) {
|
public void hasIgnorePermission(UUID uuid) {
|
||||||
lastMovement.put(uuid, -1L);
|
lastMovement.put(uuid, -1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void usedAfkCommand(UUID uuid, long time) {
|
public void usedAfkCommand(UUID uuid, long time) {
|
||||||
usedAFKCommand.add(uuid);
|
usedAFKCommand.add(uuid);
|
||||||
lastMovement.put(uuid, time - config.get(TimeSettings.AFK_THRESHOLD));
|
lastMovement.put(uuid, time - getAfkThreshold());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void performedAction(UUID uuid, long time) {
|
public void performedAction(UUID uuid, long time) {
|
||||||
Long lastMoved = lastMovement.getOrDefault(uuid, time);
|
Long lastMoved = lastMovement.getOrDefault(uuid, time);
|
||||||
|
// Ignore afk permission
|
||||||
if (lastMoved == -1) {
|
if (lastMoved == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastMovement.put(uuid, time);
|
lastMovement.put(uuid, time);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (time - lastMoved < config.get(TimeSettings.AFK_THRESHOLD)) {
|
if (time - lastMoved < getAfkThreshold()) {
|
||||||
// Threshold not crossed, no action required.
|
// Threshold not crossed, no action required.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long removeAfkCommandEffect = usedAFKCommand.contains(uuid) ? config.get(TimeSettings.AFK_THRESHOLD) : 0;
|
long removeAfkCommandEffect = usedAFKCommand.contains(uuid) ? getAfkThreshold() : 0;
|
||||||
long timeAFK = time - lastMoved - removeAfkCommandEffect;
|
long timeAFK = time - lastMoved - removeAfkCommandEffect;
|
||||||
|
|
||||||
Optional<Session> cachedSession = SessionCache.getCachedSession(uuid);
|
SessionCache.getCachedSession(uuid)
|
||||||
if (!cachedSession.isPresent()) {
|
.ifPresent(session -> session.addAFKTime(timeAFK));
|
||||||
return;
|
|
||||||
}
|
|
||||||
Session session = cachedSession.get();
|
|
||||||
session.addAFKTime(timeAFK);
|
|
||||||
} finally {
|
} finally {
|
||||||
usedAFKCommand.remove(uuid);
|
usedAFKCommand.remove(uuid);
|
||||||
}
|
}
|
||||||
@ -89,6 +93,6 @@ public class AFKTracker {
|
|||||||
if (lastMoved == null || lastMoved == -1) {
|
if (lastMoved == null || lastMoved == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return time - lastMoved > config.get(TimeSettings.AFK_THRESHOLD);
|
return time - lastMoved > getAfkThreshold();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,10 +22,10 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to store active sessions of players in memory.
|
* This class is used to store active sessions of players in memory.
|
||||||
@ -35,7 +35,7 @@ import java.util.UUID;
|
|||||||
@Singleton
|
@Singleton
|
||||||
public class SessionCache {
|
public class SessionCache {
|
||||||
|
|
||||||
private static final Map<UUID, Session> ACTIVE_SESSIONS = new HashMap<>();
|
private static final Map<UUID, Session> ACTIVE_SESSIONS = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public SessionCache() {
|
public SessionCache() {
|
||||||
|
@ -23,8 +23,9 @@ import com.djrapitops.plugin.utilities.Verify;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.util.HashSet;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
|
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
|
||||||
|
|
||||||
@ -55,8 +56,7 @@ public class FileWatcher extends Thread {
|
|||||||
) {
|
) {
|
||||||
this.errorHandler = errorHandler;
|
this.errorHandler = errorHandler;
|
||||||
this.running = false;
|
this.running = false;
|
||||||
this.watchedFiles = new HashSet<>();
|
this.watchedFiles = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||||
|
|
||||||
|
|
||||||
Verify.isTrue(watchedPath.toFile().isDirectory(), () -> new IllegalArgumentException("Given File " + watchedPath.toString() + " was not a folder."));
|
Verify.isTrue(watchedPath.toFile().isDirectory(), () -> new IllegalArgumentException("Given File " + watchedPath.toString() + " was not a folder."));
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ public class FileWatcher extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void actOnModification(Path modifiedFile) {
|
private void actOnModification(Path modifiedFile) {
|
||||||
for (WatchedFile watchedFile : new HashSet<>(watchedFiles)) {
|
for (WatchedFile watchedFile : watchedFiles) {
|
||||||
watchedFile.modified(modifiedFile);
|
watchedFile.modified(modifiedFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
name: Plan
|
name: Plan
|
||||||
author: Rsl1122
|
author: Rsl1122
|
||||||
main: com.djrapitops.plan.PlanBungee
|
main: com.djrapitops.plan.PlanBungee
|
||||||
version: 4.9.3
|
version: 4.9.4
|
||||||
softdepend:
|
softdepend:
|
||||||
- AdvancedBan
|
- AdvancedBan
|
||||||
- LiteBans
|
- LiteBans
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
name: Plan
|
name: Plan
|
||||||
author: Rsl1122
|
author: Rsl1122
|
||||||
main: com.djrapitops.plan.Plan
|
main: com.djrapitops.plan.Plan
|
||||||
version: 4.9.3
|
version: 4.9.4
|
||||||
api-version: 1.13
|
api-version: 1.13
|
||||||
softdepend:
|
softdepend:
|
||||||
- ASkyBlock
|
- ASkyBlock
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package com.djrapitops.plan.db;
|
package com.djrapitops.plan.db;
|
||||||
|
|
||||||
import com.djrapitops.plan.system.PlanSystem;
|
import com.djrapitops.plan.system.PlanSystem;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
@ -52,6 +53,12 @@ public class H2Test implements DatabaseTest {
|
|||||||
.orElseThrow(IllegalStateException::new);
|
.orElseThrow(IllegalStateException::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void disableSystem() {
|
||||||
|
if (database != null) database.close();
|
||||||
|
system.disable();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Database db() {
|
public Database db() {
|
||||||
return database;
|
return database;
|
||||||
|
@ -20,6 +20,7 @@ import com.djrapitops.plan.data.container.GeoInfo;
|
|||||||
import com.djrapitops.plan.db.access.queries.ServerAggregateQueries;
|
import com.djrapitops.plan.db.access.queries.ServerAggregateQueries;
|
||||||
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
|
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
|
||||||
import com.djrapitops.plan.system.PlanSystem;
|
import com.djrapitops.plan.system.PlanSystem;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.Assumptions;
|
import org.junit.jupiter.api.Assumptions;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -65,6 +66,12 @@ class MySQLTest implements DatabaseTest {
|
|||||||
database = mysql.get();
|
database = mysql.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void disableSystem() {
|
||||||
|
if (database != null) database.close();
|
||||||
|
system.disable();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Database db() {
|
public Database db() {
|
||||||
return database;
|
return database;
|
||||||
|
@ -23,6 +23,7 @@ import com.djrapitops.plan.db.access.transactions.StoreServerInformationTransact
|
|||||||
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
|
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
|
||||||
import com.djrapitops.plan.system.PlanSystem;
|
import com.djrapitops.plan.system.PlanSystem;
|
||||||
import com.djrapitops.plan.system.info.server.Server;
|
import com.djrapitops.plan.system.info.server.Server;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@ -62,6 +63,12 @@ public class SQLiteTest implements DatabaseTest {
|
|||||||
.orElseThrow(IllegalStateException::new);
|
.orElseThrow(IllegalStateException::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void disableSystem() {
|
||||||
|
if (database != null) database.close();
|
||||||
|
system.disable();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Database db() {
|
public Database db() {
|
||||||
return database;
|
return database;
|
||||||
|
@ -42,7 +42,7 @@ import java.io.InputStream;
|
|||||||
@Plugin(
|
@Plugin(
|
||||||
id = "plan",
|
id = "plan",
|
||||||
name = "Plan",
|
name = "Plan",
|
||||||
version = "4.9.3",
|
version = "4.9.4",
|
||||||
description = "Player Analytics Plugin by Rsl1122",
|
description = "Player Analytics Plugin by Rsl1122",
|
||||||
authors = {"Rsl1122"},
|
authors = {"Rsl1122"},
|
||||||
dependencies = {
|
dependencies = {
|
||||||
|
@ -30,8 +30,11 @@ import org.spongepowered.api.event.entity.living.humanoid.player.PlayerChangeCli
|
|||||||
import org.spongepowered.api.event.entity.living.humanoid.player.TargetPlayerEvent;
|
import org.spongepowered.api.event.entity.living.humanoid.player.TargetPlayerEvent;
|
||||||
import org.spongepowered.api.event.filter.cause.First;
|
import org.spongepowered.api.event.filter.cause.First;
|
||||||
import org.spongepowered.api.event.message.MessageChannelEvent;
|
import org.spongepowered.api.event.message.MessageChannelEvent;
|
||||||
|
import org.spongepowered.api.event.network.ClientConnectionEvent;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,11 +50,13 @@ public class SpongeAFKListener {
|
|||||||
// Static so that /reload does not cause afk tracking to fail.
|
// Static so that /reload does not cause afk tracking to fail.
|
||||||
static AFKTracker AFK_TRACKER;
|
static AFKTracker AFK_TRACKER;
|
||||||
|
|
||||||
|
private final Map<UUID, Boolean> ignorePermissionInfo;
|
||||||
private final ErrorHandler errorHandler;
|
private final ErrorHandler errorHandler;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public SpongeAFKListener(PlanConfig config, ErrorHandler errorHandler) {
|
public SpongeAFKListener(PlanConfig config, ErrorHandler errorHandler) {
|
||||||
this.errorHandler = errorHandler;
|
this.errorHandler = errorHandler;
|
||||||
|
this.ignorePermissionInfo = new HashMap<>();
|
||||||
|
|
||||||
SpongeAFKListener.assignAFKTracker(config);
|
SpongeAFKListener.assignAFKTracker(config);
|
||||||
}
|
}
|
||||||
@ -84,8 +89,16 @@ public class SpongeAFKListener {
|
|||||||
UUID uuid = player.getUniqueId();
|
UUID uuid = player.getUniqueId();
|
||||||
long time = System.currentTimeMillis();
|
long time = System.currentTimeMillis();
|
||||||
|
|
||||||
if (player.hasPermission(Permissions.IGNORE_AFK.getPermission())) {
|
Boolean ignored = ignorePermissionInfo.get(uuid);
|
||||||
|
if (ignored == null) {
|
||||||
|
ignored = player.hasPermission(Permissions.IGNORE_AFK.getPermission());
|
||||||
|
}
|
||||||
|
if (ignored) {
|
||||||
AFK_TRACKER.hasIgnorePermission(uuid);
|
AFK_TRACKER.hasIgnorePermission(uuid);
|
||||||
|
ignorePermissionInfo.put(uuid, true);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
ignorePermissionInfo.put(uuid, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
AFK_TRACKER.performedAction(uuid, time);
|
AFK_TRACKER.performedAction(uuid, time);
|
||||||
@ -106,4 +119,8 @@ public class SpongeAFKListener {
|
|||||||
event(event);
|
event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Listener(order = Order.POST)
|
||||||
|
public void onLeave(ClientConnectionEvent.Disconnect event) {
|
||||||
|
ignorePermissionInfo.remove(event.getTargetEntity().getUniqueId());
|
||||||
|
}
|
||||||
}
|
}
|
@ -46,7 +46,7 @@ import java.nio.file.Path;
|
|||||||
@Plugin(
|
@Plugin(
|
||||||
id = "plan",
|
id = "plan",
|
||||||
name = "Plan",
|
name = "Plan",
|
||||||
version = "4.9.3",
|
version = "4.9.4",
|
||||||
description = "Player Analytics Plugin by Rsl1122",
|
description = "Player Analytics Plugin by Rsl1122",
|
||||||
authors = {"Rsl1122"}
|
authors = {"Rsl1122"}
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user