Implement player persistence

This saves your health, inventory, position, and look values.
This commit is contained in:
Drew DeVault 2015-04-18 17:11:09 -06:00
parent f84538b9c6
commit 74849b0b56
7 changed files with 64 additions and 38 deletions

View File

@ -19,6 +19,8 @@ namespace TrueCraft.API.Networking
IMultiplayerServer Server { get; }
bool EnableLogging { get; set; }
bool Load();
void Save();
void QueuePacket(IPacket packet);
void SendMessage(string message);
void Log(string message, params object[] parameters);

View File

@ -22,6 +22,7 @@ namespace TrueCraft.API.Windows
/// Gets an array of all slots in this window. Suitable for sending to clients over the network.
/// </summary>
ItemStack[] GetSlots();
void SetSlots(ItemStack[] slots);
/// <summary>
/// Adds the specified item stack to this window, merging with established slots as neccessary.
/// </summary>

View File

@ -14,7 +14,6 @@ namespace TrueCraft.Core.Entities
public PlayerEntity(string username) : base()
{
Username = username;
Food = 20;
}
public const double Width = 0.6;
@ -100,39 +99,6 @@ namespace TrueCraft.Core.Entities
}
}
protected short _Food;
public short Food
{
get { return _Food; }
set
{
_Food = value;
OnPropertyChanged("Food");
}
}
protected float _FoodSaturation;
public float FoodSaturation
{
get { return _FoodSaturation; }
set
{
_FoodSaturation = value;
OnPropertyChanged("FoodSaturation");
}
}
protected float _FoodExhaustion;
public float FoodExhaustion
{
get { return _FoodExhaustion; }
set
{
_FoodExhaustion = value;
OnPropertyChanged("FoodExhaustion");
}
}
public event EventHandler<EntityEventArgs> PickUpItem;
public void OnPickUpItem(ItemEntity item)
{

View File

@ -95,6 +95,12 @@ namespace TrueCraft.Core.Windows
return slots;
}
public virtual void SetSlots(ItemStack[] slots)
{
foreach (var windowArea in WindowAreas)
Array.Copy(slots, windowArea.StartIndex, windowArea.Items, 0, windowArea.Length);
}
public virtual ItemStack this[int index]
{
get

View File

@ -35,15 +35,19 @@ namespace TrueCraft.Handlers
client.World = server.Worlds[0];
client.ChunkRadius = 2;
if (!client.Load())
client.Entity.Position = client.World.SpawnPoint;
// Send setup packets
client.QueuePacket(new LoginResponsePacket(0, 0, Dimension.Overworld));
client.UpdateChunks();
client.QueuePacket(new WindowItemsPacket(0, client.Inventory.GetSlots()));
client.Entity.Position = client.World.SpawnPoint;
client.QueuePacket(new SpawnPositionPacket((int)client.Entity.Position.X,
(int)client.Entity.Position.Y, (int)client.Entity.Position.Z));
client.QueuePacket(new SetPlayerPositionPacket(client.Entity.Position.X, client.Entity.Position.Y,
client.Entity.Position.Y + client.Entity.Size.Height, client.Entity.Position.Z, 0, 0, true));
client.QueuePacket(new SetPlayerPositionPacket(client.Entity.Position.X,
client.Entity.Position.Y + 1,
client.Entity.Position.Y + client.Entity.Size.Height + 1,
client.Entity.Position.Z, client.Entity.Yaw, client.Entity.Pitch, true));
client.QueuePacket(new TimeUpdatePacket(client.World.Time));
// Start housekeeping for this client

View File

@ -216,6 +216,7 @@ namespace TrueCraft
GetEntityManagerForWorld(client.World).DespawnEntity(client.Entity);
GetEntityManagerForWorld(client.World).FlushDespawns();
}
client.Save();
client.Disconnected = true;
}

View File

@ -17,6 +17,8 @@ using TrueCraft.Core.Windows;
using System.Threading.Tasks;
using System.Threading;
using TrueCraft.Core.Entities;
using System.IO;
using fNbt;
namespace TrueCraft
{
@ -25,7 +27,7 @@ namespace TrueCraft
public RemoteClient(IMultiplayerServer server, NetworkStream stream)
{
NetworkStream = stream;
MinecraftStream = new MinecraftStream(new BufferedStream(NetworkStream));
MinecraftStream = new MinecraftStream(new TrueCraft.Core.Networking.BufferedStream(NetworkStream));
PacketQueue = new ConcurrentQueue<IPacket>();
LoadedChunks = new List<Coordinates2D>();
Server = server;
@ -117,6 +119,50 @@ namespace TrueCraft
}
}
public bool Load()
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "players", Username + ".nbt");
if (!File.Exists(path))
return false;
try
{
var nbt = new NbtFile(path);
Entity.Position = new Vector3(
nbt.RootTag["position"][0].DoubleValue,
nbt.RootTag["position"][1].DoubleValue,
nbt.RootTag["position"][2].DoubleValue);
Inventory.SetSlots(((NbtList)nbt.RootTag["inventory"]).Select(t => ItemStack.FromNbt(t as NbtCompound)).ToArray());
(Entity as PlayerEntity).Health = nbt.RootTag["health"].ShortValue;
Entity.Yaw = nbt.RootTag["yaw"].FloatValue;
Entity.Pitch = nbt.RootTag["pitch"].FloatValue;
}
catch { /* Who cares */ }
return true;
}
public void Save()
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "players", Username + ".nbt");
if (!Directory.Exists(Path.GetDirectoryName(path)))
Directory.CreateDirectory(Path.GetDirectoryName(path));
var nbt = new NbtFile(new NbtCompound("player", new NbtTag[]
{
new NbtString("username", Username),
new NbtList("position", new[]
{
new NbtDouble(Entity.Position.X),
new NbtDouble(Entity.Position.Y),
new NbtDouble(Entity.Position.Z)
}),
new NbtList("inventory", Inventory.GetSlots().Select(s => s.ToNbt())),
new NbtShort("health", (Entity as PlayerEntity).Health),
new NbtFloat("yaw", Entity.Yaw),
new NbtFloat("pitch", Entity.Pitch),
}
));
nbt.SaveToFile(path, NbtCompression.ZLib);
}
public void OpenWindow(IWindow window)
{
CurrentWindow = window;