@@ -1,22 +1,22 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>10</LangVersion>
|
<LangVersion>10</LangVersion>
|
||||||
<RootNamespace>Ragon.Client.Simulation</RootNamespace>
|
<RootNamespace>Ragon.Client.Simulation</RootNamespace>
|
||||||
<Authors>Eduard Kargin (Edmand46)</Authors>
|
<Authors>Eduard Kargin (Edmand46)</Authors>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<DebugType>none</DebugType>
|
<DebugType>none</DebugType>
|
||||||
<OutputPath>/Users/edmand46/RagonProjects/ragon-oss-sdk/Assets/Ragon/Plugins/</OutputPath>
|
<OutputPath>/Users/edmand46/RagonProjects/ragon-oss-examples/Assets/Ragon/Plugins/</OutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<OutputPath>/Users/edmand46/RagonProjects/ragon-unity-sdk/Assets/Ragon/Runtime/Plugins</OutputPath>
|
<OutputPath>/Users/edmand46/RagonProjects/ragon-oss-examples/Assets/Ragon/Plugins/</OutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -57,10 +57,12 @@ namespace Ragon.Client
|
|||||||
State = new RagonEntityState(this);
|
State = new RagonEntityState(this);
|
||||||
Type = type;
|
Type = type;
|
||||||
|
|
||||||
|
_spawnPayload = new RagonPayload(0);
|
||||||
|
_destroyPayload = new RagonPayload(0);
|
||||||
_sceneId = sceneId;
|
_sceneId = sceneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Attach(RagonClient client, ushort entityId, ushort entityType, bool hasAuthority, RagonPlayer owner, RagonPayload payload)
|
internal void Attach(RagonClient client, ushort entityId, ushort entityType, bool hasAuthority, RagonPlayer owner)
|
||||||
{
|
{
|
||||||
Type = entityType;
|
Type = entityType;
|
||||||
Id = entityId;
|
Id = entityId;
|
||||||
@@ -70,7 +72,6 @@ namespace Ragon.Client
|
|||||||
HasAuthority = hasAuthority;
|
HasAuthority = hasAuthority;
|
||||||
|
|
||||||
_client = client;
|
_client = client;
|
||||||
_spawnPayload = payload;
|
|
||||||
|
|
||||||
Attached?.Invoke(this);
|
Attached?.Invoke(this);
|
||||||
}
|
}
|
||||||
@@ -96,15 +97,9 @@ namespace Ragon.Client
|
|||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachPayload(IRagonPayload? payload)
|
public void AttachPayload(RagonPayload payload)
|
||||||
{
|
{
|
||||||
if (payload == null) return;
|
_spawnPayload = payload;
|
||||||
|
|
||||||
var buffer = new RagonBuffer();
|
|
||||||
payload.Serialize(buffer);
|
|
||||||
|
|
||||||
_spawnPayload = new RagonPayload();
|
|
||||||
_spawnPayload.Read(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetAttachPayload<T>() where T : IRagonPayload, new()
|
public T GetAttachPayload<T>() where T : IRagonPayload, new()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ using Ragon.Protocol;
|
|||||||
|
|
||||||
namespace Ragon.Client;
|
namespace Ragon.Client;
|
||||||
|
|
||||||
public struct RagonPayload
|
public class RagonPayload
|
||||||
{
|
{
|
||||||
private readonly uint[] _data = new uint[128];
|
private readonly uint[] _data = new uint[128];
|
||||||
private readonly int _size = 0;
|
private readonly int _size = 0;
|
||||||
@@ -32,16 +32,12 @@ public struct RagonPayload
|
|||||||
|
|
||||||
public void Read(RagonBuffer buffer)
|
public void Read(RagonBuffer buffer)
|
||||||
{
|
{
|
||||||
var readOnlySpan = _data.AsSpan();
|
buffer.ReadArray(_data, _size);
|
||||||
|
|
||||||
buffer.ReadSpan(ref readOnlySpan, _size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(RagonBuffer buffer)
|
public void Write(RagonBuffer buffer)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<uint> readOnlySpan = _data.AsSpan();
|
buffer.WriteArray(_data, _size);
|
||||||
|
|
||||||
buffer.WriteSpan(ref readOnlySpan, _size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
|||||||
@@ -23,16 +23,18 @@ internal class EntityCreateHandler : Handler
|
|||||||
private readonly RagonClient _client;
|
private readonly RagonClient _client;
|
||||||
private readonly RagonPlayerCache _playerCache;
|
private readonly RagonPlayerCache _playerCache;
|
||||||
private readonly RagonEntityCache _entityCache;
|
private readonly RagonEntityCache _entityCache;
|
||||||
|
private readonly IRagonEntityListener _entityListener;
|
||||||
public EntityCreateHandler(
|
public EntityCreateHandler(
|
||||||
RagonClient client,
|
RagonClient client,
|
||||||
RagonPlayerCache playerCache,
|
RagonPlayerCache playerCache,
|
||||||
RagonEntityCache entityCache
|
RagonEntityCache entityCache,
|
||||||
|
IRagonEntityListener entityListener
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_entityCache = entityCache;
|
_entityCache = entityCache;
|
||||||
_playerCache = playerCache;
|
_playerCache = playerCache;
|
||||||
|
_entityListener = entityListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Handle(RagonBuffer buffer)
|
public void Handle(RagonBuffer buffer)
|
||||||
@@ -52,7 +54,13 @@ internal class EntityCreateHandler : Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
var hasAuthority = _playerCache.Local.Id == player.Id;
|
var hasAuthority = _playerCache.Local.Id == player.Id;
|
||||||
var entity = _entityCache.OnCreate(attachId, entityType, 0, entityId, hasAuthority);
|
var entity = _entityCache.TryGetEntity(attachId, entityType, 0, entityId, hasAuthority, out var hasCreated);
|
||||||
entity.Attach(_client, entityId, entityType, hasAuthority, player, payload);
|
|
||||||
|
entity.AttachPayload(payload);
|
||||||
|
|
||||||
|
if (hasCreated)
|
||||||
|
_entityListener.OnEntityCreated(entity);
|
||||||
|
|
||||||
|
entity.Attach(_client, entityId, entityType, hasAuthority, player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,8 +53,9 @@ internal class PlayerLeftHandler : Handler
|
|||||||
toDeleteIds[i] = entityId;
|
toDeleteIds[i] = entityId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var emptyPayload = new RagonPayload(0);
|
||||||
foreach (var id in toDeleteIds)
|
foreach (var id in toDeleteIds)
|
||||||
_entityCache.OnDestroy(id, new RagonPayload());
|
_entityCache.OnDestroy(id, emptyPayload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,19 +22,22 @@ namespace Ragon.Client;
|
|||||||
|
|
||||||
internal class SnapshotHandler : Handler
|
internal class SnapshotHandler : Handler
|
||||||
{
|
{
|
||||||
private RagonClient _client;
|
private readonly IRagonEntityListener _entityListener;
|
||||||
private RagonListenerList _listenerList;
|
private readonly RagonClient _client;
|
||||||
private RagonEntityCache _entityCache;
|
private readonly RagonListenerList _listenerList;
|
||||||
private RagonPlayerCache _playerCache;
|
private readonly RagonEntityCache _entityCache;
|
||||||
|
private readonly RagonPlayerCache _playerCache;
|
||||||
|
|
||||||
public SnapshotHandler(
|
public SnapshotHandler(
|
||||||
RagonClient ragonClient,
|
RagonClient ragonClient,
|
||||||
RagonListenerList listenerList,
|
RagonListenerList listenerList,
|
||||||
RagonEntityCache entityCache,
|
RagonEntityCache entityCache,
|
||||||
RagonPlayerCache playerCache
|
RagonPlayerCache playerCache,
|
||||||
|
IRagonEntityListener entityListener
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_client = ragonClient;
|
_client = ragonClient;
|
||||||
|
_entityListener = entityListener;
|
||||||
_listenerList = listenerList;
|
_listenerList = listenerList;
|
||||||
_entityCache = entityCache;
|
_entityCache = entityCache;
|
||||||
_playerCache = playerCache;
|
_playerCache = playerCache;
|
||||||
@@ -51,7 +54,10 @@ internal class SnapshotHandler : Handler
|
|||||||
var playerName = buffer.ReadString();
|
var playerName = buffer.ReadString();
|
||||||
|
|
||||||
_playerCache.AddPlayer(playerPeerId, playerId, playerName);
|
_playerCache.AddPlayer(playerPeerId, playerId, playerName);
|
||||||
|
|
||||||
|
RagonLog.Trace($"Player {playerPeerId} - {playerId} - {playerName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var dynamicEntities = buffer.ReadUShort();
|
var dynamicEntities = buffer.ReadUShort();
|
||||||
RagonLog.Trace("Dynamic Entities: " + dynamicEntities);
|
RagonLog.Trace("Dynamic Entities: " + dynamicEntities);
|
||||||
for (var i = 0; i < dynamicEntities; i++)
|
for (var i = 0; i < dynamicEntities; i++)
|
||||||
@@ -60,16 +66,30 @@ internal class SnapshotHandler : Handler
|
|||||||
var entityId = buffer.ReadUShort();
|
var entityId = buffer.ReadUShort();
|
||||||
var ownerPeerId = buffer.ReadUShort();
|
var ownerPeerId = buffer.ReadUShort();
|
||||||
var payloadSize = buffer.ReadUShort();
|
var payloadSize = buffer.ReadUShort();
|
||||||
var player = _playerCache.GetPlayerByPeer(ownerPeerId);
|
RagonLog.Trace("Read offset: " + buffer.ReadOffset);
|
||||||
|
|
||||||
var payload = new RagonPayload(payloadSize);
|
var player = _playerCache.GetPlayerByPeer(ownerPeerId);
|
||||||
payload.Read(buffer);
|
if (player == null)
|
||||||
|
{
|
||||||
|
RagonLog.Error($"Player not found with peerId: ${ownerPeerId}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var hasAuthority = _playerCache.Local.Id == player.Id;
|
var hasAuthority = _playerCache.Local.Id == player.Id;
|
||||||
var entity = _entityCache.OnCreate(0, entityType, 0, entityId, hasAuthority);
|
var entity = _entityCache.TryGetEntity(0, entityType, 0, entityId, hasAuthority, out _);
|
||||||
|
|
||||||
|
if (payloadSize > 0)
|
||||||
|
{
|
||||||
|
var payload = new RagonPayload(payloadSize);
|
||||||
|
payload.Read(buffer);
|
||||||
|
|
||||||
|
entity.AttachPayload(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
_entityListener.OnEntityCreated(entity);
|
||||||
|
|
||||||
entity.Read(buffer);
|
entity.Read(buffer);
|
||||||
entity.Attach(_client, entityId, entityType, hasAuthority, player, payload);
|
entity.Attach(_client, entityId, entityType, hasAuthority, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
var staticEntities = buffer.ReadUShort();
|
var staticEntities = buffer.ReadUShort();
|
||||||
@@ -81,16 +101,21 @@ internal class SnapshotHandler : Handler
|
|||||||
var staticId = buffer.ReadUShort();
|
var staticId = buffer.ReadUShort();
|
||||||
var ownerPeerId = buffer.ReadUShort();
|
var ownerPeerId = buffer.ReadUShort();
|
||||||
var payloadSize = buffer.ReadUShort();
|
var payloadSize = buffer.ReadUShort();
|
||||||
var player = _playerCache.GetPlayerByPeer(ownerPeerId);
|
|
||||||
|
|
||||||
var payload = new RagonPayload(payloadSize);
|
var player = _playerCache.GetPlayerByPeer(ownerPeerId);
|
||||||
payload.Read(buffer);
|
if (player == null)
|
||||||
|
{
|
||||||
|
RagonLog.Error($"Player not found with peerId: ${ownerPeerId}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var hasAuthority = _playerCache.Local.Id == player.Id;
|
var hasAuthority = _playerCache.Local.Id == player.Id;
|
||||||
var entity = _entityCache.OnCreate(0, entityType, staticId, entityId, hasAuthority);
|
var entity = _entityCache.TryGetEntity(0, entityType, staticId, entityId, hasAuthority, out _);
|
||||||
|
|
||||||
|
_entityListener.OnEntityCreated(entity);
|
||||||
|
|
||||||
entity.Read(buffer);
|
entity.Read(buffer);
|
||||||
entity.Attach(_client, entityId, entityType, hasAuthority, player, payload);
|
entity.Attach(_client, entityId, entityType, hasAuthority, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
_listenerList.OnJoined();
|
_listenerList.OnJoined();
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ namespace Ragon.Client
|
|||||||
_session = new RagonSession(this, _readBuffer);
|
_session = new RagonSession(this, _readBuffer);
|
||||||
|
|
||||||
_playerCache = new RagonPlayerCache();
|
_playerCache = new RagonPlayerCache();
|
||||||
_entityCache = new RagonEntityCache(this, _playerCache, _entityListener, _sceneCollector);
|
_entityCache = new RagonEntityCache(this, _playerCache, _sceneCollector);
|
||||||
|
|
||||||
_handlers = new Handler[byte.MaxValue];
|
_handlers = new Handler[byte.MaxValue];
|
||||||
_handlers[(byte)RagonOperation.AUTHORIZED_SUCCESS] = new AuthorizeSuccessHandler(_listenerList);
|
_handlers[(byte)RagonOperation.AUTHORIZED_SUCCESS] = new AuthorizeSuccessHandler(_listenerList);
|
||||||
@@ -112,11 +112,11 @@ namespace Ragon.Client
|
|||||||
_handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, _listenerList);
|
_handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, _listenerList);
|
||||||
_handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_entityCache, _playerCache, _listenerList);
|
_handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_entityCache, _playerCache, _listenerList);
|
||||||
_handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, _listenerList);
|
_handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, _listenerList);
|
||||||
_handlers[(byte)RagonOperation.CREATE_ENTITY] = new EntityCreateHandler(this, _playerCache, _entityCache);
|
_handlers[(byte)RagonOperation.CREATE_ENTITY] = new EntityCreateHandler(this, _playerCache, _entityCache, _entityListener);
|
||||||
_handlers[(byte)RagonOperation.REMOVE_ENTITY] = new EntityRemoveHandler(_entityCache);
|
_handlers[(byte)RagonOperation.REMOVE_ENTITY] = new EntityRemoveHandler(_entityCache);
|
||||||
_handlers[(byte)RagonOperation.REPLICATE_ENTITY_STATE] = new StateEntityHandler(_entityCache);
|
_handlers[(byte)RagonOperation.REPLICATE_ENTITY_STATE] = new StateEntityHandler(_entityCache);
|
||||||
_handlers[(byte)RagonOperation.REPLICATE_ENTITY_EVENT] = new EntityEventHandler(this, _playerCache, _entityCache);
|
_handlers[(byte)RagonOperation.REPLICATE_ENTITY_EVENT] = new EntityEventHandler(this, _playerCache, _entityCache);
|
||||||
_handlers[(byte)RagonOperation.SNAPSHOT] = new SnapshotHandler(this, _listenerList, _entityCache, _playerCache);
|
_handlers[(byte)RagonOperation.SNAPSHOT] = new SnapshotHandler(this, _listenerList, _entityCache, _playerCache, _entityListener);
|
||||||
|
|
||||||
var protocolRaw = RagonVersion.Parse(protocol);
|
var protocolRaw = RagonVersion.Parse(protocol);
|
||||||
_connection.Connect(address, port, protocolRaw);
|
_connection.Connect(address, port, protocolRaw);
|
||||||
@@ -145,6 +145,7 @@ namespace Ragon.Client
|
|||||||
_stats.Update(_connection.BytesSent, _connection.BytesReceived, _connection.Ping, dt);
|
_stats.Update(_connection.BytesSent, _connection.BytesReceived, _connection.Ping, dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_listenerList.Update();
|
||||||
_connection.Update();
|
_connection.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ public sealed class RagonEntityCache
|
|||||||
private readonly Dictionary<uint, RagonEntity> _sceneEntities = new();
|
private readonly Dictionary<uint, RagonEntity> _sceneEntities = new();
|
||||||
|
|
||||||
private readonly RagonClient _client;
|
private readonly RagonClient _client;
|
||||||
private readonly IRagonEntityListener _entityListener;
|
|
||||||
private readonly IRagonSceneCollector _sceneCollector;
|
private readonly IRagonSceneCollector _sceneCollector;
|
||||||
private readonly RagonPlayerCache _playerCache;
|
private readonly RagonPlayerCache _playerCache;
|
||||||
|
|
||||||
@@ -35,12 +34,10 @@ public sealed class RagonEntityCache
|
|||||||
public RagonEntityCache(
|
public RagonEntityCache(
|
||||||
RagonClient client,
|
RagonClient client,
|
||||||
RagonPlayerCache playerCache,
|
RagonPlayerCache playerCache,
|
||||||
IRagonEntityListener listener,
|
|
||||||
IRagonSceneCollector sceneCollector
|
IRagonSceneCollector sceneCollector
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_entityListener = listener;
|
|
||||||
_sceneCollector = sceneCollector;
|
_sceneCollector = sceneCollector;
|
||||||
_playerCache = playerCache;
|
_playerCache = playerCache;
|
||||||
}
|
}
|
||||||
@@ -50,7 +47,7 @@ public sealed class RagonEntityCache
|
|||||||
return _entityMap.TryGetValue(id, out entity);
|
return _entityMap.TryGetValue(id, out entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Create(RagonEntity entity, IRagonPayload? spawnPayload)
|
public void Create(RagonEntity entity, RagonPayload spawnPayload)
|
||||||
{
|
{
|
||||||
var attachId = (ushort)(_playerCache.Local.PeerId + _localEntitiesCounter++);
|
var attachId = (ushort)(_playerCache.Local.PeerId + _localEntitiesCounter++);
|
||||||
var buffer = _client.Buffer;
|
var buffer = _client.Buffer;
|
||||||
@@ -63,7 +60,7 @@ public sealed class RagonEntityCache
|
|||||||
|
|
||||||
entity.State.WriteInfo(buffer);
|
entity.State.WriteInfo(buffer);
|
||||||
|
|
||||||
spawnPayload?.Serialize(buffer);
|
spawnPayload?.Write(buffer);
|
||||||
|
|
||||||
_pendingEntities.Add(attachId, entity);
|
_pendingEntities.Add(attachId, entity);
|
||||||
|
|
||||||
@@ -84,7 +81,7 @@ public sealed class RagonEntityCache
|
|||||||
_client.Reliable.Send(sendData);
|
_client.Reliable.Send(sendData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Destroy(RagonEntity entity, IRagonPayload? destroyPayload)
|
public void Destroy(RagonEntity entity, RagonPayload destroyPayload)
|
||||||
{
|
{
|
||||||
if (!entity.IsAttached)
|
if (!entity.IsAttached)
|
||||||
{
|
{
|
||||||
@@ -98,7 +95,7 @@ public sealed class RagonEntityCache
|
|||||||
buffer.WriteOperation(RagonOperation.REMOVE_ENTITY);
|
buffer.WriteOperation(RagonOperation.REMOVE_ENTITY);
|
||||||
buffer.WriteUShort(entity.Id);
|
buffer.WriteUShort(entity.Id);
|
||||||
|
|
||||||
destroyPayload?.Serialize(buffer);
|
destroyPayload?.Write(buffer);
|
||||||
|
|
||||||
var sendData = buffer.ToArray();
|
var sendData = buffer.ToArray();
|
||||||
_client.Reliable.Send(sendData);
|
_client.Reliable.Send(sendData);
|
||||||
@@ -162,7 +159,7 @@ public sealed class RagonEntityCache
|
|||||||
|
|
||||||
internal void Cleanup()
|
internal void Cleanup()
|
||||||
{
|
{
|
||||||
var payload = new RagonPayload();
|
var payload = new RagonPayload(0);
|
||||||
foreach (var ent in _entityList)
|
foreach (var ent in _entityList)
|
||||||
ent.Detach(payload);
|
ent.Detach(payload);
|
||||||
|
|
||||||
@@ -170,53 +167,58 @@ public sealed class RagonEntityCache
|
|||||||
_entityList.Clear();
|
_entityList.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal RagonEntity OnCreate(ushort attachId, ushort entityType, ushort sceneId, ushort entityId, bool hasAuthority)
|
internal RagonEntity TryGetEntity(ushort attachId, ushort entityType, ushort sceneId, ushort entityId, bool hasAuthority, out bool hasCreated)
|
||||||
{
|
{
|
||||||
if (sceneId > 0)
|
if (sceneId > 0)
|
||||||
{
|
{
|
||||||
if (_sceneEntities.TryGetValue(sceneId, out var entity))
|
if (_sceneEntities.TryGetValue(sceneId, out var sceneEntity))
|
||||||
{
|
{
|
||||||
_entityMap.Add(entityId, entity);
|
_entityMap.Add(entityId, sceneEntity);
|
||||||
|
|
||||||
if (hasAuthority)
|
if (hasAuthority)
|
||||||
_entityList.Add(entity);
|
_entityList.Add(sceneEntity);
|
||||||
|
|
||||||
return entity;
|
hasCreated = false;
|
||||||
|
|
||||||
|
return sceneEntity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pendingEntities.Remove(attachId, out var existsEntity))
|
if (_pendingEntities.TryGetValue(attachId, out var pendingEntity))
|
||||||
{
|
{
|
||||||
_entityMap.Add(entityId, existsEntity);
|
_pendingEntities.Remove(attachId);
|
||||||
|
_entityMap.Add(entityId, pendingEntity);
|
||||||
|
|
||||||
if (hasAuthority)
|
if (hasAuthority)
|
||||||
_entityList.Add(existsEntity);
|
_entityList.Add(pendingEntity);
|
||||||
|
|
||||||
return existsEntity;
|
hasCreated = false;
|
||||||
|
|
||||||
|
return pendingEntity;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
var entity = new RagonEntity(entityType, sceneId);
|
|
||||||
|
|
||||||
_entityMap.Add(entityId, entity);
|
|
||||||
|
|
||||||
if (hasAuthority)
|
var entity = new RagonEntity(entityType, sceneId);
|
||||||
_entityList.Add(entity);
|
|
||||||
|
|
||||||
_entityListener.OnEntityCreated(entity);
|
_entityMap.Add(entityId, entity);
|
||||||
|
|
||||||
return entity;
|
if (hasAuthority)
|
||||||
}
|
_entityList.Add(entity);
|
||||||
|
|
||||||
|
hasCreated = true;
|
||||||
|
|
||||||
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal void OnDestroy(ushort entityId, RagonPayload payload)
|
internal void OnDestroy(ushort entityId, RagonPayload payload)
|
||||||
{
|
{
|
||||||
if (_entityMap.Remove(entityId, out var ragonEntity))
|
if (_entityMap.TryGetValue(entityId, out var entity))
|
||||||
{
|
{
|
||||||
_entityList.Remove(ragonEntity);
|
_entityMap.Remove(entityId);
|
||||||
|
_entityList.Remove(entity);
|
||||||
|
|
||||||
ragonEntity.Detach(payload);
|
entity.Detach(payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace Ragon.Client
|
|||||||
private readonly List<IRagonOwnershipChangedListener> _ownershipChangedListeners = new();
|
private readonly List<IRagonOwnershipChangedListener> _ownershipChangedListeners = new();
|
||||||
private readonly List<IRagonPlayerJoinListener> _playerJoinListeners = new();
|
private readonly List<IRagonPlayerJoinListener> _playerJoinListeners = new();
|
||||||
private readonly List<IRagonPlayerLeftListener> _playerLeftListeners = new();
|
private readonly List<IRagonPlayerLeftListener> _playerLeftListeners = new();
|
||||||
|
private readonly List<Action> _delayedActions = new();
|
||||||
|
|
||||||
public RagonListenerList(RagonClient client)
|
public RagonListenerList(RagonClient client)
|
||||||
{
|
{
|
||||||
@@ -51,17 +52,29 @@ namespace Ragon.Client
|
|||||||
|
|
||||||
public void Remove(IRagonListener listener)
|
public void Remove(IRagonListener listener)
|
||||||
{
|
{
|
||||||
_authorizationListeners.Remove(listener);
|
_delayedActions.Add(() =>
|
||||||
_connectionListeners.Remove(listener);
|
{
|
||||||
_failedListeners.Remove(listener);
|
_authorizationListeners.Remove(listener);
|
||||||
_joinListeners.Remove(listener);
|
_connectionListeners.Remove(listener);
|
||||||
_leftListeners.Remove(listener);
|
_failedListeners.Remove(listener);
|
||||||
_levelListeners.Remove(listener);
|
_joinListeners.Remove(listener);
|
||||||
_ownershipChangedListeners.Remove(listener);
|
_leftListeners.Remove(listener);
|
||||||
_playerJoinListeners.Remove(listener);
|
_levelListeners.Remove(listener);
|
||||||
_playerLeftListeners.Remove(listener);
|
_ownershipChangedListeners.Remove(listener);
|
||||||
|
_playerJoinListeners.Remove(listener);
|
||||||
|
_playerLeftListeners.Remove(listener);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
foreach (var action in _delayedActions)
|
||||||
|
action.Invoke();
|
||||||
|
|
||||||
|
_delayedActions.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Add(IRagonAuthorizationListener listener)
|
public void Add(IRagonAuthorizationListener listener)
|
||||||
{
|
{
|
||||||
_authorizationListeners.Add(listener);
|
_authorizationListeners.Add(listener);
|
||||||
@@ -109,47 +122,48 @@ namespace Ragon.Client
|
|||||||
|
|
||||||
public void Remove(IRagonAuthorizationListener listener)
|
public void Remove(IRagonAuthorizationListener listener)
|
||||||
{
|
{
|
||||||
_authorizationListeners.Remove(listener);
|
_delayedActions.Add(() => _authorizationListeners.Remove(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(IRagonConnectionListener listener)
|
public void Remove(IRagonConnectionListener listener)
|
||||||
{
|
{
|
||||||
_connectionListeners.Remove(listener);
|
|
||||||
|
_delayedActions.Add(() => _connectionListeners.Remove(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(IRagonFailedListener listener)
|
public void Remove(IRagonFailedListener listener)
|
||||||
{
|
{
|
||||||
_failedListeners.Remove(listener);
|
_delayedActions.Add(() => _failedListeners.Remove(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(IRagonJoinListener listener)
|
public void Remove(IRagonJoinListener listener)
|
||||||
{
|
{
|
||||||
_joinListeners.Remove(listener);
|
_delayedActions.Add(() => _joinListeners.Remove(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(IRagonLeftListener listener)
|
public void Remove(IRagonLeftListener listener)
|
||||||
{
|
{
|
||||||
_leftListeners.Remove(listener);
|
_delayedActions.Add(() => _leftListeners.Remove(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(IRagonLevelListener listener)
|
public void Remove(IRagonLevelListener listener)
|
||||||
{
|
{
|
||||||
_levelListeners.Remove(listener);
|
_delayedActions.Add(() => _levelListeners.Remove(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(IRagonOwnershipChangedListener listener)
|
public void Remove(IRagonOwnershipChangedListener listener)
|
||||||
{
|
{
|
||||||
_ownershipChangedListeners.Remove(listener);
|
_delayedActions.Add(() => _ownershipChangedListeners.Remove(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(IRagonPlayerJoinListener listener)
|
public void Remove(IRagonPlayerJoinListener listener)
|
||||||
{
|
{
|
||||||
_playerJoinListeners.Remove(listener);
|
_delayedActions.Add(() => _playerJoinListeners.Remove(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(IRagonPlayerLeftListener listener)
|
public void Remove(IRagonPlayerLeftListener listener)
|
||||||
{
|
{
|
||||||
_playerLeftListeners.Remove(listener);
|
_delayedActions.Add(() => _playerLeftListeners.Remove(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnAuthorizationSuccess(string playerId, string playerName, string payload)
|
public void OnAuthorizationSuccess(string playerId, string playerName, string payload)
|
||||||
|
|||||||
@@ -64,9 +64,10 @@ public sealed class RagonPlayerCache
|
|||||||
|
|
||||||
public void RemovePlayer(string playerId)
|
public void RemovePlayer(string playerId)
|
||||||
{
|
{
|
||||||
if (_playersById.Remove(playerId, out var player))
|
if (_playersById.TryGetValue(playerId, out var player))
|
||||||
{
|
{
|
||||||
_players.Remove(player);
|
_players.Remove(player);
|
||||||
|
_playersById.Remove(playerId);
|
||||||
_playersByConnection.Remove(player.PeerId);
|
_playersByConnection.Remove(player.PeerId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,10 +55,10 @@ namespace Ragon.Client
|
|||||||
public void SceneLoaded() => _scene.SceneLoaded();
|
public void SceneLoaded() => _scene.SceneLoaded();
|
||||||
|
|
||||||
public void CreateEntity(RagonEntity entity) => CreateEntity(entity, null);
|
public void CreateEntity(RagonEntity entity) => CreateEntity(entity, null);
|
||||||
public void CreateEntity(RagonEntity entity, IRagonPayload? payload) => _entityCache.Create(entity, payload);
|
public void CreateEntity(RagonEntity entity, RagonPayload payload) => _entityCache.Create(entity, payload);
|
||||||
public void TransferEntity(RagonEntity entity, RagonPlayer player) => _entityCache.Transfer(entity, player);
|
public void TransferEntity(RagonEntity entity, RagonPlayer player) => _entityCache.Transfer(entity, player);
|
||||||
|
|
||||||
public void DestroyEntity(RagonEntity entityId) => DestroyEntity(entityId, null);
|
public void DestroyEntity(RagonEntity entityId) => DestroyEntity(entityId, null);
|
||||||
public void DestroyEntity(RagonEntity entityId, IRagonPayload? payload) => _entityCache.Destroy(entityId, payload);
|
public void DestroyEntity(RagonEntity entityId, RagonPayload payload) => _entityCache.Destroy(entityId, payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
<RepositoryUrl>https://github.com/edmand46/Ragon</RepositoryUrl>
|
<RepositoryUrl>https://github.com/edmand46/Ragon</RepositoryUrl>
|
||||||
<RepositoryType>Source</RepositoryType>
|
<RepositoryType>Source</RepositoryType>
|
||||||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
|||||||
@@ -58,7 +58,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -292,7 +291,7 @@ namespace Ragon.Protocol
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void ReadSpan(ref Span<uint> data, int size)
|
public void ReadArray(uint[] data, int size)
|
||||||
{
|
{
|
||||||
var used = _read & 0x0000001F;
|
var used = _read & 0x0000001F;
|
||||||
var index = _read >> 5;
|
var index = _read >> 5;
|
||||||
@@ -321,8 +320,9 @@ namespace Ragon.Protocol
|
|||||||
_read += size;
|
_read += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void WriteSpan(ref ReadOnlySpan<uint> data, int size)
|
public void WriteArray(uint[] data, int size)
|
||||||
{
|
{
|
||||||
var used = _write & 0x0000001F;
|
var used = _write & 0x0000001F;
|
||||||
var index = _write >> 5;
|
var index = _write >> 5;
|
||||||
@@ -333,7 +333,7 @@ namespace Ragon.Protocol
|
|||||||
|
|
||||||
for (var i = 0; i < limit; i += 1)
|
for (var i = 0; i < limit; i += 1)
|
||||||
{
|
{
|
||||||
var prepared = (ulong) data[i] << used;
|
var prepared = (ulong)data[i] << used;
|
||||||
var mask = (1UL << used) - 1;
|
var mask = (1UL << used) - 1;
|
||||||
var scratch = _buckets[index] & mask;
|
var scratch = _buckets[index] & mask;
|
||||||
var result = scratch | prepared;
|
var result = scratch | prepared;
|
||||||
@@ -356,15 +356,13 @@ namespace Ragon.Protocol
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void FromBuffer(RagonBuffer buffer, int size)
|
public void FromBuffer(RagonBuffer buffer, int size)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<uint> data = buffer._buckets.AsSpan();
|
WriteArray(buffer._buckets, size);
|
||||||
WriteSpan(ref data, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void ToBuffer(RagonBuffer buffer, int size)
|
public void ToBuffer(RagonBuffer buffer, int size)
|
||||||
{
|
{
|
||||||
var data = buffer._buckets.AsSpan();
|
ReadArray(buffer._buckets, size);
|
||||||
ReadSpan(ref data, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FromArray(byte[] data)
|
public void FromArray(byte[] data)
|
||||||
|
|||||||
@@ -117,11 +117,13 @@ public class RagonEntity : IRagonEntity
|
|||||||
{
|
{
|
||||||
buffer.WriteUShort(Type);
|
buffer.WriteUShort(Type);
|
||||||
buffer.WriteUShort(Id);
|
buffer.WriteUShort(Id);
|
||||||
|
|
||||||
if (StaticId != 0)
|
if (StaticId != 0)
|
||||||
buffer.WriteUShort(StaticId);
|
buffer.WriteUShort(StaticId);
|
||||||
buffer.WriteUShort(Owner.Connection.Id);
|
|
||||||
|
|
||||||
|
buffer.WriteUShort(Owner.Connection.Id);
|
||||||
buffer.WriteUShort(Payload.Size);
|
buffer.WriteUShort(Payload.Size);
|
||||||
|
|
||||||
Payload.Write(buffer);
|
Payload.Write(buffer);
|
||||||
|
|
||||||
_state.Snapshot(buffer);
|
_state.Snapshot(buffer);
|
||||||
|
|||||||
@@ -39,15 +39,12 @@ public class RagonEvent
|
|||||||
|
|
||||||
public void Read(RagonBuffer buffer)
|
public void Read(RagonBuffer buffer)
|
||||||
{
|
{
|
||||||
var readOnlySpan = _data.AsSpan();
|
buffer.ReadArray(_data, buffer.Capacity);
|
||||||
_size = buffer.Capacity;
|
|
||||||
buffer.ReadSpan(ref readOnlySpan, _size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(RagonBuffer buffer)
|
public void Write(RagonBuffer buffer)
|
||||||
{
|
{
|
||||||
if (_size == 0) return;
|
if (_size == 0) return;
|
||||||
ReadOnlySpan<uint> readOnlySpan = _data.AsSpan();
|
buffer.WriteArray(_data, _size);
|
||||||
buffer.WriteSpan(ref readOnlySpan, _size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,19 +28,13 @@ public class RagonPayload
|
|||||||
|
|
||||||
public void Read(RagonBuffer buffer)
|
public void Read(RagonBuffer buffer)
|
||||||
{
|
{
|
||||||
var readOnlySpan = _data.AsSpan();
|
|
||||||
|
|
||||||
_size = buffer.Capacity;
|
_size = buffer.Capacity;
|
||||||
|
buffer.ReadArray(_data, _size);
|
||||||
buffer.ReadSpan(ref readOnlySpan, _size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(RagonBuffer buffer)
|
public void Write(RagonBuffer buffer)
|
||||||
{
|
{
|
||||||
if (_size == 0) return;
|
if (_size == 0) return;
|
||||||
|
buffer.WriteArray(_data, _size);
|
||||||
ReadOnlySpan<uint> readOnlySpan = _data.AsSpan();
|
|
||||||
|
|
||||||
buffer.WriteSpan(ref readOnlySpan, _size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,15 +37,14 @@ public class RagonProperty : RagonPayload
|
|||||||
|
|
||||||
public void Read(RagonBuffer buffer)
|
public void Read(RagonBuffer buffer)
|
||||||
{
|
{
|
||||||
var readOnlySpan = _data.AsSpan();
|
|
||||||
if (IsFixed)
|
if (IsFixed)
|
||||||
{
|
{
|
||||||
buffer.ReadSpan(ref readOnlySpan, Size);
|
buffer.ReadArray(_data, Size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Size = (int) buffer.Read();
|
Size = (int) buffer.Read();
|
||||||
buffer.ReadSpan(ref readOnlySpan, Size);
|
buffer.ReadArray(_data, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
IsDirty = true;
|
IsDirty = true;
|
||||||
@@ -53,8 +52,7 @@ public class RagonProperty : RagonPayload
|
|||||||
|
|
||||||
public void Write(RagonBuffer buffer)
|
public void Write(RagonBuffer buffer)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<uint> readOnlySpan = _data.AsSpan();
|
buffer.WriteArray(_data, Size);
|
||||||
buffer.WriteSpan(ref readOnlySpan, Size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ public sealed class SceneLoadedOperation : IRagonOperation
|
|||||||
|
|
||||||
if (player == owner)
|
if (player == owner)
|
||||||
{
|
{
|
||||||
|
|
||||||
var statics = reader.ReadUShort();
|
var statics = reader.ReadUShort();
|
||||||
for (var staticIndex = 0; staticIndex < statics; staticIndex++)
|
for (var staticIndex = 0; staticIndex < statics; staticIndex++)
|
||||||
{
|
{
|
||||||
@@ -73,7 +72,7 @@ public sealed class SceneLoadedOperation : IRagonOperation
|
|||||||
var playerInfo = $"Player {context.Connection.Id}|{context.LobbyPlayer.Name}";
|
var playerInfo = $"Player {context.Connection.Id}|{context.LobbyPlayer.Name}";
|
||||||
var entityInfo = $"{entity.Id}:{entity.Type}";
|
var entityInfo = $"{entity.Id}:{entity.Type}";
|
||||||
|
|
||||||
_logger.Trace($"{playerInfo} created entity {entityInfo}");
|
_logger.Trace($"{playerInfo} created static entity {entityInfo}");
|
||||||
|
|
||||||
entity.Attach(player);
|
entity.Attach(player);
|
||||||
room.AttachEntity(entity);
|
room.AttachEntity(entity);
|
||||||
|
|||||||
Reference in New Issue
Block a user