This commit is contained in:
2023-10-04 14:42:59 +03:00
parent 27db256902
commit 8788cb0fcf
57 changed files with 914 additions and 78 deletions
+1 -1
View File
@@ -12,7 +12,7 @@
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>none</DebugType>
<OutputPath>/Users/edmand46/RagonProjects/ragon-oss-examples/Assets/Ragon/Plugins/</OutputPath>
<OutputPath>/Users/edmand46/RagonProjects/ragon-oss-examples/Assets/Ragon/Plugins/netstandard2.0/</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
@@ -19,7 +19,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class AuthorizeFailedHandler: Handler
internal class AuthorizeFailedHandler: IHandler
{
private readonly RagonListenerList _listenerList;
public AuthorizeFailedHandler(RagonListenerList list)
@@ -19,7 +19,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class AuthorizeSuccessHandler: Handler
internal class AuthorizeSuccessHandler: IHandler
{
private readonly RagonListenerList _listenerList;
private readonly RagonClient _client;
@@ -18,7 +18,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class EntityCreateHandler : Handler
internal class EntityCreateHandler : IHandler
{
private readonly RagonClient _client;
private readonly RagonPlayerCache _playerCache;
@@ -18,19 +18,16 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class EntityEventHandler : Handler
internal class EntityEventHandler : IHandler
{
private readonly RagonClient _client;
private readonly RagonPlayerCache _playerCache;
private readonly RagonEntityCache _entityCache;
public EntityEventHandler(
RagonClient client,
RagonPlayerCache playerCache,
RagonEntityCache entityCache
)
{
_client = client;
_playerCache = playerCache;
_entityCache = entityCache;
}
@@ -19,7 +19,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class EntityOwnershipHandler: Handler
internal class EntityOwnershipHandler: IHandler
{
private readonly RagonListenerList _listenerList;
private readonly RagonPlayerCache _playerCache;
@@ -19,7 +19,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class EntityRemoveHandler: Handler
internal class EntityRemoveHandler: IHandler
{
private readonly RagonEntityCache _entityCache;
@@ -18,7 +18,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class StateEntityHandler: Handler
internal class StateEntityHandler: IHandler
{
private readonly RagonEntityCache _entityCache;
@@ -0,0 +1,53 @@
/*
* 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;
public class EventRoomHandler: IHandler
{
private readonly RagonClient _client;
private readonly RagonPlayerCache _playerCache;
public EventRoomHandler(
RagonClient client,
RagonPlayerCache playerCache
)
{
_client = client;
_playerCache = playerCache;
}
public void Handle(RagonBuffer buffer)
{
var eventCode = buffer.ReadUShort();
var peerId = buffer.ReadUShort();
var executionMode = (RagonReplicationMode)buffer.ReadByte();
var player = _playerCache.GetPlayerByPeer(peerId);
if (player == null)
{
RagonLog.Warn($"Player not found for event {eventCode}");
return;
}
if (player.IsLocal && executionMode == RagonReplicationMode.LocalAndServer)
return;
_client.Room.Event(eventCode, player, buffer);
}
}
@@ -19,7 +19,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
public interface Handler
public interface IHandler
{
public void Handle(RagonBuffer buffer);
}
@@ -19,7 +19,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class JoinFailedHandler: Handler
internal class JoinFailedHandler: IHandler
{
private readonly RagonListenerList _listenerList;
@@ -37,7 +37,7 @@ public struct RagonRoomInformation
public ushort Max { get; private set; }
}
internal class JoinSuccessHandler : Handler
internal class JoinSuccessHandler : IHandler
{
private readonly RagonListenerList _listenerList;
private readonly RagonPlayerCache _playerCache;
@@ -46,7 +46,6 @@ internal class JoinSuccessHandler : Handler
public JoinSuccessHandler(
RagonClient client,
RagonBuffer buffer,
RagonListenerList listenerList,
RagonPlayerCache playerCache,
RagonEntityCache entityCache
@@ -19,7 +19,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class LeaveRoomHandler : Handler
internal class LeaveRoomHandler : IHandler
{
private readonly RagonClient _client;
private readonly RagonListenerList _listenerList;
@@ -18,7 +18,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class SceneLoadHandler: Handler
internal class SceneLoadHandler: IHandler
{
private readonly RagonClient _client;
private readonly RagonListenerList _listenerList;
@@ -19,7 +19,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class OwnershipRoomHandler: Handler
internal class OwnershipRoomHandler: IHandler
{
private readonly RagonListenerList _listenerList;
private readonly RagonPlayerCache _playerCache;
@@ -19,7 +19,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class PlayerJoinHandler : Handler
internal class PlayerJoinHandler : IHandler
{
private RagonPlayerCache _playerCache;
private RagonListenerList _listenerList;
@@ -19,7 +19,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class PlayerLeftHandler : Handler
internal class PlayerLeftHandler : IHandler
{
private RagonPlayerCache _playerCache;
private RagonEntityCache _entityCache;
@@ -20,7 +20,7 @@ using Ragon.Protocol;
namespace Ragon.Client;
internal class SnapshotHandler : Handler
internal class SnapshotHandler : IHandler
{
private readonly IRagonEntityListener _entityListener;
private readonly RagonClient _client;
@@ -0,0 +1,21 @@
using Ragon.Protocol;
namespace Ragon.Client;
public class TimestampHandler: IHandler
{
private readonly RagonClient _client;
public TimestampHandler(RagonClient client)
{
_client = client;
}
public void Handle(RagonBuffer buffer)
{
var timestamp0 = buffer.Read(32);
var timestamp1 = buffer.Read(32);
var value = new DoubleToUInt { Int0 = timestamp0, Int1 = timestamp1 };
_client.SetTimestamp(value.Double);
}
}
+1 -1
View File
@@ -18,5 +18,5 @@ namespace Ragon.Client;
public interface IRagonConnection
{
public void Close();
}
+33 -7
View File
@@ -24,7 +24,7 @@ namespace Ragon.Client
private readonly NetworkStatistics _stats;
private IRagonEntityListener _entityListener;
private IRagonSceneCollector _sceneCollector;
private Handler[] _handlers;
private IHandler[] _handlers;
private RagonBuffer _readBuffer;
private RagonBuffer _writeBuffer;
private RagonRoom _room;
@@ -35,9 +35,11 @@ namespace Ragon.Client
private RagonEventCache _eventCache;
private RagonStatus _status;
private double _serverTimestamp;
private float _replicationRate = 0;
private float _replicationTime = 0;
public double ServerTimestamp => _serverTimestamp;
public IRagonConnection Connection => _connection;
public RagonStatus Status => _status;
public RagonSession Session => _session;
@@ -46,6 +48,7 @@ namespace Ragon.Client
public NetworkStatistics Statistics => _stats;
public RagonRoom Room => _room;
internal RagonBuffer Buffer => _writeBuffer;
internal INetworkChannel Reliable => _connection.Reliable;
internal INetworkChannel Unreliable => _connection.Unreliable;
@@ -96,15 +99,15 @@ namespace Ragon.Client
_writeBuffer = new RagonBuffer();
_readBuffer = new RagonBuffer();
_session = new RagonSession(this, _readBuffer);
_session = new RagonSession(this, _writeBuffer);
_playerCache = new RagonPlayerCache();
_entityCache = new RagonEntityCache(this, _playerCache, _sceneCollector);
_handlers = new Handler[byte.MaxValue];
_handlers = new IHandler[byte.MaxValue];
_handlers[(byte)RagonOperation.AUTHORIZED_SUCCESS] = new AuthorizeSuccessHandler(this, listeners);
_handlers[(byte)RagonOperation.AUTHORIZED_FAILED] = new AuthorizeFailedHandler(listeners);
_handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, _readBuffer, listeners, _playerCache, _entityCache);
_handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, listeners, _playerCache, _entityCache);
_handlers[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(listeners);
_handlers[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, listeners, _entityCache);
_handlers[(byte)RagonOperation.OWNERSHIP_ROOM_CHANGED] = new OwnershipRoomHandler(listeners, _playerCache, _entityCache);
@@ -115,8 +118,10 @@ namespace Ragon.Client
_handlers[(byte)RagonOperation.CREATE_ENTITY] = new EntityCreateHandler(this, _playerCache, _entityCache, _entityListener);
_handlers[(byte)RagonOperation.REMOVE_ENTITY] = new EntityRemoveHandler(_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(_playerCache, _entityCache);
_handlers[(byte)RagonOperation.SNAPSHOT] = new SnapshotHandler(this, listeners, _entityCache, _playerCache, _entityListener);
_handlers[(byte)RagonOperation.REPLICATE_RAW_DATA] = new EventRoomHandler(this, _playerCache);
_handlers[(byte)RagonOperation.TIMESTAMP_SYNCHRONIZATION] = new TimestampHandler(this);
var protocolRaw = RagonVersion.Parse(protocol);
_connection.Connect(address, port, protocolRaw);
@@ -138,8 +143,10 @@ namespace Ragon.Client
_replicationTime += dt;
if (_replicationTime >= _replicationRate)
{
_entityCache.WriteState(_readBuffer);
_replicationTime = 0;
_entityCache.WriteState(_writeBuffer);
SendTimestamp();
}
_stats.Update(_connection.BytesSent, _connection.BytesReceived, _connection.Ping, dt);
@@ -194,10 +201,29 @@ namespace Ragon.Client
_status = status;
}
internal void SetTimestamp(double time)
{
_serverTimestamp = time;
}
#endregion
#region PRIVATE
private void SendTimestamp()
{
var timestamp = RagonTime.CurrentTimestamp();
var value = new DoubleToUInt()
{
Double = timestamp,
};
_writeBuffer.Clear();
_writeBuffer.WriteOperation(RagonOperation.TIMESTAMP_SYNCHRONIZATION);
_writeBuffer.Write(value.Int0, 32);
_writeBuffer.Write(value.Int1, 32);
}
private void OnConnected()
{
RagonLog.Trace("Connected");
@@ -214,7 +240,7 @@ namespace Ragon.Client
_status = RagonStatus.DISCONNECTED;
}
public void OnData(byte[] data)
private void OnData(byte[] data)
{
_readBuffer.Clear();
_readBuffer.FromArray(data);
+40 -1
View File
@@ -14,16 +14,20 @@
* limitations under the License.
*/
using Ragon.Protocol;
namespace Ragon.Client
{
public class RagonRoom
{
private delegate void OnEventDelegate(RagonPlayer player, RagonBuffer serializer);
private RagonClient _client;
private RagonScene _scene;
private RagonEntityCache _entityCache;
private RagonPlayerCache _playerCache;
private RagonRoomInformation _information;
public string Id => _information.RoomId;
public int MinPlayers => _information.Min;
public int MaxPlayers => _information.Max;
@@ -33,6 +37,9 @@ namespace Ragon.Client
public RagonPlayer Local => _playerCache.Local;
public RagonPlayer Owner => _playerCache.Owner;
private readonly Dictionary<int, OnEventDelegate> _events = new Dictionary<int, OnEventDelegate>();
private readonly Dictionary<int, Action<RagonPlayer, IRagonEvent>> _localEvents = new Dictionary<int, Action<RagonPlayer, IRagonEvent>>();
public RagonRoom(RagonClient client,
RagonEntityCache entityCache,
RagonPlayerCache playerCache,
@@ -57,8 +64,40 @@ namespace Ragon.Client
_scene.Update(sceneName);
}
internal void Event(ushort eventCode, RagonPlayer caller, RagonBuffer buffer)
{
if (_events.TryGetValue(eventCode, out var evnt))
evnt?.Invoke(caller, buffer);
else
RagonLog.Warn($"Handler event on entity {Id} with eventCode {eventCode} not defined");
}
public void OnEvent<TEvent>(Action<RagonPlayer, TEvent> callback) where TEvent : IRagonEvent, new()
{
var t = new TEvent();
var eventCode = _client.Event.GetEventCode(t);
if (_events.ContainsKey(eventCode))
{
_events.Remove(eventCode);
_localEvents.Remove(eventCode);
RagonLog.Warn($"Event already {eventCode} subscribed, removed old one!");
}
_localEvents.Add(eventCode, (player, eventData) => { callback.Invoke(player, (TEvent)eventData); });
_events.Add(eventCode, (player, serializer) =>
{
t.Deserialize(serializer);
callback.Invoke(player, t);
});
}
public void LoadScene(string sceneName) => _scene.Load(sceneName);
public void SceneLoaded() => _scene.SceneLoaded();
public void ReplicateEvent<TEvent>(TEvent evnt, RagonTarget target, RagonReplicationMode mode) where TEvent : IRagonEvent, new() => _scene.ReplicateEvent(evnt, target, mode);
public void ReplicateEvent<TEvent>(TEvent evnt, RagonPlayer target, RagonReplicationMode mode) where TEvent : IRagonEvent, new() => _scene.ReplicateEvent(evnt, target, mode);
public void CreateEntity(RagonEntity entity) => CreateEntity(entity, null);
public void CreateEntity(RagonEntity entity, RagonPayload payload) => _entityCache.Create(entity, payload);
+35
View File
@@ -67,4 +67,39 @@ public class RagonScene
var sendData = buffer.ToArray();
_client.Reliable.Send(sendData);
}
internal void ReplicateEvent<TEvent>(TEvent evnt, RagonTarget target, RagonReplicationMode replicationMode)
where TEvent : IRagonEvent, new()
{
var evntId = _client.Event.GetEventCode(evnt);
var buffer = _client.Buffer;
buffer.Clear();
buffer.WriteOperation(RagonOperation.REPLICATE_RAW_DATA);
buffer.WriteUShort(evntId);
buffer.WriteByte((byte)replicationMode);
buffer.WriteByte((byte)target);
var sendData = buffer.ToArray();
_client.Reliable.Send(sendData);
}
internal void ReplicateEvent<TEvent>(TEvent evnt, RagonPlayer target, RagonReplicationMode replicationMode)
where TEvent : IRagonEvent, new()
{
var evntId = _client.Event.GetEventCode(evnt);
var buffer = _client.Buffer;
buffer.Clear();
buffer.WriteOperation(RagonOperation.REPLICATE_RAW_DATA);
buffer.WriteUShort(evntId);
buffer.WriteByte((byte)replicationMode);
buffer.WriteByte((byte)RagonTarget.Player);
buffer.WriteUShort(target.PeerId);
evnt.Serialize(buffer);
var sendData = buffer.ToArray();
_client.Reliable.Send(sendData);
}
}