Skip to content

Instantly share code, notes, and snippets.

@dumptruckman
Last active May 1, 2020 05:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dumptruckman/9a24e6132e8bc9ddd4ef to your computer and use it in GitHub Desktop.
Save dumptruckman/9a24e6132e8bc9ddd4ef to your computer and use it in GitHub Desktop.
Safe Player Data Map
/* Copyright (C) dumptruckman 2014
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.plugin.Plugin;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* This class will allow you to create safe player data maps for your plugin.
* <p/>
* A safe player data map is basically just a <code>Map<Player, T></code> that will
* automatically purge itself of any entries related to a Player object that has
* gone offline. This means that you do not have to worry about memory leaks (or
* worse) from your player related data due to large amounts of players coming and
* going.
* <p/>
* To get started, you need to create an instance of PlayerDataFactory for your
* plugin. See {@link #getPlayerDataFactory(org.bukkit.plugin.Plugin)}.
*/
public final class PlayerDataFactory {
/**
* Gets the player data factory for the given plugin.
* <p/>
* This will create a new factory object if one does not already exist for the
* given plugin.
*
* @param plugin the plugin to retrieve the factory object for.
* @return the factory object for the given plugin.
*/
public static PlayerDataFactory getPlayerDataFactory(Plugin plugin) {
if (plugin == null) {
throw new IllegalArgumentException("plugin must not be null.");
}
if (!Bukkit.getPluginManager().isPluginEnabled(plugin)) {
throw new IllegalArgumentException("plugin must be enabled.");
}
PlayerDataFactory playerDataFactory = registeredDataFactories.get(plugin);
if (playerDataFactory == null) {
playerDataFactory = createNewPlayerDataFactory(plugin);
}
return playerDataFactory;
}
/**
* Creates a HashMap for tracking player data of the type of your choice.
* <p/>
* This Map will be purged automatically of any entries if the Player they are
* keyed to logs off.
*
* @param dataType The class representing the data type for the map entries.
* @param <T> The data type for the map entries.
* @return A new HashMap that keys Players to data.
*/
public <T> Map<Player, T> createPlayerDataHashMap(Class<T> dataType) {
Map<Player, T> playerDataMap = new HashMap<Player, T>();
managePlayerDataMap(playerDataMap);
return playerDataMap;
}
/**
* This causes the PlayerDataFactory to begin managing the given Map.
* <p/>
* Management by this PlayerDataFactory means the map will be purged automatically
* of any entries if the
* Player they are keyed to logs off.
* <p/>
* This method mostly provides convenience so you may use your own Map
* implementations.
*
* @param playerDataMap the map to begin managing.
*/
public void managePlayerDataMap(Map<Player, ?> playerDataMap) {
if (managedMaps.contains(playerDataMap)) {
throw new IllegalArgumentException("Map is already being managed by this PlayerDataFactory.");
}
managedMaps.add(playerDataMap);
}
private static final Map<Plugin, PlayerDataFactory> registeredDataFactories = new HashMap<Plugin, PlayerDataFactory>();
private static PlayerDataFactory createNewPlayerDataFactory(Plugin plugin) {
PlayerDataFactory playerDataFactory = new PlayerDataFactory(plugin);
return playerDataFactory;
}
private static class CleanupListener implements Listener {
private PlayerDataFactory dataFactory;
private CleanupListener(PlayerDataFactory dataFactory) {
this.dataFactory = dataFactory;
}
@EventHandler
public void pluginDisable(PluginDisableEvent event) {
if (registeredDataFactories.containsKey(event.getPlugin())) {
registeredDataFactories.remove(event.getPlugin());
}
}
@EventHandler
public void playerQuit(PlayerQuitEvent event) {
for (Map<Player, ?> map : dataFactory.managedMaps) {
if (map.containsKey(event.getPlayer())) {
map.remove(event.getPlayer());
}
}
}
}
private final Set<Map<Player, ?>> managedMaps = new LinkedHashSet<Map<Player, ?>>();
private PlayerDataFactory(Plugin plugin) {
CleanupListener cleanupListener = new CleanupListener(this);
plugin.getServer().getPluginManager().registerEvents(cleanupListener, plugin);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment