From d71d4a856985e28caf3dd90174dbe5fc9f043f09 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 1 May 2011 17:37:05 -0700 Subject: [PATCH] Added expiration timer to sessions. Sessions will now last up to 10 minutes (by default) before removed, so you can quickly disconnect (or crash) and come back and still maintain your history. --- .../com/sk89q/worldedit/LocalSession.java | 18 +++ .../com/sk89q/worldedit/SessionCheck.java | 37 ++++++ .../java/com/sk89q/worldedit/WorldEdit.java | 120 +++++++++++++----- .../worldedit/bukkit/BukkitConfiguration.java | 1 + .../sk89q/worldedit/bukkit/SessionTimer.java | 51 ++++++++ .../bukkit/WorldEditPlayerListener.java | 2 +- .../worldedit/bukkit/WorldEditPlugin.java | 3 + .../com/sk89q/worldedit/tools/BrushTool.java | 1 + src/main/resources/config.yml | 1 + 9 files changed, 198 insertions(+), 36 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/SessionCheck.java create mode 100644 src/main/java/com/sk89q/worldedit/bukkit/SessionTimer.java diff --git a/src/main/java/com/sk89q/worldedit/LocalSession.java b/src/main/java/com/sk89q/worldedit/LocalSession.java index 27de2e9cc..297c31fa8 100644 --- a/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -51,9 +51,11 @@ import com.sk89q.worldedit.regions.RegionSelector; */ public class LocalSession { public static int MAX_HISTORY_SIZE = 15; + public static int EXPIRATION_GRACE = 600000; private LocalConfiguration config; + private long expirationTime = 0; private LocalWorld selectionWorld; private RegionSelector selector = new CuboidRegionSelector(); private boolean placeAtPos1 = false; @@ -615,4 +617,20 @@ public class LocalSession { return date.getBeginCalendar(); } } + + /** + * Update the last update time for calculating expiration. + */ + public void update() { + expirationTime = System.currentTimeMillis(); + } + + /** + * Returns whether this session has expired. + * + * @return + */ + public boolean hasExpired() { + return System.currentTimeMillis() - expirationTime > EXPIRATION_GRACE; + } } diff --git a/src/main/java/com/sk89q/worldedit/SessionCheck.java b/src/main/java/com/sk89q/worldedit/SessionCheck.java new file mode 100644 index 000000000..38ed81cbe --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/SessionCheck.java @@ -0,0 +1,37 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit; + +/** + * Used to discard old sessions. + * + * @author sk89q + */ +public interface SessionCheck { + + /** + * Checks if a player is online. + * + * @param name + * @return + */ + public boolean isOnlinePlayer(String name); + +} diff --git a/src/main/java/com/sk89q/worldedit/WorldEdit.java b/src/main/java/com/sk89q/worldedit/WorldEdit.java index 55d14fe45..81fe35060 100644 --- a/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -129,42 +129,46 @@ public class WorldEdit { * @return */ public LocalSession getSession(LocalPlayer player) { - if (sessions.containsKey(player.getName())) { - return sessions.get(player.getName()); - } + LocalSession session; - LocalSession session = new LocalSession(config); - - // Set the limit on the number of blocks that an operation can - // change at once, or don't if the player has an override or there - // is no limit. There is also a default limit - if (!player.hasPermission("worldedit.limit.unrestricted") - && config.maxChangeLimit > -1) { - - // If the default limit is infinite but there is a maximum - // limit, make sure to not have it be overridden - if (config.defaultChangeLimit < 0) { - session.setBlockChangeLimit(config.maxChangeLimit); - } else { - // Bound the change limit - int limit = Math.min(config.defaultChangeLimit, - config.maxChangeLimit); - session.setBlockChangeLimit(limit); + synchronized (sessions) { + if (sessions.containsKey(player.getName())) { + return sessions.get(player.getName()); } - } else { - // No change limit or override - session.setBlockChangeLimit(config.defaultChangeLimit); + + session = new LocalSession(config); + + // Set the limit on the number of blocks that an operation can + // change at once, or don't if the player has an override or there + // is no limit. There is also a default limit + if (!player.hasPermission("worldedit.limit.unrestricted") + && config.maxChangeLimit > -1) { + + // If the default limit is infinite but there is a maximum + // limit, make sure to not have it be overridden + if (config.defaultChangeLimit < 0) { + session.setBlockChangeLimit(config.maxChangeLimit); + } else { + // Bound the change limit + int limit = Math.min(config.defaultChangeLimit, + config.maxChangeLimit); + session.setBlockChangeLimit(limit); + } + } else { + // No change limit or override + session.setBlockChangeLimit(config.defaultChangeLimit); + } + + // Have the session use inventory if it's enabled and the player + // doesn't have an override + session.setUseInventory(config.useInventory + && (!config.useInventoryOverride + || !player.hasPermission("worldedit.inventory.unrestricted"))); + + // Remember the session + sessions.put(player.getName(), session); } - // Have the session use inventory if it's enabled and the player - // doesn't have an override - session.setUseInventory(config.useInventory - && (!config.useInventoryOverride - || !player.hasPermission("worldedit.inventory.unrestricted"))); - - // Remember the session - sessions.put(player.getName(), session); - return session; } @@ -175,7 +179,9 @@ public class WorldEdit { * @return */ public boolean hasSession(LocalPlayer player) { - return sessions.containsKey(player.getName()); + synchronized (sessions) { + return sessions.containsKey(player.getName()); + } } /** @@ -726,14 +732,18 @@ public class WorldEdit { * @param player */ public void removeSession(LocalPlayer player) { - sessions.remove(player.getName()); + synchronized (sessions) { + sessions.remove(player.getName()); + } } /** * Remove all sessions. */ public void clearSessions() { - sessions.clear(); + synchronized (sessions) { + sessions.clear(); + } } /** @@ -788,9 +798,49 @@ public class WorldEdit { * * @param player */ + @Deprecated public void handleDisconnect(LocalPlayer player) { + forgetPlayer(player); + } + + /** + * + * @param player + */ + public void markExpire(LocalPlayer player) { + synchronized (sessions) { + LocalSession session = sessions.get(player.getName()); + if (session != null) { + session.update(); + } + } + } + + /** + * Forget a player. + * + * @param player + */ + public void forgetPlayer(LocalPlayer player) { removeSession(player); } + + /* + * Flush expired sessions. + */ + public void flushExpiredSessions(SessionCheck checker) { + synchronized (sessions) { + Iterator> it = sessions.entrySet().iterator(); + + while (it.hasNext()) { + Map.Entry entry = it.next(); + if (entry.getValue().hasExpired() + && !checker.isOnlinePlayer(entry.getKey())) { + it.remove(); + } + } + } + } /** * Called on arm swing. diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java b/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java index dfab46b9d..564a8e905 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java +++ b/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java @@ -82,6 +82,7 @@ public class BukkitConfiguration extends LocalConfiguration { noOpPermissions = config.getBoolean("no-op-permissions", false); LocalSession.MAX_HISTORY_SIZE = Math.max(15, config.getInt("history.size", 15)); + LocalSession.EXPIRATION_GRACE = config.getInt("history.expiration", 10) * 60 * 1000; String snapshotsDir = config.getString("snapshots.directory", ""); if (!snapshotsDir.trim().equals("")) { diff --git a/src/main/java/com/sk89q/worldedit/bukkit/SessionTimer.java b/src/main/java/com/sk89q/worldedit/bukkit/SessionTimer.java new file mode 100644 index 000000000..4fbeb6f3f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/bukkit/SessionTimer.java @@ -0,0 +1,51 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit.bukkit; + +import org.bukkit.Server; +import org.bukkit.entity.Player; +import com.sk89q.worldedit.SessionCheck; +import com.sk89q.worldedit.WorldEdit; + +/** + * Used to remove expired sessions in Bukkit. + * + * @author sk89q + */ +public class SessionTimer implements Runnable { + + private WorldEdit worldEdit; + private SessionCheck checker; + + public SessionTimer(WorldEdit worldEdit, final Server server) { + this.worldEdit = worldEdit; + this.checker = new SessionCheck() { + public boolean isOnlinePlayer(String name) { + Player player = server.getPlayer(name); + return player != null && player.isOnline(); + } + }; + } + + public void run() { + worldEdit.flushExpiredSessions(checker); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlayerListener.java b/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlayerListener.java index b78a651d7..0e6063fb1 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlayerListener.java +++ b/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlayerListener.java @@ -79,7 +79,7 @@ public class WorldEditPlayerListener extends PlayerListener { */ @Override public void onPlayerQuit(PlayerQuitEvent event) { - plugin.getWorldEdit().handleDisconnect(wrapPlayer(event.getPlayer())); + plugin.getWorldEdit().markExpire(wrapPlayer(event.getPlayer())); } /** diff --git a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index d0387e51b..5e6dffdc3 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -101,6 +101,9 @@ public class WorldEditPlugin extends JavaPlugin { // Now we can register events! registerEvents(); + + getServer().getScheduler().scheduleAsyncRepeatingTask(this, + new SessionTimer(controller, getServer()), 120, 120); } /** diff --git a/src/main/java/com/sk89q/worldedit/tools/BrushTool.java b/src/main/java/com/sk89q/worldedit/tools/BrushTool.java index e78f101c5..bd7fbf832 100644 --- a/src/main/java/com/sk89q/worldedit/tools/BrushTool.java +++ b/src/main/java/com/sk89q/worldedit/tools/BrushTool.java @@ -83,6 +83,7 @@ public class BrushTool implements TraceTool { * Set the brush. * * @param brush + * @param perm */ public void setBrush(Brush brush, String perm) { this.brush = brush; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 0b1a61511..687efcd6f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -52,6 +52,7 @@ saving: history: size: 15 + expiration: 10 wand-item: 271 shell-save-type: