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: