2011-04-07 07:03:54 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.IO;
|
2011-06-29 02:58:34 +00:00
|
|
|
|
using Substrate.Core;
|
2011-06-30 04:41:29 +00:00
|
|
|
|
using Substrate.Nbt;
|
2011-08-14 16:27:52 +00:00
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using System.Collections;
|
2011-04-07 07:03:54 +00:00
|
|
|
|
|
|
|
|
|
namespace Substrate
|
|
|
|
|
{
|
2011-07-02 03:51:48 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Functions to manage multiple <see cref="Player"/> entities and files in multiplayer settings.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>This manager is intended for player files stored in standard compressed NBT format.</remarks>
|
2011-08-14 16:27:52 +00:00
|
|
|
|
public class PlayerManager : IPlayerManager, IEnumerable<Player>
|
2011-04-07 07:03:54 +00:00
|
|
|
|
{
|
2011-07-02 03:51:48 +00:00
|
|
|
|
private string _playerPath;
|
2011-04-07 07:03:54 +00:00
|
|
|
|
|
2011-07-02 03:51:48 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create a new <see cref="PlayerManager"/> for a given file path.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="playerDir">Path to a directory containing player data files.</param>
|
2011-04-07 07:03:54 +00:00
|
|
|
|
public PlayerManager (string playerDir)
|
|
|
|
|
{
|
|
|
|
|
_playerPath = playerDir;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-02 03:51:48 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets a <see cref="PlayerFile"/> representing the backing NBT data stream.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name">The name of the player to fetch.</param>
|
|
|
|
|
/// <returns>A <see cref="PlayerFile"/> for the given player.</returns>
|
2011-04-07 07:03:54 +00:00
|
|
|
|
protected PlayerFile GetPlayerFile (string name)
|
|
|
|
|
{
|
|
|
|
|
return new PlayerFile(_playerPath, name);
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-02 03:51:48 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets a raw <see cref="NbtTree"/> of data for the given player.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name">The name of the player to fetch.</param>
|
|
|
|
|
/// <returns>An <see cref="NbtTree"/> containing the given player's raw data.</returns>
|
|
|
|
|
/// <exception cref="NbtIOException">Thrown when the manager cannot read in an NBT data stream.</exception>
|
|
|
|
|
public NbtTree GetPlayerTree (string name)
|
2011-04-07 07:03:54 +00:00
|
|
|
|
{
|
|
|
|
|
PlayerFile pf = GetPlayerFile(name);
|
2011-04-07 08:04:53 +00:00
|
|
|
|
Stream nbtstr = pf.GetDataInputStream();
|
2011-04-07 07:03:54 +00:00
|
|
|
|
if (nbtstr == null) {
|
2011-07-02 03:51:48 +00:00
|
|
|
|
throw new NbtIOException("Failed to initialize NBT data stream for input.");
|
2011-04-07 07:03:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-06-30 04:41:29 +00:00
|
|
|
|
return new NbtTree(nbtstr);
|
2011-04-07 07:03:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-07-02 03:51:48 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Saves a raw <see cref="NbtTree"/> representing a player to the given player's file.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name">The name of the player to write data to.</param>
|
|
|
|
|
/// <param name="tree">The player's data as an <see cref="NbtTree"/>.</param>
|
|
|
|
|
/// <exception cref="NbtIOException">Thrown when the manager cannot initialize an NBT data stream for output.</exception>
|
|
|
|
|
public void SetPlayerTree (string name, NbtTree tree)
|
2011-04-07 07:03:54 +00:00
|
|
|
|
{
|
|
|
|
|
PlayerFile pf = GetPlayerFile(name);
|
2011-04-07 08:04:53 +00:00
|
|
|
|
Stream zipstr = pf.GetDataOutputStream();
|
2011-04-07 07:03:54 +00:00
|
|
|
|
if (zipstr == null) {
|
2011-07-02 03:51:48 +00:00
|
|
|
|
throw new NbtIOException("Failed to initialize NBT data stream for output.");
|
2011-04-07 07:03:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tree.WriteTo(zipstr);
|
|
|
|
|
zipstr.Close();
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-02 03:51:48 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets a <see cref="Player"/> object for the given player.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name">The name of the player to fetch.</param>
|
|
|
|
|
/// <returns>A <see cref="Player"/> object for the given player, or null if the player could not be found.</returns>
|
|
|
|
|
/// <exception cref="PlayerIOException">Thrown when the manager cannot read in a player that should exist.</exception>
|
2011-04-07 07:03:54 +00:00
|
|
|
|
public Player GetPlayer (string name)
|
|
|
|
|
{
|
|
|
|
|
if (!PlayerExists(name)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-02 03:51:48 +00:00
|
|
|
|
try {
|
2011-08-14 16:27:52 +00:00
|
|
|
|
Player p = new Player().LoadTreeSafe(GetPlayerTree(name).Root);
|
|
|
|
|
p.Name = name;
|
|
|
|
|
return p;
|
2011-07-02 03:51:48 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex) {
|
|
|
|
|
PlayerIOException pex = new PlayerIOException("Could not load player", ex);
|
|
|
|
|
pex.Data["PlayerName"] = name;
|
|
|
|
|
throw pex;
|
|
|
|
|
}
|
2011-04-07 07:03:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-07-02 03:51:48 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Saves a <see cref="Player"/> object's data back to the given player's file.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name">The name of the player to write back to.</param>
|
|
|
|
|
/// <param name="player">The <see cref="Player"/> object containing data to write back.</param>
|
|
|
|
|
/// <exception cref="PlayerIOException">Thrown when the manager cannot write out the player.</exception>
|
|
|
|
|
public void SetPlayer (string name, Player player)
|
2011-04-07 07:03:54 +00:00
|
|
|
|
{
|
2011-07-02 03:51:48 +00:00
|
|
|
|
try {
|
|
|
|
|
SetPlayerTree(name, new NbtTree(player.BuildTree() as TagNodeCompound));
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex) {
|
|
|
|
|
PlayerIOException pex = new PlayerIOException("Could not save player", ex);
|
|
|
|
|
pex.Data["PlayerName"] = name;
|
|
|
|
|
throw pex;
|
|
|
|
|
}
|
2011-04-07 07:03:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-08-14 16:27:52 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Saves a <see cref="Player"/> object's data back to file given the name set in the <see cref="Player"/> object.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="player">The <see cref="Player"/> object containing the data to write back.</param>
|
|
|
|
|
/// <exception cref="PlayerIOException">Thrown when the manager cannot write out the player.</exception>
|
|
|
|
|
public void SetPlayer (Player player)
|
|
|
|
|
{
|
|
|
|
|
SetPlayer(player.Name, player);
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-02 03:51:48 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks if data for a player with the given name exists.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name">The name of the player to look up.</param>
|
|
|
|
|
/// <returns>True if player data was found; false otherwise.</returns>
|
2011-04-07 07:03:54 +00:00
|
|
|
|
public bool PlayerExists (string name)
|
|
|
|
|
{
|
|
|
|
|
return new PlayerFile(_playerPath, name).Exists();
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-02 03:51:48 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Deletes a player with the given name from the underlying data store.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name">The name of the player to delete.</param>
|
|
|
|
|
/// <exception cref="PlayerIOException">Thrown when the manager cannot delete the player.</exception>
|
|
|
|
|
public void DeletePlayer (string name)
|
2011-04-07 07:03:54 +00:00
|
|
|
|
{
|
2011-07-02 03:51:48 +00:00
|
|
|
|
try {
|
|
|
|
|
new PlayerFile(_playerPath, name).Delete();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex) {
|
2011-11-10 02:46:19 +00:00
|
|
|
|
PlayerIOException pex = new PlayerIOException("Could not remove player", ex);
|
2011-07-02 03:51:48 +00:00
|
|
|
|
pex.Data["PlayerName"] = name;
|
|
|
|
|
throw pex;
|
|
|
|
|
}
|
2011-04-07 07:03:54 +00:00
|
|
|
|
}
|
2011-08-14 16:27:52 +00:00
|
|
|
|
|
|
|
|
|
#region IEnumerable<Player> Members
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2011-11-10 02:46:19 +00:00
|
|
|
|
/// Gets an enumerator that iterates through all the players in the world.
|
2011-08-14 16:27:52 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>An enumerator for this manager.</returns>
|
|
|
|
|
public IEnumerator<Player> GetEnumerator ()
|
|
|
|
|
{
|
|
|
|
|
return new Enumerator(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region IEnumerable Members
|
|
|
|
|
|
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
|
|
|
|
|
{
|
|
|
|
|
return new Enumerator(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
private class Enumerator : IEnumerator<Player>
|
|
|
|
|
{
|
|
|
|
|
protected PlayerManager _pm;
|
|
|
|
|
protected Queue<string> _names;
|
|
|
|
|
|
|
|
|
|
protected Player _curPlayer;
|
|
|
|
|
|
|
|
|
|
public Enumerator (PlayerManager cfm)
|
|
|
|
|
{
|
|
|
|
|
_pm = cfm;
|
|
|
|
|
_names = new Queue<string>();
|
|
|
|
|
|
|
|
|
|
if (!Directory.Exists(_pm._playerPath)) {
|
|
|
|
|
throw new DirectoryNotFoundException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool MoveNext ()
|
|
|
|
|
{
|
|
|
|
|
if (_names.Count == 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string name = _names.Dequeue();
|
|
|
|
|
_curPlayer = _pm.GetPlayer(name);
|
|
|
|
|
_curPlayer.Name = name;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Reset ()
|
|
|
|
|
{
|
|
|
|
|
_names.Clear();
|
|
|
|
|
_curPlayer = null;
|
|
|
|
|
|
|
|
|
|
string[] files = Directory.GetFiles(_pm._playerPath);
|
|
|
|
|
foreach (string file in files) {
|
|
|
|
|
string basename = Path.GetFileName(file);
|
|
|
|
|
|
|
|
|
|
if (!ParseFileName(basename)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_names.Enqueue(PlayerFile.NameFromFilename(basename));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IDisposable.Dispose () { }
|
|
|
|
|
|
|
|
|
|
object IEnumerator.Current
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return Current;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Player IEnumerator<Player>.Current
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return Current;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Player Current
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (_curPlayer == null) {
|
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
|
}
|
|
|
|
|
return _curPlayer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool ParseFileName (string filename)
|
|
|
|
|
{
|
|
|
|
|
Match match = _namePattern.Match(filename);
|
|
|
|
|
if (!match.Success) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected static Regex _namePattern = new Regex(".+\\.dat$");
|
|
|
|
|
}
|
2011-04-07 07:03:54 +00:00
|
|
|
|
}
|
|
|
|
|
}
|