Compare commits

...

24 Commits

Author SHA1 Message Date
edmand46 27db256902 🐛 scene entities not execute buffered events 2023-09-03 13:29:37 +03:00
edmand46 8705e93929 🐛 event size 2023-08-02 22:13:51 +03:00
edmand46 08e931d1bd 🚑 remove static entity spawn 2023-08-01 22:21:21 +03:00
edmand46 fb58dedfaf changed scene loading flow 2023-07-30 21:46:42 +03:00
edmand46 92062cd708 🎨 update naming of fields 2023-07-30 21:19:39 +03:00
edmand46 5fc55eaddc wip 2023-07-30 21:14:14 +03:00
edmand46 4a8aae11e3 🚑 fixed empty state values 2023-07-30 17:44:51 +03:00
edmand46 cd9304e63a Merge pull request #13 from edmand46/fix/payload
Fix/payload
2023-07-30 17:01:08 +03:00
edmand46 5199b5271b 🐛 Remove listener inside callback 2023-07-30 16:56:11 +03:00
edmand46 c01b748031 wip 2023-07-29 10:58:06 +03:00
edmand46 0a8d761cc1 🐛 empty payload 2023-07-23 15:56:08 +03:00
edmand46 f38c7e98de ⬆️ deps 2023-07-23 11:23:38 +03:00
edmand46 0479a21980 feat: added safe get entity by id 2023-07-09 07:40:06 +03:00
edmand46 1406b17d62 🚑 independent buffers in properties 2023-07-01 08:12:40 +03:00
edmand46 105457ffa0 added transfer ownership, limit buffered events 2023-07-01 07:47:57 +03:00
edmand46 20662ae24d wip 2023-06-27 23:41:30 +03:00
edmand46 6c441d9dee feat: Entity.OnEvent now support resubscribing 2023-05-25 11:28:18 +03:00
edmand46 907bd2611e added reason of disconnect at callback 2023-05-08 00:16:43 +03:00
edmand46 91d8516ac9 independent buffers for ragon properties, extended buffer functionality 2023-05-07 23:54:07 +03:00
edmand46 ecdafeab00 ♻️ naming changing 2023-05-07 18:16:46 +03:00
edmand46 88baff9fee compressor extensions for write/read data and reduce boilerplate 2023-05-07 18:07:56 +03:00
edmand46 fdb41649b2 ♻️ added checks in client sdk 2023-05-07 12:46:39 +03:00
edmand46 aa607a7eb9 Update README.md 2023-05-06 15:30:16 +04:00
edmand46 efebf4ceda 🐛 scene entities 2023-04-14 17:42:27 +04:00
76 changed files with 851 additions and 484 deletions
+2
View File
@@ -4,3 +4,5 @@
obj obj
bin bin
*.user *.user
*.dylib
*.dll
+1 -1
View File
@@ -6,7 +6,7 @@
Ragon is fully free, small and high perfomance room based game server with plugin based architecture. Ragon is fully free, small and high perfomance room based game server with plugin based architecture.
<a href="https://www.ragon-server.com/docs/installation">Documentation</a> <a href="https://www.ragon-server.com/docs/overview">Documentation</a>
### Features: ### Features:
- Effective - Effective
+27 -21
View File
@@ -1,8 +1,10 @@
using Ragon.Protocol;
namespace Ragon.Client.Simulation; namespace Ragon.Client.Simulation;
public class Game : IRagonListener public class Game : IRagonListener, IRagonSceneRequestListener
{ {
private RagonFloat _health; private RagonFloat _health;
private RagonInt _points; private RagonInt _points;
@@ -34,23 +36,7 @@ public class Game : IRagonListener
public void OnJoined(RagonClient client) public void OnJoined(RagonClient client)
{ {
RagonLog.Trace("Joined");
_health = new RagonFloat(100.0f, false, 0);
_health.Changed += () => Console.WriteLine($"[Ragon Property] Health: {_health.Value}");
_points = new RagonInt(0, -1000, 1000, false, 0);
_points.Changed += () => Console.WriteLine($"[Ragon Property] Points: {_points.Value}");
_name = new RagonString("Edmand 000", false);
_name.Changed += () => Console.WriteLine($"[Ragon Property] Name: {_name.Value}");
_entity = new RagonEntity(12, 0);
_entity.State.AddProperty(_health);
_entity.State.AddProperty(_points);
_entity.State.AddProperty(_name);
client.Room.CreateEntity(_entity);
} }
public void OnFailed(RagonClient client, string message) public void OnFailed(RagonClient client, string message)
@@ -63,7 +49,7 @@ public class Game : IRagonListener
RagonLog.Trace("Left"); RagonLog.Trace("Left");
} }
public void OnDisconnected(RagonClient client) public void OnDisconnected(RagonClient client, RagonDisconnect ragonDisconnect)
{ {
RagonLog.Trace("Disconnected"); RagonLog.Trace("Disconnected");
} }
@@ -83,11 +69,25 @@ public class Game : IRagonListener
RagonLog.Trace("Owner ship changed"); RagonLog.Trace("Owner ship changed");
} }
public void OnLevel(RagonClient client, string sceneName) public void OnSceneLoaded(RagonClient client)
{ {
RagonLog.Trace($"New level: {sceneName}"); RagonLog.Trace("Joined");
client.Room.SceneLoaded(); _health = new RagonFloat(100.0f, false, 0);
_health.Changed += () => Console.WriteLine($"[Ragon Property] Health: {_health.Value}");
_points = new RagonInt(0, -1000, 1000, false, 0);
_points.Changed += () => Console.WriteLine($"[Ragon Property] Points: {_points.Value}");
_name = new RagonString("Edmand 000", false);
_name.Changed += () => Console.WriteLine($"[Ragon Property] Name: {_name.Value}");
_entity = new RagonEntity(12, 0);
_entity.State.AddProperty(_health);
_entity.State.AddProperty(_points);
_entity.State.AddProperty(_name);
client.Room.CreateEntity(_entity);
} }
private float _timer = 0; private float _timer = 0;
@@ -107,4 +107,10 @@ public class Game : IRagonListener
_timer = 0; _timer = 0;
} }
} }
public void OnRequestScene(RagonClient client, string sceneName)
{
client.Room.SceneLoaded();
}
} }
@@ -16,6 +16,7 @@
using ENet; using ENet;
using Ragon.Protocol;
using Event = ENet.Event; using Event = ENet.Event;
using EventType = ENet.EventType; using EventType = ENet.EventType;
@@ -31,7 +32,7 @@ namespace Ragon.Client
public Action<byte[]> OnData { get; set; } public Action<byte[]> OnData { get; set; }
public Action OnConnected { get; set; } public Action OnConnected { get; set; }
public Action<DisconnectReason> OnDisconnected { get; set; } public Action<RagonDisconnect> OnDisconnected { get; set; }
public ulong BytesSent { get; } public ulong BytesSent { get; }
public ulong BytesReceived { get; } public ulong BytesReceived { get; }
public int Ping { get; } public int Ping { get; }
@@ -98,10 +99,10 @@ namespace Ragon.Client
OnConnected?.Invoke(); OnConnected?.Invoke();
break; break;
case EventType.Disconnect: case EventType.Disconnect:
OnDisconnected?.Invoke(DisconnectReason.MANUAL); OnDisconnected?.Invoke(RagonDisconnect.SERVER);
break; break;
case EventType.Timeout: case EventType.Timeout:
OnDisconnected?.Invoke(DisconnectReason.TIMEOUT); OnDisconnected?.Invoke(RagonDisconnect.TIMEOUT);
break; break;
case EventType.Receive: case EventType.Receive:
var data = new byte[_netEvent.Packet.Length]; var data = new byte[_netEvent.Packet.Length];
@@ -16,6 +16,7 @@
using ENet; using ENet;
using Ragon.Protocol;
using Event = ENet.Event; using Event = ENet.Event;
using EventType = ENet.EventType; using EventType = ENet.EventType;
@@ -31,7 +32,7 @@ namespace Ragon.Client
public Action<byte[]> OnData { get; set; } public Action<byte[]> OnData { get; set; }
public Action OnConnected { get; set; } public Action OnConnected { get; set; }
public Action<DisconnectReason> OnDisconnected { get; set; } public Action<RagonDisconnect> OnDisconnected { get; set; }
public ulong BytesSent { get; } public ulong BytesSent { get; }
public ulong BytesReceived { get; } public ulong BytesReceived { get; }
public int Ping { get; } public int Ping { get; }
@@ -99,10 +100,10 @@ namespace Ragon.Client
OnConnected?.Invoke(); OnConnected?.Invoke();
break; break;
case EventType.Disconnect: case EventType.Disconnect:
OnDisconnected?.Invoke(DisconnectReason.MANUAL); OnDisconnected?.Invoke(RagonDisconnect.SERVER);
break; break;
case EventType.Timeout: case EventType.Timeout:
OnDisconnected?.Invoke(DisconnectReason.TIMEOUT); OnDisconnected?.Invoke(RagonDisconnect.TIMEOUT);
break; break;
case EventType.Receive: case EventType.Receive:
var data = new byte[_netEvent.Packet.Length]; var data = new byte[_netEvent.Packet.Length];
+3 -3
View File
@@ -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>
+46 -23
View File
@@ -22,6 +22,7 @@ namespace Ragon.Client
public sealed class RagonEntity public sealed class RagonEntity
{ {
private delegate void OnEventDelegate(RagonPlayer player, RagonBuffer serializer); private delegate void OnEventDelegate(RagonPlayer player, RagonBuffer serializer);
private RagonClient _client; private RagonClient _client;
public ushort Id { get; private set; } public ushort Id { get; private set; }
@@ -48,18 +49,20 @@ namespace Ragon.Client
private RagonPayload _spawnPayload; private RagonPayload _spawnPayload;
private RagonPayload _destroyPayload; private RagonPayload _destroyPayload;
private Dictionary<int, OnEventDelegate> _events = new(); private readonly Dictionary<int, OnEventDelegate> _events = new Dictionary<int, OnEventDelegate>();
private Dictionary<int, Action<RagonPlayer, IRagonEvent>> _localEvents = new(); private readonly Dictionary<int, Action<RagonPlayer, IRagonEvent>> _localEvents = new Dictionary<int, Action<RagonPlayer, IRagonEvent>>();
public RagonEntity(ushort type = 0, ushort sceneId = 0) public RagonEntity(ushort type = 0, ushort sceneId = 0)
{ {
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;
@@ -69,7 +72,6 @@ namespace Ragon.Client
HasAuthority = hasAuthority; HasAuthority = hasAuthority;
_client = client; _client = client;
_spawnPayload = payload;
Attached?.Invoke(this); Attached?.Invoke(this);
} }
@@ -83,21 +85,29 @@ namespace Ragon.Client
internal T GetPayload<T>(RagonPayload data) where T : IRagonPayload, new() internal T GetPayload<T>(RagonPayload data) where T : IRagonPayload, new()
{ {
var payload = new T();
if (data.Size <= 0) return payload;
var buffer = new RagonBuffer(); var buffer = new RagonBuffer();
data.Write(buffer); data.Write(buffer);
var payload = new T();
payload.Deserialize(buffer); payload.Deserialize(buffer);
return payload; return payload;
} }
public T GetSpawnPayload<T>() where T : IRagonPayload, new() public void AttachPayload(RagonPayload payload)
{
_spawnPayload = payload;
}
public T GetAttachPayload<T>() where T : IRagonPayload, new()
{ {
return GetPayload<T>(_spawnPayload); return GetPayload<T>(_spawnPayload);
} }
public T GetDestroyPayload<T>() where T : IRagonPayload, new() public T GetDetachPayload<T>() where T : IRagonPayload, new()
{ {
return GetPayload<T>(_destroyPayload); return GetPayload<T>(_destroyPayload);
} }
@@ -105,6 +115,12 @@ namespace Ragon.Client
public void ReplicateEvent<TEvent>(TEvent evnt, RagonPlayer target, RagonReplicationMode replicationMode) public void ReplicateEvent<TEvent>(TEvent evnt, RagonPlayer target, RagonReplicationMode replicationMode)
where TEvent : IRagonEvent, new() where TEvent : IRagonEvent, new()
{ {
if (!IsAttached)
{
RagonLog.Error("Entity not attached");
return;
}
var evntId = _client.Event.GetEventCode(evnt); var evntId = _client.Event.GetEventCode(evnt);
var buffer = _client.Buffer; var buffer = _client.Buffer;
@@ -112,9 +128,9 @@ namespace Ragon.Client
buffer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT); buffer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT);
buffer.WriteUShort(Id); buffer.WriteUShort(Id);
buffer.WriteUShort(evntId); buffer.WriteUShort(evntId);
buffer.WriteByte((byte) replicationMode); buffer.WriteByte((byte)replicationMode);
buffer.WriteByte((byte) RagonTarget.Player); buffer.WriteByte((byte)RagonTarget.Player);
buffer.WriteUShort((ushort) target.PeerId); buffer.WriteUShort(target.PeerId);
evnt.Serialize(buffer); evnt.Serialize(buffer);
@@ -128,31 +144,34 @@ namespace Ragon.Client
RagonReplicationMode replicationMode = RagonReplicationMode.Server) RagonReplicationMode replicationMode = RagonReplicationMode.Server)
where TEvent : IRagonEvent, new() where TEvent : IRagonEvent, new()
{ {
if (!IsAttached)
{
RagonLog.Error("Entity not attached");
return;
}
var eventCode = _client.Event.GetEventCode(evnt);
if (target != RagonTarget.ExceptOwner) if (target != RagonTarget.ExceptOwner)
{ {
if (replicationMode == RagonReplicationMode.Local) if (replicationMode == RagonReplicationMode.Local)
{ {
var eventCode = _client.Event.GetEventCode(evnt);
_localEvents[eventCode].Invoke(_client.Room.Local, evnt); _localEvents[eventCode].Invoke(_client.Room.Local, evnt);
return; return;
} }
if (replicationMode == RagonReplicationMode.LocalAndServer) if (replicationMode == RagonReplicationMode.LocalAndServer)
{ {
var eventCode = _client.Event.GetEventCode(evnt);
_localEvents[eventCode].Invoke(_client.Room.Local, evnt); _localEvents[eventCode].Invoke(_client.Room.Local, evnt);
} }
} }
var evntId = _client.Event.GetEventCode(evnt);
var buffer = _client.Buffer; var buffer = _client.Buffer;
buffer.Clear(); buffer.Clear();
buffer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT); buffer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT);
buffer.WriteUShort(Id); buffer.WriteUShort(Id);
buffer.WriteUShort(evntId); buffer.WriteUShort(eventCode);
buffer.WriteByte((byte) replicationMode); buffer.WriteByte((byte)replicationMode);
buffer.WriteByte((byte) target); buffer.WriteByte((byte)target);
evnt.Serialize(buffer); evnt.Serialize(buffer);
@@ -167,11 +186,13 @@ namespace Ragon.Client
if (_events.ContainsKey(eventCode)) if (_events.ContainsKey(eventCode))
{ {
RagonLog.Warn($"Event already {eventCode} subscribed"); _events.Remove(eventCode);
return; _localEvents.Remove(eventCode);
RagonLog.Warn($"Event already {eventCode} subscribed, removed old one!");
} }
_localEvents.Add(eventCode, (player, eventData) => { callback.Invoke(player, (TEvent) eventData); }); _localEvents.Add(eventCode, (player, eventData) => { callback.Invoke(player, (TEvent)eventData); });
_events.Add(eventCode, (player, serializer) => _events.Add(eventCode, (player, serializer) =>
{ {
t.Deserialize(serializer); t.Deserialize(serializer);
@@ -196,8 +217,10 @@ namespace Ragon.Client
internal void Event(ushort eventCode, RagonPlayer caller, RagonBuffer buffer) internal void Event(ushort eventCode, RagonPlayer caller, RagonBuffer buffer)
{ {
if (_events.ContainsKey(eventCode)) if (_events.TryGetValue(eventCode, out var evnt))
_events[eventCode]?.Invoke(caller, buffer); evnt?.Invoke(caller, buffer);
else
RagonLog.Warn($"Handler event on entity {Id} with eventCode {eventCode} not defined");
} }
internal void TrackChangedProperty(RagonProperty property) internal void TrackChangedProperty(RagonProperty property)
@@ -210,7 +233,7 @@ namespace Ragon.Client
var prevOwner = Owner; var prevOwner = Owner;
Owner = player; Owner = player;
HasAuthority = player.PeerId == _client.Room.Local.PeerId; HasAuthority = player.IsLocal;
OwnershipChanged?.Invoke(prevOwner, player); OwnershipChanged?.Invoke(prevOwner, player);
} }
@@ -53,7 +53,7 @@ public sealed class RagonEntityState
{ {
var changed = buffer.ReadBool(); var changed = buffer.ReadBool();
if (changed) if (changed)
property.Deserialize(buffer); property.Read(buffer);
} }
} }
+5 -9
View File
@@ -19,10 +19,10 @@ using Ragon.Protocol;
namespace Ragon.Client; namespace Ragon.Client;
public struct RagonPayload public class RagonPayload
{ {
private uint[] _data = new uint[128]; private readonly uint[] _data = new uint[128];
private int _size = 0; private readonly int _size = 0;
public RagonPayload(int capacity) public RagonPayload(int capacity)
{ {
@@ -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()
+34 -13
View File
@@ -29,22 +29,25 @@ namespace Ragon.Client
public bool IsFixed => _fixed; public bool IsFixed => _fixed;
public int Size => _size; public int Size => _size;
private bool _fixed; private RagonBuffer _propertyBuffer;
private string _name;
protected bool _invokeLocal;
private RagonEntity _entity; private RagonEntity _entity;
private bool _dirty; private bool _dirty;
private int _size; private int _size;
private int _ticks; private int _ticks;
private int _priority; private int _priority;
private bool _fixed;
private string _name;
protected bool InvokeLocal;
protected RagonProperty(int priority, bool invokeLocal) protected RagonProperty(int priority, bool invokeLocal)
{ {
_size = 0; _size = 0;
_priority = priority; _priority = priority;
_fixed = false; _fixed = false;
_invokeLocal = invokeLocal; _propertyBuffer = new RagonBuffer();
InvokeLocal = invokeLocal;
} }
public void SetName(string name) public void SetName(string name)
@@ -60,7 +63,7 @@ namespace Ragon.Client
protected void InvokeChanged() protected void InvokeChanged()
{ {
if (!_invokeLocal) if (!InvokeLocal)
return; return;
Changed?.Invoke(); Changed?.Invoke();
@@ -97,20 +100,38 @@ namespace Ragon.Client
internal void Write(RagonBuffer buffer) internal void Write(RagonBuffer buffer)
{ {
_propertyBuffer.Clear();
if (_fixed) if (_fixed)
{ {
Serialize(buffer); Serialize(_propertyBuffer);
buffer.FromBuffer(_propertyBuffer, _size);
return; return;
} }
var sizeOffset = buffer.WriteOffset; Serialize(_propertyBuffer);
buffer.Write(0, 16);
var propOffset = buffer.WriteOffset;
Serialize(buffer); var propertySize = (ushort) _propertyBuffer.WriteOffset;
buffer.WriteUShort(propertySize);;
buffer.FromBuffer(_propertyBuffer, propertySize);
}
var propSize = (uint)(buffer.WriteOffset - propOffset); internal void Read(RagonBuffer buffer)
buffer.Write(propSize, 16, sizeOffset); {
_propertyBuffer.Clear();
if (_fixed)
{
buffer.ToBuffer(_propertyBuffer, _size);
Deserialize(_propertyBuffer);
return;
}
var propSize = buffer.ReadUShort();
buffer.ToBuffer(_propertyBuffer, propSize);
Deserialize(_propertyBuffer);
} }
public virtual void Serialize(RagonBuffer buffer) public virtual void Serialize(RagonBuffer buffer)
@@ -22,9 +22,13 @@ namespace Ragon.Client;
internal class AuthorizeSuccessHandler: Handler internal class AuthorizeSuccessHandler: Handler
{ {
private readonly RagonListenerList _listenerList; private readonly RagonListenerList _listenerList;
private readonly RagonClient _client;
public AuthorizeSuccessHandler(RagonListenerList listenerList) public AuthorizeSuccessHandler(
RagonClient client,
RagonListenerList listenerList)
{ {
_client = client;
_listenerList = listenerList; _listenerList = listenerList;
} }
@@ -34,6 +38,7 @@ internal class AuthorizeSuccessHandler: Handler
var playerName = buffer.ReadString(); var playerName = buffer.ReadString();
var playerPayload = buffer.ReadString(); var playerPayload = buffer.ReadString();
_client.SetStatus(RagonStatus.LOBBY);
_listenerList.OnAuthorizationSuccess(playerId, playerName, playerPayload); _listenerList.OnAuthorizationSuccess(playerId, playerName, playerPayload);
} }
} }
@@ -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)
@@ -51,8 +53,14 @@ internal class EntityCreateHandler : Handler
return; return;
} }
var hasAuthority = _playerCache.LocalPlayer.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);
} }
} }
@@ -49,7 +49,7 @@ internal class EntityEventHandler : Handler
return; return;
} }
if (player.IsMe && executionMode == RagonReplicationMode.LocalAndServer) if (player.IsLocal && executionMode == RagonReplicationMode.LocalAndServer)
return; return;
_entityCache.OnEvent(player, entityId, eventCode, buffer); _entityCache.OnEvent(player, entityId, eventCode, buffer);
@@ -19,13 +19,13 @@ using Ragon.Protocol;
namespace Ragon.Client; namespace Ragon.Client;
internal class OwnershipHandler: Handler internal class EntityOwnershipHandler: Handler
{ {
private readonly RagonListenerList _listenerList; private readonly RagonListenerList _listenerList;
private readonly RagonPlayerCache _playerCache; private readonly RagonPlayerCache _playerCache;
private readonly RagonEntityCache _entityCache; private readonly RagonEntityCache _entityCache;
public OwnershipHandler( public EntityOwnershipHandler(
RagonListenerList listenerList, RagonListenerList listenerList,
RagonPlayerCache playerCache, RagonPlayerCache playerCache,
RagonEntityCache entityCache) RagonEntityCache entityCache)
@@ -37,17 +37,16 @@ internal class OwnershipHandler: Handler
public void Handle(RagonBuffer buffer) public void Handle(RagonBuffer buffer)
{ {
var newOwnerId = buffer.ReadString(); var newOwnerId = buffer.ReadUShort();
var player = _playerCache.GetPlayerById(newOwnerId);
_playerCache.OnOwnershipChanged(newOwnerId);
_listenerList.OnOwnershipChanged(player);
var entities = buffer.ReadUShort(); var entities = buffer.ReadUShort();
var player = _playerCache.GetPlayerByPeer(newOwnerId);
for (var i = 0; i < entities; i++) for (var i = 0; i < entities; i++)
{ {
var entityId = buffer.ReadUShort(); var entityId = buffer.ReadUShort();
_entityCache.OnOwnershipChanged(player, entityId); _entityCache.OnOwnershipChanged(player, entityId);
RagonLog.Trace("Entity changed owner: " + entityId);
} }
} }
} }
@@ -43,7 +43,6 @@ internal class JoinSuccessHandler : Handler
private readonly RagonPlayerCache _playerCache; private readonly RagonPlayerCache _playerCache;
private readonly RagonEntityCache _entityCache; private readonly RagonEntityCache _entityCache;
private readonly RagonClient _client; private readonly RagonClient _client;
private readonly RagonBuffer _buffer;
public JoinSuccessHandler( public JoinSuccessHandler(
RagonClient client, RagonClient client,
@@ -53,7 +52,6 @@ internal class JoinSuccessHandler : Handler
RagonEntityCache entityCache RagonEntityCache entityCache
) )
{ {
_buffer = buffer;
_client = client; _client = client;
_listenerList = listenerList; _listenerList = listenerList;
_entityCache = entityCache; _entityCache = entityCache;
@@ -67,14 +65,15 @@ internal class JoinSuccessHandler : Handler
var ownerId = buffer.ReadString(); var ownerId = buffer.ReadString();
var min = buffer.ReadUShort(); var min = buffer.ReadUShort();
var max = buffer.ReadUShort(); var max = buffer.ReadUShort();
var map = buffer.ReadString(); var sceneName = buffer.ReadString();
var scene = new RagonScene(_client, _playerCache, _entityCache); var scene = new RagonScene(_client, _playerCache, _entityCache, sceneName);
var roomInfo = new RagonRoomInformation(roomId, localId, ownerId, min, max); var roomInfo = new RagonRoomInformation(roomId, localId, ownerId, min, max);
var room = new RagonRoom(_client, _entityCache, _playerCache, roomInfo, scene); var room = new RagonRoom(_client, _entityCache, _playerCache, roomInfo, scene);
_playerCache.SetOwnerAndLocal(ownerId, localId); _playerCache.SetOwnerAndLocal(ownerId, localId);
_client.AssignRoom(room); _client.AssignRoom(room);
_listenerList.OnLevel(map);
_listenerList.OnSceneRequest(sceneName);
} }
} }
@@ -38,7 +38,8 @@ internal class SceneLoadHandler: Handler
var room = _client.Room; var room = _client.Room;
room.Cleanup(); room.Cleanup();
room.Update(sceneName);
_listenerList.OnLevel(sceneName); _listenerList.OnSceneRequest(sceneName);
} }
} }
@@ -0,0 +1,46 @@
/*
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using Ragon.Protocol;
namespace Ragon.Client;
internal class OwnershipRoomHandler: Handler
{
private readonly RagonListenerList _listenerList;
private readonly RagonPlayerCache _playerCache;
private readonly RagonEntityCache _entityCache;
public OwnershipRoomHandler(
RagonListenerList listenerList,
RagonPlayerCache playerCache,
RagonEntityCache entityCache)
{
_listenerList = listenerList;
_playerCache = playerCache;
_entityCache = entityCache;
}
public void Handle(RagonBuffer buffer)
{
var newOwnerId = buffer.ReadUShort();
var player = _playerCache.GetPlayerByPeer(newOwnerId);
_playerCache.OnOwnershipChanged(newOwnerId);
_listenerList.OnOwnershipChanged(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);
} }
} }
} }
+44 -15
View File
@@ -15,25 +15,29 @@
*/ */
using System.Diagnostics;
using Ragon.Protocol; using Ragon.Protocol;
namespace Ragon.Client; 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;
@@ -50,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++)
@@ -59,16 +66,29 @@ 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);
var player = _playerCache.GetPlayerByPeer(ownerPeerId);
if (player == null)
{
RagonLog.Error($"Player not found with peerId: ${ownerPeerId}");
return;
}
var hasAuthority = _playerCache.Local.Id == player.Id;
var entity = _entityCache.TryGetEntity(0, entityType, 0, entityId, hasAuthority, out _);
if (payloadSize > 0)
{
var payload = new RagonPayload(payloadSize); var payload = new RagonPayload(payloadSize);
payload.Read(buffer); payload.Read(buffer);
var hasAuthority = _playerCache.LocalPlayer.Id == player.Id; entity.AttachPayload(payload);
var entity = _entityCache.OnCreate(0, entityType, 0, entityId, hasAuthority); }
_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();
@@ -80,18 +100,27 @@ 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 player = _playerCache.GetPlayerByPeer(ownerPeerId);
if (player == null)
{
RagonLog.Error($"Player not found with peerId: ${ownerPeerId}");
return;
}
var payload = new RagonPayload(payloadSize); var hasAuthority = _playerCache.Local.Id == player.Id;
payload.Read(buffer); var entity = _entityCache.TryGetEntity(0, entityType, staticId, entityId, hasAuthority, out _);
var hasAuthority = _playerCache.LocalPlayer.Id == player.Id;
var entity = _entityCache.OnCreate(0, entityType, staticId, entityId, hasAuthority);
entity.Read(buffer); entity.Read(buffer);
entity.Attach(_client, entityId, entityType, hasAuthority, player, payload); entity.Attach(_client, entityId, entityType, hasAuthority, player);
} }
if (_client.Status == RagonStatus.LOBBY)
{
_client.SetStatus(RagonStatus.ROOM);
_listenerList.OnJoined(); _listenerList.OnJoined();
} }
_listenerList.OnSceneLoaded();
}
} }
@@ -15,6 +15,8 @@
*/ */
using Ragon.Protocol;
namespace Ragon.Client; namespace Ragon.Client;
public interface INetworkConnection: IRagonConnection public interface INetworkConnection: IRagonConnection
@@ -23,7 +25,7 @@ public interface INetworkConnection: IRagonConnection
public INetworkChannel Unreliable { get; } public INetworkChannel Unreliable { get; }
public Action<byte[]> OnData { get; set; } public Action<byte[]> OnData { get; set; }
public Action OnConnected { get; set; } public Action OnConnected { get; set; }
public Action<DisconnectReason> OnDisconnected { get; set; } public Action<RagonDisconnect> OnDisconnected { get; set; }
public ulong BytesSent { get; } public ulong BytesSent { get; }
public ulong BytesReceived { get; } public ulong BytesReceived { get; }
public int Ping { get; } public int Ping { get; }
@@ -14,10 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
using Ragon.Protocol;
namespace Ragon.Client; namespace Ragon.Client;
public interface IRagonConnectionListener public interface IRagonConnectionListener
{ {
void OnConnected(RagonClient client); void OnConnected(RagonClient client);
void OnDisconnected(RagonClient client); void OnDisconnected(RagonClient client, RagonDisconnect reason);
} }
@@ -1,22 +0,0 @@
/*
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Ragon.Client;
public interface IRagonLevelListener
{
void OnLevel(RagonClient client, string sceneName);
}
@@ -22,10 +22,11 @@ namespace Ragon.Client
IRagonFailedListener, IRagonFailedListener,
IRagonJoinListener, IRagonJoinListener,
IRagonLeftListener, IRagonLeftListener,
IRagonLevelListener, IRagonSceneListener,
IRagonOwnershipChangedListener, IRagonOwnershipChangedListener,
IRagonPlayerJoinListener, IRagonPlayerJoinListener,
IRagonPlayerLeftListener IRagonPlayerLeftListener
{ {
} }
} }
@@ -16,8 +16,7 @@
namespace Ragon.Client; namespace Ragon.Client;
public enum DisconnectReason public interface IRagonSceneListener
{ {
MANUAL, void OnSceneLoaded(RagonClient client);
TIMEOUT,
} }
@@ -0,0 +1,6 @@
namespace Ragon.Client;
public interface IRagonSceneRequestListener
{
void OnRequestScene(RagonClient client, string sceneName);
}
+75 -50
View File
@@ -21,19 +21,19 @@ namespace Ragon.Client
public sealed class RagonClient public sealed class RagonClient
{ {
private readonly INetworkConnection _connection; private readonly INetworkConnection _connection;
private readonly IRagonEntityListener _entityListener; private readonly NetworkStatistics _stats;
private readonly IRagonSceneCollector _sceneCollector; private IRagonEntityListener _entityListener;
private IRagonSceneCollector _sceneCollector;
private Handler[] _handlers; private Handler[] _handlers;
private RagonBuffer _readBuffer; private RagonBuffer _readBuffer;
private RagonBuffer _writeBuffer; private RagonBuffer _writeBuffer;
private RagonRoom _room; private RagonRoom _room;
private RagonSession _session; private RagonSession _session;
private RagonListenerList _listenerList; private RagonListenerList listeners;
private RagonPlayerCache _playerCache; private RagonPlayerCache _playerCache;
private RagonEntityCache _entityCache; private RagonEntityCache _entityCache;
private RagonEventCache _eventCache; private RagonEventCache _eventCache;
private RagonStatus _status; private RagonStatus _status;
private NetworkStatistics _stats;
private float _replicationRate = 0; private float _replicationRate = 0;
private float _replicationTime = 0; private float _replicationTime = 0;
@@ -52,21 +52,15 @@ namespace Ragon.Client
#region PUBLIC #region PUBLIC
public RagonClient( public RagonClient(INetworkConnection connection, int rate)
INetworkConnection connection,
IRagonEntityListener entityListener,
IRagonSceneCollector sceneCollector,
int rate)
{ {
_listenerList = new RagonListenerList(this);
_entityListener = entityListener;
_sceneCollector = sceneCollector;
_connection = connection; _connection = connection;
_connection.OnData += OnData; _connection.OnData += OnData;
_connection.OnConnected += OnConnected; _connection.OnConnected += OnConnected;
_connection.OnDisconnected += OnDisconnected; _connection.OnDisconnected += OnDisconnected;
listeners = new RagonListenerList(this);
_replicationRate = (1000.0f / rate) / 1000.0f; _replicationRate = (1000.0f / rate) / 1000.0f;
_replicationTime = 0; _replicationTime = 0;
@@ -75,30 +69,54 @@ namespace Ragon.Client
_status = RagonStatus.DISCONNECTED; _status = RagonStatus.DISCONNECTED;
} }
public void Configure(IRagonSceneCollector sceneCollector)
{
_sceneCollector = sceneCollector;
}
public void Configure(IRagonEntityListener listener)
{
_entityListener = listener;
}
public void Connect(string address, ushort port, string protocol) public void Connect(string address, ushort port, string protocol)
{ {
if (_sceneCollector == null)
{
RagonLog.Error("Scene collector is not defined!");
return;
}
if (_entityListener == null)
{
RagonLog.Error("Entity Listener is not defined!");
return;
}
_writeBuffer = new RagonBuffer(); _writeBuffer = new RagonBuffer();
_readBuffer = new RagonBuffer(); _readBuffer = new RagonBuffer();
_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(this, listeners);
_handlers[(byte)RagonOperation.AUTHORIZED_FAILED] = new AuthorizeFailedHandler(_listenerList); _handlers[(byte)RagonOperation.AUTHORIZED_FAILED] = new AuthorizeFailedHandler(listeners);
_handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, _readBuffer, _listenerList, _playerCache, _entityCache); _handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, _readBuffer, listeners, _playerCache, _entityCache);
_handlers[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(_listenerList); _handlers[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(listeners);
_handlers[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, _listenerList, _entityCache); _handlers[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, listeners, _entityCache);
_handlers[(byte)RagonOperation.OWNERSHIP_CHANGED] = new OwnershipHandler(_listenerList, _playerCache, _entityCache); _handlers[(byte)RagonOperation.OWNERSHIP_ROOM_CHANGED] = new OwnershipRoomHandler(listeners, _playerCache, _entityCache);
_handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, _listenerList); _handlers[(byte)RagonOperation.OWNERSHIP_ENTITY_CHANGED] = new EntityOwnershipHandler(listeners, _playerCache, _entityCache);
_handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_entityCache, _playerCache, _listenerList); _handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, listeners);
_handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, _listenerList); _handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_entityCache, _playerCache, listeners);
_handlers[(byte)RagonOperation.CREATE_ENTITY] = new EntityCreateHandler(this, _playerCache, _entityCache); _handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, listeners);
_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, listeners, _entityCache, _playerCache, _entityListener);
var protocolRaw = RagonVersion.Parse(protocol); var protocolRaw = RagonVersion.Parse(protocol);
_connection.Connect(address, port, protocolRaw); _connection.Connect(address, port, protocolRaw);
@@ -110,7 +128,7 @@ namespace Ragon.Client
_room.Cleanup(); _room.Cleanup();
_connection.Disconnect(); _connection.Disconnect();
OnDisconnected(DisconnectReason.MANUAL); OnDisconnected(RagonDisconnect.MANUAL);
} }
public void Update(float dt) public void Update(float dt)
@@ -127,6 +145,7 @@ namespace Ragon.Client
_stats.Update(_connection.BytesSent, _connection.BytesReceived, _connection.Ping, dt); _stats.Update(_connection.BytesSent, _connection.BytesReceived, _connection.Ping, dt);
} }
listeners.Update();
_connection.Update(); _connection.Update();
} }
@@ -137,27 +156,29 @@ namespace Ragon.Client
_connection.Dispose(); _connection.Dispose();
} }
public void AddListener(IRagonListener listener) => _listenerList.Add(listener); public void AddListener(IRagonListener listener) => listeners.Add(listener);
public void AddListener(IRagonAuthorizationListener listener) => _listenerList.Add(listener); public void AddListener(IRagonAuthorizationListener listener) => listeners.Add(listener);
public void AddListener(IRagonConnectionListener listener) => _listenerList.Add(listener); public void AddListener(IRagonConnectionListener listener) => listeners.Add(listener);
public void AddListener(IRagonFailedListener listener) => _listenerList.Add(listener); public void AddListener(IRagonFailedListener listener) => listeners.Add(listener);
public void AddListener(IRagonJoinListener listener) => _listenerList.Add(listener); public void AddListener(IRagonJoinListener listener) => listeners.Add(listener);
public void AddListener(IRagonLeftListener listener) => _listenerList.Add(listener); public void AddListener(IRagonLeftListener listener) => listeners.Add(listener);
public void AddListener(IRagonLevelListener listener) => _listenerList.Add(listener); public void AddListener(IRagonOwnershipChangedListener listener) => listeners.Add(listener);
public void AddListener(IRagonOwnershipChangedListener listener) => _listenerList.Add(listener); public void AddListener(IRagonPlayerJoinListener listener) => listeners.Add(listener);
public void AddListener(IRagonPlayerJoinListener listener) => _listenerList.Add(listener); public void AddListener(IRagonPlayerLeftListener listener) => listeners.Add(listener);
public void AddListener(IRagonPlayerLeftListener listener) => _listenerList.Add(listener); public void AddListener(IRagonSceneListener listener) => listeners.Add(listener);
public void AddListener(IRagonSceneRequestListener listener) => listeners.Add(listener);
public void RemoveListener(IRagonListener listener) => _listenerList.Remove(listener); public void RemoveListener(IRagonListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonAuthorizationListener listener) => _listenerList.Remove(listener); public void RemoveListener(IRagonAuthorizationListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonConnectionListener listener) => _listenerList.Remove(listener); public void RemoveListener(IRagonConnectionListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonFailedListener listener) => _listenerList.Remove(listener); public void RemoveListener(IRagonFailedListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonJoinListener listener) => _listenerList.Remove(listener); public void RemoveListener(IRagonJoinListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonLeftListener listener) => _listenerList.Remove(listener); public void RemoveListener(IRagonLeftListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonLevelListener listener) => _listenerList.Remove(listener); public void RemoveListener(IRagonOwnershipChangedListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonOwnershipChangedListener listener) => _listenerList.Remove(listener); public void RemoveListener(IRagonPlayerJoinListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonPlayerJoinListener listener) => _listenerList.Remove(listener); public void RemoveListener(IRagonPlayerLeftListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonPlayerLeftListener listener) => _listenerList.Remove(listener); public void RemoveListener(IRagonSceneListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonSceneRequestListener listener) => listeners.Remove(listener);
#endregion #endregion
@@ -166,7 +187,11 @@ namespace Ragon.Client
internal void AssignRoom(RagonRoom room) internal void AssignRoom(RagonRoom room)
{ {
_room = room; _room = room;
_status = RagonStatus.ROOM; }
internal void SetStatus(RagonStatus status)
{
_status = status;
} }
#endregion #endregion
@@ -177,15 +202,15 @@ namespace Ragon.Client
{ {
RagonLog.Trace("Connected"); RagonLog.Trace("Connected");
_listenerList.OnConnected(); listeners.OnConnected();
_status = RagonStatus.CONNECTED; _status = RagonStatus.CONNECTED;
} }
private void OnDisconnected(DisconnectReason reason) private void OnDisconnected(RagonDisconnect reason)
{ {
RagonLog.Trace($"Disconnected: {reason}"); RagonLog.Trace($"Disconnected: {reason}");
_listenerList.OnDisconnected(); listeners.OnDisconnected(reason);
_status = RagonStatus.DISCONNECTED; _status = RagonStatus.DISCONNECTED;
} }
+56 -31
View File
@@ -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,35 +34,33 @@ 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;
} }
public RagonEntity FindById(ushort id) public bool TryGetEntity(ushort id, out RagonEntity entity)
{ {
return _entityMap[id]; return _entityMap.TryGetValue(id, out entity);
} }
public void Create(RagonEntity entity, IRagonPayload? spawnPayload) public void Create(RagonEntity entity, RagonPayload spawnPayload)
{ {
var attachId = (ushort) (_playerCache.LocalPlayer.PeerId + _localEntitiesCounter++) ; var attachId = (ushort)(_playerCache.Local.PeerId + _localEntitiesCounter++);
var buffer = _client.Buffer; var buffer = _client.Buffer;
buffer.Clear(); buffer.Clear();
buffer.WriteOperation(RagonOperation.CREATE_ENTITY); buffer.WriteOperation(RagonOperation.CREATE_ENTITY);
buffer.WriteUShort(attachId); buffer.WriteUShort(attachId);
buffer.WriteUShort(entity.Type); buffer.WriteUShort(entity.Type);
buffer.WriteByte((byte) entity.Authority); buffer.WriteByte((byte)entity.Authority);
entity.State.WriteInfo(buffer); entity.State.WriteInfo(buffer);
spawnPayload?.Serialize(buffer); spawnPayload?.Write(buffer);
_pendingEntities.Add(attachId, entity); _pendingEntities.Add(attachId, entity);
@@ -71,20 +68,34 @@ public sealed class RagonEntityCache
_client.Reliable.Send(sendData); _client.Reliable.Send(sendData);
} }
public void Destroy(RagonEntity entity, IRagonPayload? destroyPayload) public void Transfer(RagonEntity entity, RagonPlayer player)
{
var buffer = _client.Buffer;
buffer.Clear();
buffer.WriteOperation(RagonOperation.TRANSFER_ENTITY_OWNERSHIP);
buffer.WriteUShort(entity.Id);
buffer.WriteUShort(player.PeerId);
var sendData = buffer.ToArray();
_client.Reliable.Send(sendData);
}
public void Destroy(RagonEntity entity, RagonPayload destroyPayload)
{ {
if (!entity.IsAttached) if (!entity.IsAttached)
{ {
RagonLog.Warn("Can't destroy object, he is not created"); RagonLog.Warn("Can't destroy object, he is not created");
return; return;
} }
var buffer = _client.Buffer; var buffer = _client.Buffer;
buffer.Clear(); buffer.Clear();
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);
@@ -124,11 +135,11 @@ public sealed class RagonEntityCache
_sceneEntities.Clear(); _sceneEntities.Clear();
var entities = _sceneCollector.Collect(); var entities = _sceneCollector.Collect();
buffer.WriteUShort((ushort) entities.Length); buffer.WriteUShort((ushort)entities.Length);
foreach (var entity in entities) foreach (var entity in entities)
{ {
buffer.WriteUShort(entity.Type); buffer.WriteUShort(entity.Type);
buffer.WriteByte((byte) entity.Authority); buffer.WriteByte((byte)entity.Authority);
buffer.WriteUShort(entity.SceneId); buffer.WriteUShort(entity.SceneId);
entity.State.WriteInfo(buffer); entity.State.WriteInfo(buffer);
@@ -148,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);
@@ -156,32 +167,37 @@ 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); var entity = new RagonEntity(entityType, sceneId);
_entityMap.Add(entityId, entity); _entityMap.Add(entityId, entity);
@@ -189,20 +205,20 @@ public sealed class RagonEntityCache
if (hasAuthority) if (hasAuthority)
_entityList.Add(entity); _entityList.Add(entity);
_entityListener.OnEntityCreated(entity); hasCreated = true;
return entity; 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);
} }
} }
@@ -225,8 +241,17 @@ public sealed class RagonEntityCache
internal void OnOwnershipChanged(RagonPlayer player, ushort entityId) internal void OnOwnershipChanged(RagonPlayer player, ushort entityId)
{ {
if (_entityMap.TryGetValue(entityId, out var entity)) if (_entityMap.TryGetValue(entityId, out var entity))
entity.OnOwnershipChanged(player); {
if (player.IsLocal)
_entityList.Add(entity);
else else
_entityList.Remove(entity);
entity.OnOwnershipChanged(player);
}
else
{
RagonLog.Warn($"Entity {entityId} not found!"); RagonLog.Warn($"Entity {entityId} not found!");
} }
}
} }
+6 -2
View File
@@ -26,8 +26,12 @@ public class RagonEventCache
public ushort GetEventCode<TEvent>(TEvent _) where TEvent : IRagonEvent public ushort GetEventCode<TEvent>(TEvent _) where TEvent : IRagonEvent
{ {
var type = typeof(TEvent); var type = typeof(TEvent);
var evntCode = _eventsRegistryByType[type]; if (!_eventsRegistryByType.TryGetValue(type, out var eventCode))
return evntCode; {
RagonLog.Error($"Event with type {type} not registered");
return 0;
}
return eventCode;
} }
public void Register<T>() where T : IRagonEvent, new() public void Register<T>() where T : IRagonEvent, new()
+53 -20
View File
@@ -14,6 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
using Ragon.Protocol;
namespace Ragon.Client namespace Ragon.Client
{ {
internal class RagonListenerList internal class RagonListenerList
@@ -24,10 +26,12 @@ namespace Ragon.Client
private readonly List<IRagonFailedListener> _failedListeners = new(); private readonly List<IRagonFailedListener> _failedListeners = new();
private readonly List<IRagonJoinListener> _joinListeners = new(); private readonly List<IRagonJoinListener> _joinListeners = new();
private readonly List<IRagonLeftListener> _leftListeners = new(); private readonly List<IRagonLeftListener> _leftListeners = new();
private readonly List<IRagonLevelListener> _levelListeners = new(); private readonly List<IRagonSceneListener> _sceneListeners = new();
private readonly List<IRagonSceneRequestListener> _sceneRequestListeners = new();
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)
{ {
@@ -41,30 +45,47 @@ namespace Ragon.Client
_failedListeners.Add(listener); _failedListeners.Add(listener);
_joinListeners.Add(listener); _joinListeners.Add(listener);
_leftListeners.Add(listener); _leftListeners.Add(listener);
_levelListeners.Add(listener); _sceneListeners.Add(listener);
_ownershipChangedListeners.Add(listener); _ownershipChangedListeners.Add(listener);
_playerJoinListeners.Add(listener); _playerJoinListeners.Add(listener);
_playerLeftListeners.Add(listener); _playerLeftListeners.Add(listener);
} }
public void Remove(IRagonListener listener) public void Remove(IRagonListener listener)
{
_delayedActions.Add(() =>
{ {
_authorizationListeners.Remove(listener); _authorizationListeners.Remove(listener);
_connectionListeners.Remove(listener); _connectionListeners.Remove(listener);
_failedListeners.Remove(listener); _failedListeners.Remove(listener);
_joinListeners.Remove(listener); _joinListeners.Remove(listener);
_leftListeners.Remove(listener); _leftListeners.Remove(listener);
_levelListeners.Remove(listener); _sceneListeners.Remove(listener);
_ownershipChangedListeners.Remove(listener); _ownershipChangedListeners.Remove(listener);
_playerJoinListeners.Remove(listener); _playerJoinListeners.Remove(listener);
_playerLeftListeners.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);
} }
public void Add(IRagonSceneRequestListener listener)
{
_sceneRequestListeners.Add(listener);
}
public void Add(IRagonConnectionListener listener) public void Add(IRagonConnectionListener listener)
{ {
_connectionListeners.Add(listener); _connectionListeners.Add(listener);
@@ -85,9 +106,9 @@ namespace Ragon.Client
_leftListeners.Add(listener); _leftListeners.Add(listener);
} }
public void Add(IRagonLevelListener listener) public void Add(IRagonSceneListener listener)
{ {
_levelListeners.Add(listener); _sceneListeners.Add(listener);
} }
public void Add(IRagonOwnershipChangedListener listener) public void Add(IRagonOwnershipChangedListener listener)
@@ -105,49 +126,55 @@ namespace Ragon.Client
_playerLeftListeners.Add(listener); _playerLeftListeners.Add(listener);
} }
public void Remove(IRagonSceneRequestListener listener)
{
_delayedActions.Add(() => _sceneRequestListeners.Remove(listener));
}
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(IRagonSceneListener listener)
{ {
_levelListeners.Remove(listener); _delayedActions.Add(() => _sceneListeners.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)
@@ -192,10 +219,16 @@ namespace Ragon.Client
listener.OnPlayerJoined(_client, player); listener.OnPlayerJoined(_client, player);
} }
public void OnLevel(string sceneName) public void OnSceneLoaded()
{ {
foreach (var listener in _levelListeners) foreach (var listener in _sceneListeners)
listener.OnLevel(_client, sceneName); listener.OnSceneLoaded(_client);
}
public void OnSceneRequest(string sceneName)
{
foreach (var listener in _sceneRequestListeners)
listener.OnRequestScene(_client, sceneName);
} }
public void OnJoined() public void OnJoined()
@@ -210,10 +243,10 @@ namespace Ragon.Client
listener.OnConnected(_client); listener.OnConnected(_client);
} }
public void OnDisconnected() public void OnDisconnected(RagonDisconnect disconnect)
{ {
foreach (var listener in _connectionListeners) foreach (var listener in _connectionListeners)
listener.OnDisconnected(_client); listener.OnDisconnected(_client, disconnect);
} }
} }
} }
+3 -3
View File
@@ -23,13 +23,13 @@ namespace Ragon.Client
public string Name { get; set; } public string Name { get; set; }
public ushort PeerId { get; set; } public ushort PeerId { get; set; }
public bool IsRoomOwner { get; set; } public bool IsRoomOwner { get; set; }
public bool IsMe { get; set; } public bool IsLocal { get; set; }
public RagonPlayer(ushort peerId, string playerId, string name, bool isRoomOwner, bool isMe) public RagonPlayer(ushort peerId, string playerId, string name, bool isRoomOwner, bool isLocal)
{ {
PeerId = peerId; PeerId = peerId;
IsRoomOwner = isRoomOwner; IsRoomOwner = isRoomOwner;
IsMe = isMe; IsLocal = isLocal;
Name = name; Name = name;
Id = playerId; Id = playerId;
} }
+14 -10
View File
@@ -18,12 +18,13 @@ namespace Ragon.Client;
public sealed class RagonPlayerCache public sealed class RagonPlayerCache
{ {
private List<RagonPlayer> _players = new List<RagonPlayer>(); private readonly List<RagonPlayer> _players = new();
private Dictionary<string, RagonPlayer> _playersById = new(); private readonly Dictionary<string, RagonPlayer> _playersById = new();
private Dictionary<ushort, RagonPlayer> _playersByConnection = new(); private readonly Dictionary<ushort, RagonPlayer> _playersByConnection = new();
public IReadOnlyList<RagonPlayer> Players => _players;
public RagonPlayer Owner { get; private set; } public RagonPlayer Owner { get; private set; }
public RagonPlayer LocalPlayer { get; private set; } public RagonPlayer Local { get; private set; }
public bool IsRoomOwner => _ownerId == _localId; public bool IsRoomOwner => _ownerId == _localId;
public RagonPlayer? GetPlayerById(string playerId) => _playersById[playerId]; public RagonPlayer? GetPlayerById(string playerId) => _playersById[playerId];
@@ -50,8 +51,8 @@ public sealed class RagonPlayerCache
var player = new RagonPlayer(peerId, playerId, playerName, isOwner, isLocal); var player = new RagonPlayer(peerId, playerId, playerName, isOwner, isLocal);
if (player.IsMe) if (player.IsLocal)
LocalPlayer = player; Local = player;
if (player.IsRoomOwner) if (player.IsRoomOwner)
Owner = player; Owner = player;
@@ -63,20 +64,23 @@ 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);
} }
} }
public void OnOwnershipChanged(string playerId) public void OnOwnershipChanged(ushort playerPeerId)
{ {
foreach (var player in _players) foreach (var player in _players)
{ {
if (player.Id == playerId) if (player.PeerId == playerPeerId)
{
Owner = player; Owner = player;
player.IsRoomOwner = player.Id == playerId; Owner.IsRoomOwner = true;
}
} }
} }
+12 -4
View File
@@ -27,8 +27,10 @@ namespace Ragon.Client
public string Id => _information.RoomId; public string Id => _information.RoomId;
public int MinPlayers => _information.Min; public int MinPlayers => _information.Min;
public int MaxPlayers => _information.Max; public int MaxPlayers => _information.Max;
public string Scene => _scene.Name;
public RagonPlayer Local => _playerCache.LocalPlayer; public IReadOnlyList<RagonPlayer> Players => _playerCache.Players;
public RagonPlayer Local => _playerCache.Local;
public RagonPlayer Owner => _playerCache.Owner; public RagonPlayer Owner => _playerCache.Owner;
public RagonRoom(RagonClient client, public RagonRoom(RagonClient client,
@@ -50,13 +52,19 @@ namespace Ragon.Client
_playerCache.Cleanup(); _playerCache.Cleanup();
} }
public void LoadScene(string map) => _scene.Load(map); internal void Update(string sceneName)
{
_scene.Update(sceneName);
}
public void LoadScene(string sceneName) => _scene.Load(sceneName);
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 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);
} }
} }
+12 -3
View File
@@ -20,24 +20,33 @@ namespace Ragon.Client;
public class RagonScene public class RagonScene
{ {
public string Name { get; private set; }
private readonly RagonClient _client; private readonly RagonClient _client;
private readonly RagonEntityCache _entityCache; private readonly RagonEntityCache _entityCache;
private readonly RagonPlayerCache _playerCache; private readonly RagonPlayerCache _playerCache;
public RagonScene(RagonClient client, RagonPlayerCache playerCache, RagonEntityCache entityCache) public RagonScene(RagonClient client, RagonPlayerCache playerCache, RagonEntityCache entityCache, string sceneName)
{ {
Name = sceneName;
_client = client; _client = client;
_playerCache = playerCache; _playerCache = playerCache;
_entityCache = entityCache; _entityCache = entityCache;
} }
internal void Load(string map) internal void Update(string scene)
{
Name = scene;
}
internal void Load(string sceneName)
{ {
var buffer = _client.Buffer; var buffer = _client.Buffer;
buffer.Clear(); buffer.Clear();
buffer.WriteOperation(RagonOperation.LOAD_SCENE); buffer.WriteOperation(RagonOperation.LOAD_SCENE);
buffer.WriteString(map); buffer.WriteString(sceneName);
var sendData = buffer.ToArray(); var sendData = buffer.ToArray();
_client.Reliable.Send(sendData); _client.Reliable.Send(sendData);
+6 -6
View File
@@ -29,9 +29,9 @@ namespace Ragon.Client
_buffer = buffer; _buffer = buffer;
} }
public void CreateOrJoin(string map, int minPlayers, int maxPlayers) public void CreateOrJoin(string sceneName, int minPlayers, int maxPlayers)
{ {
var parameters = new RagonRoomParameters() {Map = map, Min = minPlayers, Max = maxPlayers}; var parameters = new RagonRoomParameters() {Scene = sceneName, Min = minPlayers, Max = maxPlayers};
CreateOrJoin(parameters); CreateOrJoin(parameters);
} }
@@ -46,14 +46,14 @@ namespace Ragon.Client
_client.Reliable.Send(sendData); _client.Reliable.Send(sendData);
} }
public void Create(string map, int minPlayers, int maxPlayers) public void Create(string sceneName, int minPlayers, int maxPlayers)
{ {
Create(null, new RagonRoomParameters() {Map = map, Min = minPlayers, Max = maxPlayers}); Create(null, new RagonRoomParameters() {Scene = sceneName, Min = minPlayers, Max = maxPlayers});
} }
public void Create(string roomId, string map, int minPlayers, int maxPlayers) public void Create(string roomId, string sceneNa, int minPlayers, int maxPlayers)
{ {
Create(roomId, new RagonRoomParameters() {Map = map, Min = minPlayers, Max = maxPlayers}); Create(roomId, new RagonRoomParameters() {Scene = sceneNa, Min = minPlayers, Max = maxPlayers});
} }
public void Create(string roomId, RagonRoomParameters parameters) public void Create(string roomId, RagonRoomParameters parameters)
@@ -0,0 +1,27 @@
using Ragon.Client.Compressor;
using Ragon.Protocol;
namespace Ragon.Client.Utils;
public static class CompressorExtension
{
public static float Read(this FloatCompressor compressor, RagonBuffer buffer)
{
return compressor.Decompress(buffer.Read(compressor.RequiredBits));
}
public static void Write(this FloatCompressor compressor, RagonBuffer buffer, float value)
{
buffer.Write(compressor.Compress(value), compressor.RequiredBits);
}
public static float Read(this IntCompressor compressor, RagonBuffer buffer)
{
return compressor.Decompress(buffer.Read(compressor.RequiredBits));
}
public static void Write(this IntCompressor compressor, RagonBuffer buffer, int value)
{
buffer.Write(compressor.Compress(value), compressor.RequiredBits);
}
}
+11 -3
View File
@@ -4,8 +4,16 @@
<ImplicitUsings>disable</ImplicitUsings> <ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable> <Nullable>disable</Nullable>
<LangVersion>8</LangVersion> <LangVersion>8</LangVersion>
<TargetFramework>netstandard2.1</TargetFramework>
<RootNamespace>Ragon.Common</RootNamespace> <RootNamespace>Ragon.Common</RootNamespace>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.2.4-rc</Version>
<Title>Ragon.Protocol</Title>
<Copyright>Eduard Kargin</Copyright>
<PackageProjectUrl>https://ragon-server.com</PackageProjectUrl>
<RepositoryUrl>https://github.com/edmand46/Ragon</RepositoryUrl>
<RepositoryType>Source</RepositoryType>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
@@ -16,8 +24,8 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>C:\Users\edmand46\RagonProjects\ragon-unity-sdk\Assets\Ragon-Unity-SDK\Runtime\Plugins</OutputPath> <OutputPath></OutputPath>
<DefineConstants>TRACE;NETSTACK_SPAN</DefineConstants> <DefineConstants>TRACE;</DefineConstants>
<DebugType>none</DebugType> <DebugType>none</DebugType>
</PropertyGroup> </PropertyGroup>
</Project> </Project>
+17 -4
View File
@@ -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,7 +320,9 @@ namespace Ragon.Protocol
_read += size; _read += size;
} }
public void WriteSpan(ref ReadOnlySpan<uint> data, int size)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteArray(uint[] data, int size)
{ {
var used = _write & 0x0000001F; var used = _write & 0x0000001F;
var index = _write >> 5; var index = _write >> 5;
@@ -332,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;
@@ -352,6 +353,18 @@ namespace Ragon.Protocol
_write = 0; _write = 0;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromBuffer(RagonBuffer buffer, int size)
{
WriteArray(buffer._buckets, size);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBuffer(RagonBuffer buffer, int size)
{
ReadArray(buffer._buckets, size);
}
public void FromArray(byte[] data) public void FromArray(byte[] data)
{ {
var length = data.Length; var length = data.Length;
@@ -0,0 +1,9 @@
namespace Ragon.Protocol
{
public enum RagonDisconnect
{
MANUAL,
TIMEOUT,
SERVER,
}
}
+4 -1
View File
@@ -26,7 +26,8 @@ namespace Ragon.Protocol
CREATE_ROOM, CREATE_ROOM,
JOIN_ROOM, JOIN_ROOM,
LEAVE_ROOM, LEAVE_ROOM,
OWNERSHIP_CHANGED, OWNERSHIP_ENTITY_CHANGED,
OWNERSHIP_ROOM_CHANGED,
JOIN_SUCCESS, JOIN_SUCCESS,
JOIN_FAILED, JOIN_FAILED,
LOAD_SCENE, LOAD_SCENE,
@@ -38,5 +39,7 @@ namespace Ragon.Protocol
SNAPSHOT, SNAPSHOT,
REPLICATE_ENTITY_STATE, REPLICATE_ENTITY_STATE,
REPLICATE_ENTITY_EVENT, REPLICATE_ENTITY_EVENT,
TRANSFER_ROOM_OWNERSHIP,
TRANSFER_ENTITY_OWNERSHIP,
} }
} }
@@ -19,20 +19,20 @@ namespace Ragon.Protocol
{ {
public class RagonRoomParameters: IRagonSerializable public class RagonRoomParameters: IRagonSerializable
{ {
public string Map { get; set; } public string Scene { get; set; }
public int Min { get; set; } public int Min { get; set; }
public int Max { get; set; } public int Max { get; set; }
public void Serialize(RagonBuffer buffer) public void Serialize(RagonBuffer buffer)
{ {
buffer.WriteString(Map); buffer.WriteString(Scene);
buffer.WriteInt(Min, 1, 32); buffer.WriteInt(Min, 1, 32);
buffer.WriteInt(Max, 1, 32); buffer.WriteInt(Max, 1, 32);
} }
public void Deserialize(RagonBuffer buffer) public void Deserialize(RagonBuffer buffer)
{ {
Map = buffer.ReadString(); Scene = buffer.ReadString();
Min = buffer.ReadInt(1, 32); Min = buffer.ReadInt(1, 32);
Max = buffer.ReadInt(1, 32); Max = buffer.ReadInt(1, 32);
} }
+1 -1
View File
@@ -21,7 +21,7 @@ namespace Ragon.Protocol
{ {
public static uint Parse(string version) public static uint Parse(string version)
{ {
var strings = version.Split("."); var strings = version.Split('.');
if (strings.Length < 3) if (strings.Length < 3)
return 0; return 0;
+1 -1
View File
@@ -24,7 +24,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ragon.Server.ENet\Ragon.Server.ENet.csproj" /> <ProjectReference Include="..\Ragon.Server.ENet\Ragon.Server.ENet.csproj" />
<ProjectReference Include="..\Ragon.Server.DotNetWebSockets\Ragon.Server.DotNetWebSockets.csproj" /> <ProjectReference Include="..\Ragon.Server.WebSocketServer\Ragon.Server.WebSocketServer.csproj" />
<ProjectReference Include="..\Ragon.Server\Ragon.Server.csproj" /> <ProjectReference Include="..\Ragon.Server\Ragon.Server.csproj" />
</ItemGroup> </ItemGroup>
+4 -4
View File
@@ -17,7 +17,7 @@
using NLog; using NLog;
using Ragon.Server; using Ragon.Server;
using Ragon.Server.ENet; using Ragon.Server.ENet;
using Ragon.Server.DotNetWebsockets; using Ragon.Server.WebSocketServer;
using Ragon.Server.IO; using Ragon.Server.IO;
using Ragon.Server.Plugin; using Ragon.Server.Plugin;
@@ -30,8 +30,8 @@ public class Relay
var logger = LogManager.GetLogger("Ragon.Relay"); var logger = LogManager.GetLogger("Ragon.Relay");
logger.Info("Relay Application"); logger.Info("Relay Application");
var configuration = Configuration.Load("relay.config.json"); var configuration = RagonServerConfiguration.Load("relay.config.json");
var serverType = Configuration.GetServerType(configuration.ServerType); var serverType = RagonServerConfiguration.GetServerType(configuration.ServerType);
INetworkServer networkServer = new ENetServer(); INetworkServer networkServer = new ENetServer();
IServerPlugin plugin = new RelayServerPlugin(); IServerPlugin plugin = new RelayServerPlugin();
@@ -41,7 +41,7 @@ public class Relay
networkServer = new ENetServer(); networkServer = new ENetServer();
break; break;
case ServerType.WEBSOCKET: case ServerType.WEBSOCKET:
networkServer = new DotNetWebSocketServer(); networkServer = new WebSocketServer();
break; break;
} }
+1
View File
@@ -9,6 +9,7 @@
"limitConnections": 4095, "limitConnections": 4095,
"limitPlayersPerRoom": 20, "limitPlayersPerRoom": 20,
"limitRooms": 200, "limitRooms": 200,
"limitBufferedEvents": 50,
"webHooks": "webHooks":
{ {
"room-created": "http://127.0.0.1:3000/service/create-room", "room-created": "http://127.0.0.1:3000/service/create-room",
+2 -2
View File
@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<RootNamespace>Ragon.ENet</RootNamespace> <RootNamespace>Ragon.ENet</RootNamespace>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ENet-CSharp" Version="2.4.8" /> <PackageReference Include="ENet-CSharp" Version="2.4.8" />
<PackageReference Include="NLog" Version="5.1.1" /> <PackageReference Include="NLog" Version="5.2.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<RootNamespace>Ragon.WebSockets</RootNamespace> <RootNamespace>Ragon.WebSockets</RootNamespace>
<TargetFrameworks>net7.0;net6.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NLog" Version="5.1.1" /> <PackageReference Include="NLog" Version="5.2.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -18,7 +18,7 @@ using NLog;
using System.Net.WebSockets; using System.Net.WebSockets;
using Ragon.Server.IO; using Ragon.Server.IO;
namespace Ragon.Server.DotNetWebsockets; namespace Ragon.Server.WebSocketServer;
public sealed class WebSocketConnection : INetworkConnection public sealed class WebSocketConnection : INetworkConnection
{ {
@@ -17,7 +17,7 @@
using System.Net.WebSockets; using System.Net.WebSockets;
using Ragon.Server.IO; using Ragon.Server.IO;
namespace Ragon.Server.DotNetWebsockets; namespace Ragon.Server.WebSocketServer;
public class WebSocketReliableChannel : INetworkChannel public class WebSocketReliableChannel : INetworkChannel
{ {
@@ -20,9 +20,9 @@ using NLog;
using Ragon.Protocol; using Ragon.Protocol;
using Ragon.Server.IO; using Ragon.Server.IO;
namespace Ragon.Server.DotNetWebsockets; namespace Ragon.Server.WebSocketServer;
public class DotNetWebSocketServer : INetworkServer public class WebSocketServer : INetworkServer
{ {
public Executor Executor => _executor; public Executor Executor => _executor;
@@ -35,7 +35,7 @@ public class DotNetWebSocketServer : INetworkServer
private List<WebSocketConnection> _activeConnections; private List<WebSocketConnection> _activeConnections;
private CancellationTokenSource _cancellationTokenSource; private CancellationTokenSource _cancellationTokenSource;
public DotNetWebSocketServer() public WebSocketServer()
{ {
_sequencer = new Stack<ushort>(); _sequencer = new Stack<ushort>();
_connections = Array.Empty<WebSocketConnection>(); _connections = Array.Empty<WebSocketConnection>();
+12 -3
View File
@@ -1,15 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<RootNamespace>Ragon.Core</RootNamespace> <RootNamespace>Ragon.Core</RootNamespace>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.2.4-rc</Version>
<Title>Ragon.Server</Title>
<Copyright>Eduard Kargin</Copyright>
<PackageProjectUrl>https://ragon-server.com</PackageProjectUrl>
<RepositoryUrl>https://github.com/edmand46/Ragon</RepositoryUrl>
<RepositoryType>Source</RepositoryType>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<LangVersion>10</LangVersion>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.2-beta2" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.1.1" /> <PackageReference Include="NLog" Version="5.2.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+9 -5
View File
@@ -20,7 +20,7 @@ using Ragon.Server.Room;
namespace Ragon.Server.Entity; namespace Ragon.Server.Entity;
public class RagonEntity: IRagonEntity public class RagonEntity : IRagonEntity
{ {
private static ushort _idGenerator = 100; private static ushort _idGenerator = 100;
public ushort Id { get; private set; } public ushort Id { get; private set; }
@@ -33,6 +33,7 @@ public class RagonEntity: IRagonEntity
public IRagonEntityState State => _state; public IRagonEntityState State => _state;
private readonly List<RagonEvent> _bufferedEvents; private readonly List<RagonEvent> _bufferedEvents;
private readonly int _limitBufferedEvents;
private readonly RagonEntityState _state; private readonly RagonEntityState _state;
public RagonEntity(RagonEntityParameters parameters) public RagonEntity(RagonEntityParameters parameters)
@@ -47,6 +48,7 @@ public class RagonEntity: IRagonEntity
_state = new RagonEntityState(this); _state = new RagonEntityState(this);
_bufferedEvents = new List<RagonEvent>(); _bufferedEvents = new List<RagonEvent>();
_limitBufferedEvents = parameters.BufferedEvents;
} }
public void Attach(RagonRoomPlayer owner) public void Attach(RagonRoomPlayer owner)
@@ -56,7 +58,6 @@ public class RagonEntity: IRagonEntity
public void Detach() public void Detach()
{ {
} }
public void RestoreBufferedEvents(RagonRoomPlayer roomPlayer, RagonBuffer writer) public void RestoreBufferedEvents(RagonRoomPlayer roomPlayer, RagonBuffer writer)
@@ -116,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);
@@ -159,11 +162,12 @@ public class RagonEntity: IRagonEntity
if (Authority == RagonAuthority.OwnerOnly && if (Authority == RagonAuthority.OwnerOnly &&
Owner.Connection.Id != caller.Connection.Id) Owner.Connection.Id != caller.Connection.Id)
{ {
Console.WriteLine($"Player have not enough authority for event with Id {evnt.EventCode}");
return; return;
} }
if (eventMode == RagonReplicationMode.Buffered && targetMode != RagonTarget.Owner) if (eventMode == RagonReplicationMode.Buffered &&
targetMode != RagonTarget.Owner &&
_bufferedEvents.Count < _limitBufferedEvents)
{ {
_bufferedEvents.Add(evnt); _bufferedEvents.Add(evnt);
} }
@@ -24,4 +24,5 @@ public ref struct RagonEntityParameters
public ushort StaticId; public ushort StaticId;
public ushort AttachId; public ushort AttachId;
public RagonAuthority Authority; public RagonAuthority Authority;
public int BufferedEvents;
} }
@@ -21,14 +21,12 @@ namespace Ragon.Server.Entity;
public class RagonEntityState: IRagonEntityState public class RagonEntityState: IRagonEntityState
{ {
private List<RagonProperty> _properties; private readonly List<RagonProperty> _properties;
private RagonEntity _entity; private readonly RagonEntity _entity;
private RagonBuffer _buffer;
public RagonEntityState(RagonEntity entity, int capacity = 10) public RagonEntityState(RagonEntity entity, int capacity = 10)
{ {
_entity = entity; _entity = entity;
_buffer = new RagonBuffer(8);
_properties = new List<RagonProperty>(capacity); _properties = new List<RagonProperty>(capacity);
} }
@@ -67,8 +65,7 @@ public class RagonEntityState: IRagonEntityState
{ {
foreach (var property in _properties) foreach (var property in _properties)
{ {
var hasPayloadOrFixed = property.IsFixed || property is { IsFixed: false, Size: > 0 }; if (property.HasData)
if (hasPayloadOrFixed)
{ {
buffer.WriteBool(true); buffer.WriteBool(true);
property.Write(buffer); property.Write(buffer);
+2 -4
View File
@@ -39,15 +39,13 @@ public class RagonEvent
public void Read(RagonBuffer buffer) public void Read(RagonBuffer buffer)
{ {
var readOnlySpan = _data.AsSpan();
_size = buffer.Capacity; _size = buffer.Capacity;
buffer.ReadSpan(ref readOnlySpan, _size); buffer.ReadArray(_data, _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);
} }
} }
+2 -8
View File
@@ -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);
} }
} }
+5 -5
View File
@@ -23,6 +23,7 @@ public class RagonProperty : RagonPayload
public int Size { get; set; } public int Size { get; set; }
public bool IsDirty { get; private set; } public bool IsDirty { get; private set; }
public bool IsFixed { get; private set; } public bool IsFixed { get; private set; }
public bool HasData { get; private set; }
private uint[] _data; private uint[] _data;
@@ -37,24 +38,23 @@ 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);
} }
HasData = true;
IsDirty = true; IsDirty = true;
} }
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()
@@ -28,16 +28,14 @@ public sealed class AuthorizationOperation: IRagonOperation
private Logger _logger = LogManager.GetCurrentClassLogger(); private Logger _logger = LogManager.GetCurrentClassLogger();
private readonly RagonWebHookPlugin _ragonWebHook; private readonly RagonWebHookPlugin _ragonWebHook;
private readonly RagonContextObserver _contextObserver; private readonly RagonContextObserver _contextObserver;
private readonly Configuration _configuration;
private readonly RagonBuffer _writer; private readonly RagonBuffer _writer;
public AuthorizationOperation(RagonWebHookPlugin ragonWebHook, public AuthorizationOperation(
RagonWebHookPlugin ragonWebHook,
RagonContextObserver contextObserver, RagonContextObserver contextObserver,
RagonBuffer writer, RagonBuffer writer)
Configuration configuration)
{ {
_ragonWebHook = ragonWebHook; _ragonWebHook = ragonWebHook;
_configuration = configuration;
_contextObserver = contextObserver; _contextObserver = contextObserver;
_writer = writer; _writer = writer;
} }
@@ -56,11 +54,12 @@ public sealed class AuthorizationOperation: IRagonOperation
return; return;
} }
var configuration = context.Configuration;
var key = reader.ReadString(); var key = reader.ReadString();
var name = reader.ReadString(); var name = reader.ReadString();
var payload = reader.ReadString(); var payload = reader.ReadString();
if (key == _configuration.ServerKey) if (key == configuration.ServerKey)
{ {
if (_ragonWebHook.RequestAuthorization(context, name, payload)) if (_ragonWebHook.RequestAuthorization(context, name, payload))
return; return;
@@ -38,7 +38,8 @@ public sealed class EntityCreateOperation : IRagonOperation
Type = entityType, Type = entityType,
Authority = eventAuthority, Authority = eventAuthority,
AttachId = attachId, AttachId = attachId,
StaticId = 0 StaticId = 0,
BufferedEvents = context.Configuration.LimitBufferedEvents,
}; };
var entity = new RagonEntity(entityParameters); var entity = new RagonEntity(entityParameters);
@@ -53,8 +54,8 @@ public sealed class EntityCreateOperation : IRagonOperation
if (reader.Capacity > 0) if (reader.Capacity > 0)
entity.Payload.Read(reader); entity.Payload.Read(reader);
var roomPlugin = room.Plugin; var plugin = room.Plugin;
if (!roomPlugin.OnEntityCreate(player, entity)) if (!plugin.OnEntityCreate(player, entity))
return; return;
entity.Attach(player); entity.Attach(player);
@@ -44,16 +44,15 @@ public sealed class EntityEventOperation : IRagonOperation
if (targetMode == RagonTarget.Player) if (targetMode == RagonTarget.Player)
targetPlayerPeerId = reader.ReadUShort(); targetPlayerPeerId = reader.ReadUShort();
var ragonEvent = new RagonEvent(player, eventId); var @event = new RagonEvent(player, eventId);
ragonEvent.Read(reader); @event.Read(reader);
if (targetMode == RagonTarget.Player && if (targetMode == RagonTarget.Player && room.Players.TryGetValue(targetPlayerPeerId, out var targetPlayer))
context.Room.Players.TryGetValue(targetPlayerPeerId, out var targetPlayer))
{ {
ent.ReplicateEvent(player, ragonEvent, eventMode, targetPlayer); ent.ReplicateEvent(player, @event, eventMode, targetPlayer);
return; return;
} }
ent.ReplicateEvent(player, ragonEvent, eventMode, targetMode); ent.ReplicateEvent(player, @event, eventMode, targetMode);
} }
} }
@@ -0,0 +1,53 @@
using NLog;
using Ragon.Protocol;
namespace Ragon.Server.Handler;
public sealed class EntityOwnershipOperation : IRagonOperation
{
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer)
{
var currentOwner = context.RoomPlayer;
var room = context.Room;
var entityId = reader.ReadUShort();
var playerPeerId = reader.ReadUShort();
if (!room.Entities.TryGetValue(entityId, out var entity))
{
_logger.Error($"Entity not found with id {entityId}");
return;
}
if (entity.Owner.Connection.Id != currentOwner.Connection.Id)
{
_logger.Error($"Player not owner of entity with id {entityId}");
return;
}
if (!room.Players.TryGetValue(playerPeerId, out var nextOwner))
{
_logger.Error($"Player not found with id {entityId}");
return;
}
currentOwner.Entities.Remove(entity);
nextOwner.Entities.Add(entity);
entity.Attach(nextOwner);
_logger.Trace($"Entity {entity.Id} next owner {nextOwner.Connection.Id}");
writer.Clear();
writer.WriteOperation(RagonOperation.OWNERSHIP_ENTITY_CHANGED);
writer.WriteUShort(playerPeerId);
writer.WriteUShort(1);
writer.WriteUShort(entity.Id);
var sendData = writer.ToArray();
foreach (var player in room.PlayerList)
player.Connection.Reliable.Send(sendData);
}
}
@@ -68,7 +68,7 @@ public sealed class RoomCreateOperation: IRagonOperation
var information = new RoomInformation() var information = new RoomInformation()
{ {
Map = _roomParameters.Map, Scene = _roomParameters.Scene,
Max = _roomParameters.Max, Max = _roomParameters.Max,
Min = _roomParameters.Min, Min = _roomParameters.Min,
}; };
@@ -87,7 +87,7 @@ public sealed class RoomCreateOperation: IRagonOperation
_ragonWebHookPlugin.RoomCreated(context, room, roomPlayer); _ragonWebHookPlugin.RoomCreated(context, room, roomPlayer);
_logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} create room {room.Id} with map {information.Map}"); _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} create room {room.Id} with scene {information.Scene}");
JoinSuccess(roomPlayer, room, writer); JoinSuccess(roomPlayer, room, writer);
@@ -103,7 +103,7 @@ public sealed class RoomCreateOperation: IRagonOperation
writer.WriteString(room.Owner.Id); writer.WriteString(room.Owner.Id);
writer.WriteUShort((ushort) room.PlayerMin); writer.WriteUShort((ushort) room.PlayerMin);
writer.WriteUShort((ushort) room.PlayerMax); writer.WriteUShort((ushort) room.PlayerMax);
writer.WriteString(room.Map); writer.WriteString(room.Scene);
var sendData = writer.ToArray(); var sendData = writer.ToArray();
player.Connection.Reliable.Send(sendData); player.Connection.Reliable.Send(sendData);
@@ -68,7 +68,7 @@ public sealed class RoomJoinOperation : IRagonOperation
writer.WriteString(room.Owner.Id); writer.WriteString(room.Owner.Id);
writer.WriteUShort((ushort) room.PlayerMin); writer.WriteUShort((ushort) room.PlayerMin);
writer.WriteUShort((ushort) room.PlayerMax); writer.WriteUShort((ushort) room.PlayerMax);
writer.WriteString(room.Map); writer.WriteString(room.Scene);
var sendData = writer.ToArray(); var sendData = writer.ToArray();
context.Connection.Reliable.Send(sendData); context.Connection.Reliable.Send(sendData);
@@ -49,7 +49,7 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation
_roomParameters.Deserialize(reader); _roomParameters.Deserialize(reader);
if (context.Lobby.FindRoomByMap(_roomParameters.Map, out var existsRoom)) if (context.Lobby.FindRoomByScene(_roomParameters.Scene, out var existsRoom))
{ {
var player = new RagonRoomPlayer(context.Connection, lobbyPlayer.Id, lobbyPlayer.Name); var player = new RagonRoomPlayer(context.Connection, lobbyPlayer.Id, lobbyPlayer.Name);
context.SetRoom(existsRoom, player); context.SetRoom(existsRoom, player);
@@ -62,7 +62,7 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation
{ {
var information = new RoomInformation() var information = new RoomInformation()
{ {
Map = _roomParameters.Map, Scene = _roomParameters.Scene,
Max = _roomParameters.Max, Max = _roomParameters.Max,
Min = _roomParameters.Min, Min = _roomParameters.Min,
}; };
@@ -77,7 +77,7 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation
context.Scheduler.Run(room); context.Scheduler.Run(room);
context.SetRoom(room, roomPlayer); context.SetRoom(room, roomPlayer);
_logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} create room {room.Id} with map {information.Map}"); _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} create room {room.Id} with scene {information.Scene}");
JoinSuccess(roomPlayer, room, writer); JoinSuccess(roomPlayer, room, writer);
} }
@@ -92,7 +92,7 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation
writer.WriteString(room.Owner.Id); writer.WriteString(room.Owner.Id);
writer.WriteUShort((ushort) room.PlayerMin); writer.WriteUShort((ushort) room.PlayerMin);
writer.WriteUShort((ushort) room.PlayerMax); writer.WriteUShort((ushort) room.PlayerMax);
writer.WriteString(room.Map); writer.WriteString(room.Scene);
var sendData = writer.ToArray(); var sendData = writer.ToArray();
player.Connection.Reliable.Send(sendData); player.Connection.Reliable.Send(sendData);
@@ -0,0 +1,14 @@
using NLog;
using Ragon.Protocol;
using Ragon.Server.Entity;
namespace Ragon.Server.Handler;
public sealed class RoomOwnershipOperation : IRagonOperation
{
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer)
{
}
}
@@ -33,7 +33,7 @@ public class SceneLoadOperation: IRagonOperation
if (roomOwner.Connection.Id != currentPlayer.Connection.Id) if (roomOwner.Connection.Id != currentPlayer.Connection.Id)
{ {
_logger.Warn("Only owner can change map!"); _logger.Warn("Only owner can change scene!");
return; return;
} }
@@ -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++)
{ {
@@ -57,6 +56,7 @@ public sealed class SceneLoadedOperation : IRagonOperation
Authority = eventAuthority, Authority = eventAuthority,
AttachId = 0, AttachId = 0,
StaticId = staticId, StaticId = staticId,
BufferedEvents = context.Configuration.LimitBufferedEvents,
}; };
var entity = new RagonEntity(entityParameters); var entity = new RagonEntity(entityParameters);
@@ -68,12 +68,12 @@ public sealed class SceneLoadedOperation : IRagonOperation
} }
var roomPlugin = room.Plugin; var roomPlugin = room.Plugin;
if (roomPlugin.OnEntityCreate(player, entity)) continue; if (!roomPlugin.OnEntityCreate(player, entity)) continue;
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);
+1 -1
View File
@@ -91,7 +91,7 @@ public class RagonHttpServer
} }
} }
public void Start(Configuration configuration) public void Start(RagonServerConfiguration configuration)
{ {
_cancellationTokenSource = new CancellationTokenSource(); _cancellationTokenSource = new CancellationTokenSource();
_logger.Info($"Listen at http://0.0.0.0:{configuration.HttpPort}/"); _logger.Info($"Listen at http://0.0.0.0:{configuration.HttpPort}/");
+1 -1
View File
@@ -22,7 +22,7 @@ namespace Ragon.Server.Lobby;
public interface IRagonLobby public interface IRagonLobby
{ {
public bool FindRoomById(string roomId, [MaybeNullWhen(false)] out RagonRoom room); public bool FindRoomById(string roomId, [MaybeNullWhen(false)] out RagonRoom room);
public bool FindRoomByMap(string map, [MaybeNullWhen(false)] out RagonRoom room); public bool FindRoomByScene(string sceneName, [MaybeNullWhen(false)] out RagonRoom room);
public void Persist(RagonRoom room); public void Persist(RagonRoom room);
public bool RemoveIfEmpty(RagonRoom room); public bool RemoveIfEmpty(RagonRoom room);
} }
@@ -40,11 +40,11 @@ public class LobbyInMemory : IRagonLobby
return false; return false;
} }
public bool FindRoomByMap(string map, [MaybeNullWhen(false)] out RagonRoom room) public bool FindRoomByScene(string sceneName, [MaybeNullWhen(false)] out RagonRoom room)
{ {
foreach (var existsRoom in _rooms) foreach (var existsRoom in _rooms)
{ {
if (existsRoom.Map == map && existsRoom.PlayerCount < existsRoom.PlayerMax) if (existsRoom.Scene == sceneName && existsRoom.PlayerCount < existsRoom.PlayerMax)
{ {
room = existsRoom; room = existsRoom;
return true; return true;
@@ -61,7 +61,7 @@ public class LobbyInMemory : IRagonLobby
_logger.Trace($"New room: {room.Id}"); _logger.Trace($"New room: {room.Id}");
foreach (var r in _rooms) foreach (var r in _rooms)
_logger.Trace($"Room: {r.Id} Map: {r.Map} Players: {r.Players.Count} Entities: {r.Entities.Count}"); _logger.Trace($"Room: {r.Id} Scene: {r.Scene} Players: {r.Players.Count} Entities: {r.Entities.Count}");
} }
public bool RemoveIfEmpty(RagonRoom room) public bool RemoveIfEmpty(RagonRoom room)
@@ -76,7 +76,7 @@ public class LobbyInMemory : IRagonLobby
} }
foreach (var r in _rooms) foreach (var r in _rooms)
_logger.Trace($"Room: {r.Id} Map: {r.Map} Players: {r.Players.Count} Entities: {r.Entities.Count}"); _logger.Trace($"Room: {r.Id} Scene: {r.Scene} Players: {r.Players.Count} Entities: {r.Entities.Count}");
return result; return result;
} }
@@ -31,7 +31,7 @@ public class RagonWebHookPlugin
private RagonServer _server; private RagonServer _server;
private HttpClient _httpClient; private HttpClient _httpClient;
public RagonWebHookPlugin(RagonServer server, Configuration configuration) public RagonWebHookPlugin(RagonServer server, RagonServerConfiguration configuration)
{ {
_webHooks = new Dictionary<string, string>(configuration.WebHooks); _webHooks = new Dictionary<string, string>(configuration.WebHooks);
_httpClient = new HttpClient(); _httpClient = new HttpClient();
+3 -1
View File
@@ -26,7 +26,7 @@ public class RagonContext
public ConnectionStatus ConnectionStatus { get; set; } public ConnectionStatus ConnectionStatus { get; set; }
public INetworkConnection Connection { get; } public INetworkConnection Connection { get; }
public IExecutor Executor { get; private set; } public IExecutor Executor { get; private set; }
public RagonServerConfiguration Configuration { get; private set; }
public IRagonLobby Lobby { get; private set; } public IRagonLobby Lobby { get; private set; }
public RagonLobbyPlayer? LobbyPlayer { get; private set; } public RagonLobbyPlayer? LobbyPlayer { get; private set; }
@@ -37,11 +37,13 @@ public class RagonContext
public RagonContext( public RagonContext(
INetworkConnection connection, INetworkConnection connection,
RagonServerConfiguration configuration,
IExecutor executor, IExecutor executor,
IRagonLobby lobby, IRagonLobby lobby,
RagonScheduler scheduler) RagonScheduler scheduler)
{ {
ConnectionStatus = ConnectionStatus.Unauthorized; ConnectionStatus = ConnectionStatus.Unauthorized;
Configuration = configuration;
Connection = connection; Connection = connection;
Executor = executor; Executor = executor;
Lobby = lobby; Lobby = lobby;
+6 -4
View File
@@ -36,7 +36,7 @@ public class RagonServer : IRagonServer, INetworkListener
private readonly IServerPlugin _serverPlugin; private readonly IServerPlugin _serverPlugin;
private readonly Thread _dedicatedThread; private readonly Thread _dedicatedThread;
private readonly Executor _executor; private readonly Executor _executor;
private readonly Configuration _configuration; private readonly RagonServerConfiguration _configuration;
private readonly RagonWebHookPlugin _webhooks; private readonly RagonWebHookPlugin _webhooks;
private readonly RagonHttpServer _httpServer; private readonly RagonHttpServer _httpServer;
private readonly RagonBuffer _reader; private readonly RagonBuffer _reader;
@@ -50,7 +50,7 @@ public class RagonServer : IRagonServer, INetworkListener
public RagonServer( public RagonServer(
INetworkServer server, INetworkServer server,
IServerPlugin plugin, IServerPlugin plugin,
Configuration configuration) RagonServerConfiguration configuration)
{ {
_server = server; _server = server;
_executor = _server.Executor; _executor = _server.Executor;
@@ -74,7 +74,7 @@ public class RagonServer : IRagonServer, INetworkListener
_serverPlugin.OnAttached(this); _serverPlugin.OnAttached(this);
_handlers = new IRagonOperation[byte.MaxValue]; _handlers = new IRagonOperation[byte.MaxValue];
_handlers[(byte) RagonOperation.AUTHORIZE] = new AuthorizationOperation(_webhooks, contextObserver, _writer, configuration); _handlers[(byte) RagonOperation.AUTHORIZE] = new AuthorizationOperation(_webhooks, contextObserver, _writer);
_handlers[(byte) RagonOperation.JOIN_OR_CREATE_ROOM] = new RoomJoinOrCreateOperation(plugin, _webhooks); _handlers[(byte) RagonOperation.JOIN_OR_CREATE_ROOM] = new RoomJoinOrCreateOperation(plugin, _webhooks);
_handlers[(byte) RagonOperation.CREATE_ROOM] = new RoomCreateOperation(plugin, _webhooks); _handlers[(byte) RagonOperation.CREATE_ROOM] = new RoomCreateOperation(plugin, _webhooks);
_handlers[(byte) RagonOperation.JOIN_ROOM] = new RoomJoinOperation(_webhooks); _handlers[(byte) RagonOperation.JOIN_ROOM] = new RoomJoinOperation(_webhooks);
@@ -85,6 +85,8 @@ public class RagonServer : IRagonServer, INetworkListener
_handlers[(byte) RagonOperation.REMOVE_ENTITY] = new EntityDestroyOperation(); _handlers[(byte) RagonOperation.REMOVE_ENTITY] = new EntityDestroyOperation();
_handlers[(byte) RagonOperation.REPLICATE_ENTITY_EVENT] = new EntityEventOperation(); _handlers[(byte) RagonOperation.REPLICATE_ENTITY_EVENT] = new EntityEventOperation();
_handlers[(byte) RagonOperation.REPLICATE_ENTITY_STATE] = new EntityStateOperation(); _handlers[(byte) RagonOperation.REPLICATE_ENTITY_STATE] = new EntityStateOperation();
_handlers[(byte) RagonOperation.TRANSFER_ROOM_OWNERSHIP] = new EntityOwnershipOperation();
_handlers[(byte) RagonOperation.TRANSFER_ENTITY_OWNERSHIP] = new EntityOwnershipOperation();
_logger.Trace($"Server Tick Rate: {_configuration.ServerTickRate}"); _logger.Trace($"Server Tick Rate: {_configuration.ServerTickRate}");
} }
@@ -134,7 +136,7 @@ public class RagonServer : IRagonServer, INetworkListener
public void OnConnected(INetworkConnection connection) public void OnConnected(INetworkConnection connection)
{ {
var context = new RagonContext(connection, _executor, _lobby, _scheduler); var context = new RagonContext(connection, _configuration, _executor, _lobby, _scheduler);
_logger.Trace($"Connected: {connection.Id}"); _logger.Trace($"Connected: {connection.Id}");
_contextsByConnection.Add(connection.Id, context); _contextsByConnection.Add(connection.Id, context);
@@ -31,7 +31,7 @@ public class WebHook
} }
[Serializable] [Serializable]
public struct Configuration public struct RagonServerConfiguration
{ {
public string ServerKey; public string ServerKey;
public string ServerType; public string ServerType;
@@ -43,22 +43,23 @@ public struct Configuration
public int LimitConnections; public int LimitConnections;
public int LimitPlayersPerRoom; public int LimitPlayersPerRoom;
public int LimitRooms; public int LimitRooms;
public int LimitBufferedEvents;
public Dictionary<string, string> WebHooks; public Dictionary<string, string> WebHooks;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly string ServerVersion = "1.2.0-rc"; private static readonly string ServerVersion = "1.2.9-rc";
private static Dictionary<string, ServerType> _serverTypes = new Dictionary<string, ServerType>() private static Dictionary<string, ServerType> _serverTypes = new Dictionary<string, ServerType>()
{ {
{"enet", Server.ServerType.ENET}, {"enet", Server.ServerType.ENET},
{"websocket", Server.ServerType.WEBSOCKET} {"websocket", Server.ServerType.WEBSOCKET}
}; };
public static Configuration Load(string filePath) public static RagonServerConfiguration Load(string filePath)
{ {
CopyrightInfo(); CopyrightInfo();
var data = File.ReadAllText(filePath); var data = File.ReadAllText(filePath);
var configuration = JsonConvert.DeserializeObject<Configuration>(data); var configuration = JsonConvert.DeserializeObject<RagonServerConfiguration>(data);
return configuration; return configuration;
} }
+6 -8
View File
@@ -25,7 +25,7 @@ namespace Ragon.Server.Room;
public class RagonRoom : IRagonRoom, IRagonAction public class RagonRoom : IRagonRoom, IRagonAction
{ {
public string Id { get; private set; } public string Id { get; private set; }
public string Map { get; private set; } public string Scene { get; private set; }
public int PlayerMax { get; private set; } public int PlayerMax { get; private set; }
public int PlayerMin { get; private set; } public int PlayerMin { get; private set; }
public int PlayerCount => WaitPlayersList.Count; public int PlayerCount => WaitPlayersList.Count;
@@ -49,7 +49,7 @@ public class RagonRoom : IRagonRoom, IRagonAction
public RagonRoom(string roomId, RoomInformation info, IRoomPlugin roomPlugin) public RagonRoom(string roomId, RoomInformation info, IRoomPlugin roomPlugin)
{ {
Id = roomId; Id = roomId;
Map = info.Map; Scene = info.Scene;
PlayerMax = info.Max; PlayerMax = info.Max;
PlayerMin = info.Min; PlayerMin = info.Min;
Plugin = roomPlugin; Plugin = roomPlugin;
@@ -153,8 +153,8 @@ public class RagonRoom : IRagonRoom, IRagonAction
var entitiesToUpdate = roomPlayer.Entities.StaticList; var entitiesToUpdate = roomPlayer.Entities.StaticList;
Writer.Clear(); Writer.Clear();
Writer.WriteOperation(RagonOperation.OWNERSHIP_CHANGED); Writer.WriteOperation(RagonOperation.OWNERSHIP_ENTITY_CHANGED);
Writer.WriteString(Owner.Id); Writer.WriteUShort(Owner.Connection.Id);
Writer.WriteUShort((ushort)entitiesToUpdate.Count); Writer.WriteUShort((ushort)entitiesToUpdate.Count);
foreach (var entity in entitiesToUpdate) foreach (var entity in entitiesToUpdate)
@@ -182,7 +182,7 @@ public class RagonRoom : IRagonRoom, IRagonAction
public void UpdateMap(string sceneName) public void UpdateMap(string sceneName)
{ {
Map = sceneName; Scene = sceneName;
DynamicEntitiesList.Clear(); DynamicEntitiesList.Clear();
StaticEntitiesList.Clear(); StaticEntitiesList.Clear();
@@ -218,9 +218,7 @@ public class RagonRoom : IRagonRoom, IRagonAction
public IRagonEntity? GetEntityById(ushort id) public IRagonEntity? GetEntityById(ushort id)
{ {
return Entities.TryGetValue(id, out var entity) ? return Entities.TryGetValue(id, out var entity) ? entity : null;
entity :
null;
} }
public IRagonEntity[] GetEntitiesOfPlayer(RagonRoomPlayer player) public IRagonEntity[] GetEntitiesOfPlayer(RagonRoomPlayer player)
@@ -18,7 +18,7 @@ namespace Ragon.Server;
public ref struct RoomInformation public ref struct RoomInformation
{ {
public string Map; public string Scene;
public int Min; public int Min;
public int Max; public int Max;
} }
+1 -1
View File
@@ -6,7 +6,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Protocol", "Ragon.Pro
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Server", "Ragon.Server\Ragon.Server.csproj", "{F4AA86B9-2486-4B53-BA77-43D958A2FDC3}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Server", "Ragon.Server\Ragon.Server.csproj", "{F4AA86B9-2486-4B53-BA77-43D958A2FDC3}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Server.DotNetWebSockets", "Ragon.Server.DotNetWebSockets\Ragon.Server.DotNetWebSockets.csproj", "{81050343-A9B8-487B-86C8-7A5B7DD9C39B}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Server.WebSocketServer", "Ragon.Server.WebSocketServer\Ragon.Server.WebSocketServer.csproj", "{81050343-A9B8-487B-86C8-7A5B7DD9C39B}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Server.ENet", "Ragon.Server.ENet\Ragon.Server.ENet.csproj", "{DD79AC4F-9E5C-4938-850E-805D537E68D0}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Server.ENet", "Ragon.Server.ENet\Ragon.Server.ENet.csproj", "{DD79AC4F-9E5C-4938-850E-805D537E68D0}"
EndProject EndProject