Skip to content

Instantly share code, notes, and snippets.

@DarkSeraphim
Last active August 29, 2015 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DarkSeraphim/2f7e2e0ec82b22358af2 to your computer and use it in GitHub Desktop.
Save DarkSeraphim/2f7e2e0ec82b22358af2 to your computer and use it in GitHub Desktop.
Heave ho! Reload persistent data without hacky JVM classloader stuff ;3
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.metadata.MetadataValue;
public class Persistence
{
private static final String METADATA_KEY = "MyPersistentStorage";
// ↓ This is the part that finds the name itself!
private static final String NAME_PATTERN = "main: ([a-z0-9.\\-_]*)";
// And here it ends! (Do not modify beyond this) ↑
private static final Class<? extends JavaPlugin> MAIN_CLASS;
private static volatile Persistence instance;
private final Map<String, Object> data;
private Persistence()
{
// This should be safe enough in our reload scope
List<MetadataValue> data = Bukkit.getWorlds().get(0).getMetadata(METADATA_KEY);
JavaPlugin plugin = JavaPlugin.getPlugin(Persistence.MAIN_CLASS);
for(MetadataValue value : data)
{
if(value.getOwningPlugin().equals(plugin))
{
if(value.value() instanceof Map)
{
// Cast will always be safe - every Map will be assignable to a Map<Object, Object>
// As everything extends Object
Map<Object, Object> map = (Map<Object, Object>)value.value();
// For typesafe keys
Iterator<Map.Entry<?, ?>> entryIterator = map.entrySet().iterator();
while(entryIterator.hasNext())
{
Map.Entry<?, ?> entry = entryIterator.next();
if(!(entry.getKey() instanceof String))
{
entryIterator.remove();
}
}
this.data = Collections.synchronizedMap((Map<String, Object>)map);
return;
}
}
}
Map<String, Object> backend = new HashMap<String, Object>();
Bukkit.getWorlds().get(0).setMetadata(METADATA_KEY, new FixedMetadataValue(plugin, backend));
// If it hasn't been found in the metadata store, create a new one
this.data = Collections.synchronizedMap(backend);
}
private static Persistence getInstance()
{
if(Persistence.instance == null)
{
synchronized (Persistence.class)
{
if (Persistence.instance == null)
{
Persistence.instance = new Persistence();
}
}
}
return Persistence.instance;
}
public static void set(String key, Object data)
{
Persistence persistence = getInstance();
persistence.data.put(key, data);
}
public static boolean has(String key)
{
Persistence persistence = getInstance();
return persistence.data.containsKey(key);
}
public static <T> T get(String key, T def)
{
Persistence persistence = getInstance();
Object obj = persistence.data.get(key);
return obj instanceof T ? obj : def;
}
public static boolean remove(String key)
{
Persistence persistence = getInstance();
return persistence.data.remove(key) != null;
}
static
{
try
{
URL url = getClassLoader().getResource("plugin.yml");
if (url == null)
{
throw IllegalStateException("No plugin.yml in your jar file, every plugin needs one!");
}
URLConnection connection = url.openConnection();
connection.setUseCaches(false);
StringBuilder data = new StringBuilder();
byte[] buf = new byte[64];
InputStream in = connection.getInputStream();
int len;
while ((len = in.read(buf)) > 0)
{
data.append(new String(buf, 0, len));
}
// Pattern may vary, but this should catch most plugin names.
Matcher it = Pattern.compile(NAME_PATTERN, Pattern.CASE_INSENSITIVE).matcher(data);
if (it.matches())
{
MAIN_CLASS = Class.forName(it.group(1));
}
else
{
throw new IllegalStateException("Couldn't find the name of the plugin. Check your plugin.yml and the NAME_PATTERN value!");
}
}
catch (IOException ex)
{
throw new IllegalStateException("Failed to load plugin.yml from the jar file", ex);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment