mirror of
https://github.com/EssentialsX/Essentials.git
synced 2025-01-09 01:48:15 +01:00
More work done on config code
This commit is contained in:
parent
6fe8e603af
commit
f3b278eac2
@ -85,8 +85,7 @@ public class UserMap extends CacheLoader<String, User> implements IConf
|
||||
return new User(player, ess);
|
||||
}
|
||||
}
|
||||
final File userFolder = new File(ess.getDataFolder(), "userdata");
|
||||
final File userFile = new File(userFolder, Util.sanitizeFileName(name) + ".yml");
|
||||
final File userFile = getUserFile(name);
|
||||
if (userFile.exists())
|
||||
{
|
||||
keys.add(name.toLowerCase(Locale.ENGLISH));
|
||||
@ -116,4 +115,10 @@ public class UserMap extends CacheLoader<String, User> implements IConf
|
||||
{
|
||||
return keys.size();
|
||||
}
|
||||
|
||||
public File getUserFile(final String name)
|
||||
{
|
||||
final File userFolder = new File(ess.getDataFolder(), "userdata");
|
||||
return new File(userFolder, Util.sanitizeFileName(name) + ".yml");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
package com.earth2me.essentials.storage;
|
||||
|
||||
import com.earth2me.essentials.IEssentials;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
|
||||
public abstract class AbstractDelayedYamlFileWriter implements Runnable
|
||||
{
|
||||
private final transient File file;
|
||||
|
||||
public AbstractDelayedYamlFileWriter(IEssentials ess, File file)
|
||||
{
|
||||
this.file = file;
|
||||
ess.scheduleAsyncDelayedTask(this);
|
||||
}
|
||||
|
||||
public abstract StorageObject getObject();
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
PrintWriter pw = null;
|
||||
try
|
||||
{
|
||||
final StorageObject object = getObject();
|
||||
final File folder = file.getParentFile();
|
||||
if (!folder.exists())
|
||||
{
|
||||
folder.mkdirs();
|
||||
}
|
||||
pw = new PrintWriter(file);
|
||||
new YamlStorageWriter(pw).save(object);
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
Bukkit.getLogger().log(Level.SEVERE, file.toString(), ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
onFinish();
|
||||
if (pw != null)
|
||||
{
|
||||
pw.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract void onFinish();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.earth2me.essentials.userdata;
|
||||
package com.earth2me.essentials.user;
|
||||
|
||||
import com.earth2me.essentials.storage.StorageObject;
|
||||
import lombok.Data;
|
@ -0,0 +1,15 @@
|
||||
package com.earth2me.essentials.user;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
|
||||
public interface IOfflinePlayer
|
||||
{
|
||||
String getName();
|
||||
|
||||
String getDisplayName();
|
||||
|
||||
Location getBedSpawnLocation();
|
||||
|
||||
void setBanned(boolean bln);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.earth2me.essentials.user;
|
||||
|
||||
|
||||
public interface IOfflineUser extends IUserData, IOfflinePlayer
|
||||
{
|
||||
|
||||
}
|
13
Essentials/src/com/earth2me/essentials/user/IUserData.java
Normal file
13
Essentials/src/com/earth2me/essentials/user/IUserData.java
Normal file
@ -0,0 +1,13 @@
|
||||
package com.earth2me.essentials.user;
|
||||
|
||||
|
||||
public interface IUserData
|
||||
{
|
||||
UserData getData();
|
||||
|
||||
void aquireReadLock();
|
||||
|
||||
void aquireWriteLock();
|
||||
|
||||
void close();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.earth2me.essentials.userdata;
|
||||
package com.earth2me.essentials.user;
|
||||
|
||||
import com.earth2me.essentials.storage.MapKeyType;
|
||||
import com.earth2me.essentials.storage.MapValueType;
|
111
Essentials/src/com/earth2me/essentials/user/User.java
Normal file
111
Essentials/src/com/earth2me/essentials/user/User.java
Normal file
@ -0,0 +1,111 @@
|
||||
package com.earth2me.essentials.user;
|
||||
|
||||
import com.earth2me.essentials.IEssentials;
|
||||
import com.earth2me.essentials.storage.AbstractDelayedYamlFileWriter;
|
||||
import com.earth2me.essentials.storage.StorageObject;
|
||||
import com.earth2me.essentials.storage.YamlStorageReader;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import lombok.Cleanup;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
// this is a prototype for locking userdata
|
||||
public class User extends UserBase implements IOfflineUser
|
||||
{
|
||||
private transient UserData data = new UserData();
|
||||
private final transient ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||
|
||||
public User(final Player base, final IEssentials ess)
|
||||
{
|
||||
super(base, ess);
|
||||
}
|
||||
|
||||
public User(final OfflinePlayer offlinePlayer, final IEssentials ess)
|
||||
{
|
||||
super(offlinePlayer, ess);
|
||||
}
|
||||
|
||||
public void loadUserData()
|
||||
{
|
||||
data = new YamlStorageReader(null).load(UserData.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserData getData()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void aquireReadLock()
|
||||
{
|
||||
rwl.readLock().lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void aquireWriteLock()
|
||||
{
|
||||
while (rwl.getReadHoldCount() > 0)
|
||||
{
|
||||
rwl.readLock().unlock();
|
||||
}
|
||||
rwl.writeLock().lock();
|
||||
rwl.readLock().lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
if (rwl.isWriteLockedByCurrentThread())
|
||||
{
|
||||
rwl.writeLock().unlock();
|
||||
scheduleSaving();
|
||||
}
|
||||
while (rwl.getReadHoldCount() > 0)
|
||||
{
|
||||
rwl.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void example()
|
||||
{
|
||||
// Cleanup will call close at the end of the function
|
||||
@Cleanup
|
||||
final User user = this;
|
||||
|
||||
// read lock allows to read data from the user
|
||||
user.aquireReadLock();
|
||||
final double money = user.getData().getMoney();
|
||||
|
||||
// write lock allows only one thread to modify the data
|
||||
user.aquireWriteLock();
|
||||
user.getData().setMoney(10 + money);
|
||||
}
|
||||
|
||||
private void scheduleSaving()
|
||||
{
|
||||
new UserDataWriter();
|
||||
}
|
||||
|
||||
|
||||
private class UserDataWriter extends AbstractDelayedYamlFileWriter
|
||||
{
|
||||
public UserDataWriter()
|
||||
{
|
||||
super(ess, ess.getUserMap().getUserFile(User.this.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageObject getObject()
|
||||
{
|
||||
aquireReadLock();
|
||||
return getData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish()
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
115
Essentials/src/com/earth2me/essentials/user/UserBase.java
Normal file
115
Essentials/src/com/earth2me/essentials/user/UserBase.java
Normal file
@ -0,0 +1,115 @@
|
||||
package com.earth2me.essentials.user;
|
||||
|
||||
import com.earth2me.essentials.IEssentials;
|
||||
import com.earth2me.essentials.craftbukkit.OfflineBedLocation;
|
||||
import lombok.Delegate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.ServerOperator;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
|
||||
|
||||
public class UserBase implements Player, IOfflinePlayer
|
||||
{
|
||||
|
||||
@Delegate(types =
|
||||
{
|
||||
Player.class, Entity.class, CommandSender.class, ServerOperator.class,
|
||||
HumanEntity.class, ConfigurationSerializable.class, LivingEntity.class,
|
||||
Permissible.class
|
||||
},excludes=IOfflinePlayer.class)
|
||||
protected Player base;
|
||||
protected transient OfflinePlayer offlinePlayer;
|
||||
protected final transient IEssentials ess;
|
||||
|
||||
public UserBase(final Player base, final IEssentials ess)
|
||||
{
|
||||
this.base = base;
|
||||
this.ess = ess;
|
||||
}
|
||||
|
||||
public UserBase(final OfflinePlayer offlinePlayer, final IEssentials ess)
|
||||
{
|
||||
this.offlinePlayer = offlinePlayer;
|
||||
this.ess = ess;
|
||||
}
|
||||
|
||||
public final Player getBase()
|
||||
{
|
||||
return base;
|
||||
}
|
||||
|
||||
public final Player setBase(final Player base)
|
||||
{
|
||||
return this.base = base;
|
||||
}
|
||||
|
||||
public void update(final Player base)
|
||||
{
|
||||
setBase(base);
|
||||
}
|
||||
|
||||
public void update(final OfflinePlayer offlinePlayer)
|
||||
{
|
||||
this.offlinePlayer = offlinePlayer;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
this.offlinePlayer = Bukkit.getOfflinePlayer(base.getName());
|
||||
this.base = null;
|
||||
}
|
||||
|
||||
public boolean isOnlineUser() {
|
||||
return base != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
if (isOnlineUser()) {
|
||||
return base.getName();
|
||||
} else {
|
||||
return offlinePlayer.getName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName()
|
||||
{
|
||||
if (isOnlineUser()) {
|
||||
return base.getDisplayName();
|
||||
} else {
|
||||
return offlinePlayer.getName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getBedSpawnLocation()
|
||||
{
|
||||
if (isOnlineUser()) {
|
||||
return base.getBedSpawnLocation();
|
||||
} else {
|
||||
return OfflineBedLocation.getBedLocation(base.getName(), ess);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBanned(boolean bln)
|
||||
{
|
||||
if (isOnlineUser()) {
|
||||
base.setBanned(bln);
|
||||
} else {
|
||||
offlinePlayer.setBanned(bln);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.earth2me.essentials.userdata;
|
||||
package com.earth2me.essentials.user;
|
||||
|
||||
import com.earth2me.essentials.storage.ListType;
|
||||
import com.earth2me.essentials.storage.MapKeyType;
|
128
Essentials/src/com/earth2me/essentials/user/UserMap.java
Normal file
128
Essentials/src/com/earth2me/essentials/user/UserMap.java
Normal file
@ -0,0 +1,128 @@
|
||||
package com.earth2me.essentials.user;
|
||||
|
||||
import com.earth2me.essentials.IConf;
|
||||
import com.earth2me.essentials.IEssentials;
|
||||
import com.earth2me.essentials.Util;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
|
||||
public class UserMap extends CacheLoader<String, User> implements IConf
|
||||
{
|
||||
private final transient IEssentials ess;
|
||||
private final transient Cache<String, User> users = CacheBuilder.newBuilder().softValues().build(this);
|
||||
private final transient ConcurrentSkipListSet<String> keys = new ConcurrentSkipListSet<String>();
|
||||
|
||||
public UserMap(final IEssentials ess)
|
||||
{
|
||||
super();
|
||||
this.ess = ess;
|
||||
loadAllUsersAsync(ess);
|
||||
}
|
||||
|
||||
private void loadAllUsersAsync(final IEssentials ess)
|
||||
{
|
||||
ess.scheduleAsyncDelayedTask(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
final File userdir = new File(ess.getDataFolder(), "userdata");
|
||||
if (!userdir.exists())
|
||||
{
|
||||
return;
|
||||
}
|
||||
keys.clear();
|
||||
users.invalidateAll();
|
||||
for (String string : userdir.list())
|
||||
{
|
||||
if (!string.endsWith(".yml"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
final String name = string.substring(0, string.length() - 4);
|
||||
keys.add(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean userExists(final String name)
|
||||
{
|
||||
return keys.contains(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
public User getUser(final String name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return users.get(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
catch (ExecutionException ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch (UncheckedExecutionException ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public User load(final String name) throws Exception
|
||||
{
|
||||
for (Player player : ess.getServer().getOnlinePlayers())
|
||||
{
|
||||
if (player.getName().equalsIgnoreCase(name))
|
||||
{
|
||||
keys.add(name.toLowerCase(Locale.ENGLISH));
|
||||
return new User(player, ess);
|
||||
}
|
||||
}
|
||||
final File userFile = getUserFile(name);
|
||||
if (userFile.exists())
|
||||
{
|
||||
keys.add(name.toLowerCase(Locale.ENGLISH));
|
||||
return new User(Bukkit.getOfflinePlayer(name), ess);
|
||||
}
|
||||
throw new Exception("User not found!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig()
|
||||
{
|
||||
loadAllUsersAsync(ess);
|
||||
}
|
||||
|
||||
public void removeUser(final String name)
|
||||
{
|
||||
keys.remove(name.toLowerCase(Locale.ENGLISH));
|
||||
users.invalidate(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
public Set<String> getAllUniqueUsers()
|
||||
{
|
||||
return Collections.unmodifiableSet(keys);
|
||||
}
|
||||
|
||||
public int getUniqueUsers()
|
||||
{
|
||||
return keys.size();
|
||||
}
|
||||
|
||||
public File getUserFile(final String name)
|
||||
{
|
||||
final File userFolder = new File(ess.getDataFolder(), "userdata");
|
||||
return new File(userFolder, Util.sanitizeFileName(name) + ".yml");
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
package com.earth2me.essentials.userdata;
|
||||
|
||||
import com.earth2me.essentials.storage.YamlStorageReader;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import lombok.Cleanup;
|
||||
|
||||
// this is a prototype for locking userdata
|
||||
public class User
|
||||
{
|
||||
UserData data = new UserData();
|
||||
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||
|
||||
public void loadUserData()
|
||||
{
|
||||
data = new YamlStorageReader(null).load(UserData.class);
|
||||
}
|
||||
|
||||
public void aquireReadLock()
|
||||
{
|
||||
rwl.readLock().lock();
|
||||
}
|
||||
|
||||
public void aquireWriteLock()
|
||||
{
|
||||
while (rwl.getReadHoldCount() > 0)
|
||||
{
|
||||
rwl.readLock().unlock();
|
||||
}
|
||||
rwl.writeLock().lock();
|
||||
rwl.readLock().lock();
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
if (rwl.isWriteLockedByCurrentThread())
|
||||
{
|
||||
scheduleSaving();
|
||||
rwl.writeLock().unlock();
|
||||
}
|
||||
while (rwl.getReadHoldCount() > 0)
|
||||
{
|
||||
rwl.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void example()
|
||||
{
|
||||
// Cleanup will call close at the end of the function
|
||||
@Cleanup
|
||||
final User user = this;
|
||||
|
||||
// read lock allows to read data from the user
|
||||
user.aquireReadLock();
|
||||
double i = user.data.getMoney();
|
||||
|
||||
// write lock allows only one thread to modify the data
|
||||
user.aquireWriteLock();
|
||||
user.data.setMoney(10 + user.data.getMoney());
|
||||
}
|
||||
|
||||
private void scheduleSaving()
|
||||
{
|
||||
System.out.println("Schedule saving...");
|
||||
}
|
||||
}
|
@ -80,11 +80,11 @@ public class StorageTest extends TestCase
|
||||
ext.start();
|
||||
final ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]);
|
||||
final Reader reader = new InputStreamReader(bais);
|
||||
final com.earth2me.essentials.userdata.UserData userdata = new YamlStorageReader(reader).load(com.earth2me.essentials.userdata.UserData.class);
|
||||
final com.earth2me.essentials.user.UserData userdata = new YamlStorageReader(reader).load(com.earth2me.essentials.user.UserData.class);
|
||||
ext.mark("load empty user");
|
||||
final ByteArrayInputStream bais3 = new ByteArrayInputStream(new byte[0]);
|
||||
final Reader reader3 = new InputStreamReader(bais3);
|
||||
final com.earth2me.essentials.userdata.UserData userdata3 = new YamlStorageReader(reader3).load(com.earth2me.essentials.userdata.UserData.class);
|
||||
final com.earth2me.essentials.user.UserData userdata3 = new YamlStorageReader(reader3).load(com.earth2me.essentials.user.UserData.class);
|
||||
ext.mark("load empty user (class cached)");
|
||||
|
||||
for (int j = 0; j < 10000; j++)
|
||||
@ -107,16 +107,16 @@ public class StorageTest extends TestCase
|
||||
ext.mark("debug output");
|
||||
final ByteArrayInputStream bais2 = new ByteArrayInputStream(written);
|
||||
final Reader reader2 = new InputStreamReader(bais2);
|
||||
final com.earth2me.essentials.userdata.UserData userdata2 = new YamlStorageReader(reader2).load(com.earth2me.essentials.userdata.UserData.class);
|
||||
final com.earth2me.essentials.user.UserData userdata2 = new YamlStorageReader(reader2).load(com.earth2me.essentials.user.UserData.class);
|
||||
ext.mark("reload file");
|
||||
final ByteArrayInputStream bais4 = new ByteArrayInputStream(written);
|
||||
final Reader reader4 = new InputStreamReader(bais4);
|
||||
final com.earth2me.essentials.userdata.UserData userdata4 = new YamlStorageReader(reader4).load(com.earth2me.essentials.userdata.UserData.class);
|
||||
final com.earth2me.essentials.user.UserData userdata4 = new YamlStorageReader(reader4).load(com.earth2me.essentials.user.UserData.class);
|
||||
ext.mark("reload file (cached)");
|
||||
System.out.println(userdata.toString());
|
||||
System.out.println(userdata2.toString());
|
||||
System.out.println(ext.end());
|
||||
com.earth2me.essentials.userdata.User test = new com.earth2me.essentials.userdata.User();
|
||||
com.earth2me.essentials.user.User test = new com.earth2me.essentials.user.User(null, ess);
|
||||
test.example();
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user