Flesh out EntityManager to sync entities w/clients
This makes sure that you get new entities as you move to chunks that have them, and that entities are despawned as you move further away from them.
This commit is contained in:
parent
eda5dd2f82
commit
079f8b9188
@ -17,8 +17,10 @@ namespace TrueCraft.API.Networking
|
||||
short SelectedSlot { get; }
|
||||
ItemStack SelectedItem { get; }
|
||||
IMultiplayerServer Server { get; }
|
||||
bool EnableLogging { get; set; }
|
||||
|
||||
void QueuePacket(IPacket packet);
|
||||
void SendMessage(string message);
|
||||
void Log(string message, params object[] parameters);
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ namespace TrueCraft.API.Server
|
||||
IBlockRepository BlockRepository { get; }
|
||||
IItemRepository ItemRepository { get; }
|
||||
bool BlockUpdatesEnabled { get; set; }
|
||||
bool EnableClientLogging { get; set; }
|
||||
|
||||
void Start(IPEndPoint endPoint);
|
||||
void RegisterPacketHandler(byte packetId, PacketHandler handler);
|
||||
|
@ -49,6 +49,33 @@ namespace TrueCraft.Core.Entities
|
||||
public bool IsCrouching { get; set; }
|
||||
public double PositiveDeltaY { get; set; }
|
||||
|
||||
private Vector3 _OldPosition;
|
||||
public Vector3 OldPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return _OldPosition;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_OldPosition = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override Vector3 Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
_OldPosition = _Position;
|
||||
_Position = value;
|
||||
OnPropertyChanged("Position");
|
||||
}
|
||||
}
|
||||
|
||||
protected short _SelectedSlot;
|
||||
public short SelectedSlot
|
||||
{
|
||||
|
@ -54,7 +54,6 @@ namespace TrueCraft.Core.Logic
|
||||
{
|
||||
if (!IsSupported(descriptor, server, world))
|
||||
{
|
||||
server.SendMessage(ChatColor.Red + "Removing block due to insufficient opaque support blocks");
|
||||
GenerateDropEntity(descriptor, world, server);
|
||||
world.SetBlockID(descriptor.Coordinates, 0);
|
||||
}
|
||||
|
@ -86,10 +86,7 @@ namespace TrueCraft.Core.Logic.Blocks
|
||||
public override void BlockUpdate(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world)
|
||||
{
|
||||
if (!ValidBedPosition(descriptor, server.BlockRepository, world))
|
||||
{
|
||||
world.SetBlockID(descriptor.Coordinates, 0);
|
||||
server.SendMessage(ChatColor.Red + "Removing block due to insufficient neighboring bed blocks");
|
||||
}
|
||||
base.BlockUpdate(descriptor, server, world);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace TrueCraft.Commands
|
||||
Commands.Add(new ResendInvCommand());
|
||||
Commands.Add(new PositionCommand());
|
||||
Commands.Add(new TimeCommand());
|
||||
Commands.Add(new LogCommand());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -42,6 +42,39 @@ namespace TrueCraft.Commands
|
||||
}
|
||||
}
|
||||
|
||||
public class LogCommand : Command
|
||||
{
|
||||
public override string Name
|
||||
{
|
||||
get { return "log"; }
|
||||
}
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get { return "Toggles client logging."; }
|
||||
}
|
||||
|
||||
public override string[] Aliases
|
||||
{
|
||||
get { return new string[0]; }
|
||||
}
|
||||
|
||||
public override void Handle(IRemoteClient Client, string Alias, string[] Arguments)
|
||||
{
|
||||
if (Arguments.Length != 0)
|
||||
{
|
||||
Help(Client, Alias, Arguments);
|
||||
return;
|
||||
}
|
||||
Client.EnableLogging = !Client.EnableLogging;
|
||||
}
|
||||
|
||||
public override void Help(IRemoteClient Client, string Alias, string[] Arguments)
|
||||
{
|
||||
Client.SendMessage("/pos: Toggles client logging.");
|
||||
}
|
||||
}
|
||||
|
||||
public class TimeCommand : Command
|
||||
{
|
||||
public override string Name
|
||||
|
@ -28,8 +28,6 @@ namespace TrueCraft
|
||||
private object EntityLock = new object();
|
||||
private ConcurrentBag<IEntity> PendingDespawns { get; set; }
|
||||
|
||||
private static readonly int MaxClientDistance = 4;
|
||||
|
||||
public EntityManager(IMultiplayerServer server, IWorld world)
|
||||
{
|
||||
Server = server;
|
||||
@ -67,12 +65,60 @@ namespace TrueCraft
|
||||
switch (property)
|
||||
{
|
||||
case "Position":
|
||||
// TODO: Only trigger this if the player crosses a chunk boundary
|
||||
Task.Factory.StartNew(client.UpdateChunks);
|
||||
if ((int)(entity.Position.X) >> 4 != (int)(entity.OldPosition.X) >> 4 ||
|
||||
(int)(entity.Position.Z) >> 4 != (int)(entity.OldPosition.Z) >> 4)
|
||||
{
|
||||
client.Log("Passed chunk boundary at {0}, {1}", (int)(entity.Position.X) >> 4, (int)(entity.Position.Z) >> 4);
|
||||
Task.Factory.StartNew(client.UpdateChunks);
|
||||
UpdateClientEntities(client);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateClientEntities(RemoteClient client)
|
||||
{
|
||||
var entity = client.Entity;
|
||||
// Calculate entities you shouldn't know about anymore
|
||||
for (int i = 0; i < client.KnownEntities.Count; i++)
|
||||
{
|
||||
var knownEntity = client.KnownEntities[i];
|
||||
if (knownEntity.Position.DistanceTo(entity.Position) > client.ChunkRadius * Chunk.Depth)
|
||||
{
|
||||
client.QueuePacket(new DestroyEntityPacket(knownEntity.EntityID));
|
||||
client.KnownEntities.Remove(knownEntity);
|
||||
i--;
|
||||
if (knownEntity is PlayerEntity)
|
||||
{
|
||||
var c = (RemoteClient)GetClientForEntity(knownEntity as PlayerEntity);
|
||||
if (c.KnownEntities.Contains(entity))
|
||||
{
|
||||
c.KnownEntities.Remove(entity);
|
||||
c.QueuePacket(new DestroyEntityPacket(entity.EntityID));
|
||||
c.Log("Destroying entity {0} ({1})", knownEntity.EntityID, knownEntity.GetType().Name);
|
||||
}
|
||||
}
|
||||
client.Log("Destroying entity {0} ({1})", knownEntity.EntityID, knownEntity.GetType().Name);
|
||||
}
|
||||
}
|
||||
// Calculate entities you should now know about
|
||||
var toSpawn = GetEntitiesInRange(entity, client.ChunkRadius);
|
||||
foreach (var e in toSpawn)
|
||||
{
|
||||
if (e != entity && !client.KnownEntities.Contains(e))
|
||||
{
|
||||
SendEntityToClient(client, e);
|
||||
// Make sure other players know about you since you've moved
|
||||
if (e is PlayerEntity)
|
||||
{
|
||||
var c = (RemoteClient)GetClientForEntity(e as PlayerEntity);
|
||||
if (!c.KnownEntities.Contains(entity))
|
||||
SendEntityToClient(c, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PropegateEntityPositionUpdates(IEntity entity)
|
||||
{
|
||||
for (int i = 0, ServerClientsCount = Server.Clients.Count; i < ServerClientsCount; i++)
|
||||
@ -107,6 +153,7 @@ namespace TrueCraft
|
||||
|
||||
private void SendEntityToClient(RemoteClient client, IEntity entity)
|
||||
{
|
||||
client.Log("Spawning entity {0} ({1}) at {2}", entity.EntityID, entity.GetType().Name, (Coordinates3D)entity.Position);
|
||||
RemoteClient spawnedClient = null;
|
||||
if (entity is PlayerEntity)
|
||||
spawnedClient = (RemoteClient)GetClientForEntity(entity as PlayerEntity);
|
||||
@ -153,7 +200,7 @@ namespace TrueCraft
|
||||
{
|
||||
Entities.Add(entity);
|
||||
}
|
||||
foreach (var clientEntity in GetEntitiesInRange(entity, MaxClientDistance))
|
||||
foreach (var clientEntity in GetEntitiesInRange(entity, 8)) // Note: 8 is pretty arbitrary here
|
||||
{
|
||||
if (clientEntity != entity && clientEntity is PlayerEntity)
|
||||
{
|
||||
@ -204,6 +251,8 @@ namespace TrueCraft
|
||||
if (client.KnownEntities.Contains(entity))
|
||||
{
|
||||
client.QueuePacket(new DestroyEntityPacket(entity.EntityID));
|
||||
client.KnownEntities.Remove(entity);
|
||||
client.Log("Destroying entity {0} ({1})", entity.EntityID, entity.GetType().Name);
|
||||
}
|
||||
}
|
||||
lock (EntityLock)
|
||||
@ -219,7 +268,7 @@ namespace TrueCraft
|
||||
public void SendEntitiesToClient(IRemoteClient _client)
|
||||
{
|
||||
var client = _client as RemoteClient;
|
||||
foreach (var entity in GetEntitiesInRange(client.Entity, MaxClientDistance))
|
||||
foreach (var entity in GetEntitiesInRange(client.Entity, client.ChunkRadius))
|
||||
{
|
||||
if (entity != client.Entity)
|
||||
SendEntityToClient(client, entity);
|
||||
|
@ -28,6 +28,7 @@ namespace TrueCraft
|
||||
public IEventScheduler Scheduler { get; private set; }
|
||||
public IBlockRepository BlockRepository { get; private set; }
|
||||
public IItemRepository ItemRepository { get; private set; }
|
||||
public bool EnableClientLogging { get; set; }
|
||||
|
||||
private bool _BlockUpdatesEnabled = true;
|
||||
private struct BlockUpdate
|
||||
@ -78,6 +79,7 @@ namespace TrueCraft
|
||||
itemRepository.DiscoverItemProviders();
|
||||
ItemRepository = itemRepository;
|
||||
PendingBlockUpdates = new Queue<BlockUpdate>();
|
||||
EnableClientLogging = false;
|
||||
|
||||
reader.RegisterCorePackets();
|
||||
Handlers.PacketHandlers.RegisterHandlers(this);
|
||||
|
@ -24,6 +24,7 @@ namespace TrueCraft
|
||||
server.AddLogProvider(new ConsoleLogProvider(LogCategory.Notice | LogCategory.Warning | LogCategory.Error | LogCategory.Debug));
|
||||
#if DEBUG
|
||||
server.AddLogProvider(new FileLogProvider(new StreamWriter("packets.log", false), LogCategory.Packets));
|
||||
server.EnableClientLogging = true;
|
||||
#endif
|
||||
CommandManager = new CommandManager();
|
||||
server.ChatMessageReceived += HandleChatMessageReceived;
|
||||
|
@ -36,6 +36,7 @@ namespace TrueCraft
|
||||
ItemStaging = ItemStack.EmptyStack;
|
||||
KnownEntities = new List<IEntity>();
|
||||
Disconnected = false;
|
||||
EnableLogging = server.EnableClientLogging;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -55,6 +56,7 @@ namespace TrueCraft
|
||||
public short SelectedSlot { get; internal set; }
|
||||
public ItemStack ItemStaging { get; set; }
|
||||
public IWindow CurrentWindow { get; set; }
|
||||
public bool EnableLogging { get; set; }
|
||||
|
||||
private IEntity _Entity;
|
||||
public IEntity Entity
|
||||
@ -112,6 +114,12 @@ namespace TrueCraft
|
||||
}
|
||||
}
|
||||
|
||||
public void Log(string message, params object[] parameters)
|
||||
{
|
||||
if (EnableLogging)
|
||||
SendMessage(ChatColor.Gray + string.Format("[" + DateTime.Now.ToShortTimeString() + "] " + message, parameters));
|
||||
}
|
||||
|
||||
public void QueuePacket(IPacket packet)
|
||||
{
|
||||
PacketQueue.Enqueue(packet);
|
||||
@ -166,6 +174,7 @@ namespace TrueCraft
|
||||
LoadChunk(chunk);
|
||||
}
|
||||
}
|
||||
((EntityManager)Server.GetEntityManagerForWorld(World)).UpdateClientEntities(this);
|
||||
}
|
||||
|
||||
internal void UnloadAllChunks()
|
||||
|
Reference in New Issue
Block a user