Compare commits

...

10 Commits

47 changed files with 416 additions and 180 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
+3 -1
View File
@@ -1,5 +1,7 @@
using Ragon.Protocol;
namespace Ragon.Client.Simulation; namespace Ragon.Client.Simulation;
public class Game : IRagonListener public class Game : IRagonListener
@@ -63,7 +65,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");
} }
@@ -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];
+24 -8
View File
@@ -92,12 +92,12 @@ namespace Ragon.Client
return payload; return payload;
} }
public T GetSpawnPayload<T>() where T : IRagonPayload, new() 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 +105,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;
@@ -114,7 +120,7 @@ namespace Ragon.Client
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,6 +134,12 @@ 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;
}
if (target != RagonTarget.ExceptOwner) if (target != RagonTarget.ExceptOwner)
{ {
if (replicationMode == RagonReplicationMode.Local) if (replicationMode == RagonReplicationMode.Local)
@@ -167,8 +179,10 @@ 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); });
@@ -196,8 +210,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 +226,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);
} }
} }
+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)
@@ -51,7 +51,7 @@ 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.OnCreate(attachId, entityType, 0, entityId, hasAuthority);
entity.Attach(_client, entityId, entityType, hasAuthority, player, payload); entity.Attach(_client, entityId, entityType, hasAuthority, player, payload);
} }
@@ -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);
} }
} }
} }
@@ -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);
}
}
@@ -15,6 +15,7 @@
*/ */
using System.Diagnostics;
using Ragon.Protocol; using Ragon.Protocol;
namespace Ragon.Client; namespace Ragon.Client;
@@ -64,7 +65,7 @@ internal class SnapshotHandler : Handler
var payload = new RagonPayload(payloadSize); var payload = new RagonPayload(payloadSize);
payload.Read(buffer); payload.Read(buffer);
var hasAuthority = _playerCache.LocalPlayer.Id == player.Id; var hasAuthority = _playerCache.Local.Id == player.Id;
var entity = _entityCache.OnCreate(0, entityType, 0, entityId, hasAuthority); var entity = _entityCache.OnCreate(0, entityType, 0, entityId, hasAuthority);
entity.Read(buffer); entity.Read(buffer);
@@ -85,7 +86,7 @@ internal class SnapshotHandler : Handler
var payload = new RagonPayload(payloadSize); var payload = new RagonPayload(payloadSize);
payload.Read(buffer); payload.Read(buffer);
var hasAuthority = _playerCache.LocalPlayer.Id == player.Id; var hasAuthority = _playerCache.Local.Id == player.Id;
var entity = _entityCache.OnCreate(0, entityType, staticId, entityId, hasAuthority); var entity = _entityCache.OnCreate(0, entityType, staticId, entityId, hasAuthority);
entity.Read(buffer); entity.Read(buffer);
@@ -1,23 +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 enum DisconnectReason
{
MANUAL,
TIMEOUT,
}
@@ -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);
} }
+5 -4
View File
@@ -90,7 +90,8 @@ namespace Ragon.Client
_handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, _readBuffer, _listenerList, _playerCache, _entityCache); _handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, _readBuffer, _listenerList, _playerCache, _entityCache);
_handlers[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(_listenerList); _handlers[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(_listenerList);
_handlers[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, _listenerList, _entityCache); _handlers[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, _listenerList, _entityCache);
_handlers[(byte)RagonOperation.OWNERSHIP_CHANGED] = new OwnershipHandler(_listenerList, _playerCache, _entityCache); _handlers[(byte)RagonOperation.OWNERSHIP_ROOM_CHANGED] = new OwnershipRoomHandler(_listenerList, _playerCache, _entityCache);
_handlers[(byte)RagonOperation.OWNERSHIP_ENTITY_CHANGED] = new EntityOwnershipHandler(_listenerList, _playerCache, _entityCache);
_handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, _listenerList); _handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, _listenerList);
_handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_entityCache, _playerCache, _listenerList); _handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_entityCache, _playerCache, _listenerList);
_handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, _listenerList); _handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, _listenerList);
@@ -110,7 +111,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)
@@ -181,11 +182,11 @@ namespace Ragon.Client
_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(); _listenerList.OnDisconnected(reason);
_status = RagonStatus.DISCONNECTED; _status = RagonStatus.DISCONNECTED;
} }
+28 -5
View File
@@ -37,7 +37,7 @@ public sealed class RagonEntityCache
RagonPlayerCache playerCache, RagonPlayerCache playerCache,
IRagonEntityListener listener, IRagonEntityListener listener,
IRagonSceneCollector sceneCollector IRagonSceneCollector sceneCollector
) )
{ {
_client = client; _client = client;
_entityListener = listener; _entityListener = listener;
@@ -52,14 +52,14 @@ public sealed class RagonEntityCache
public void Create(RagonEntity entity, IRagonPayload? spawnPayload) public void Create(RagonEntity entity, IRagonPayload? 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);
@@ -71,6 +71,19 @@ public sealed class RagonEntityCache
_client.Reliable.Send(sendData); _client.Reliable.Send(sendData);
} }
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, IRagonPayload? destroyPayload) public void Destroy(RagonEntity entity, IRagonPayload? destroyPayload)
{ {
if (!entity.IsAttached) if (!entity.IsAttached)
@@ -78,6 +91,7 @@ public sealed class RagonEntityCache
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();
@@ -124,11 +138,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);
@@ -225,8 +239,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))
{
if (player.IsLocal)
_entityList.Add(entity);
else
_entityList.Remove(entity);
entity.OnOwnershipChanged(player); entity.OnOwnershipChanged(player);
}
else 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()
+4 -2
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
@@ -210,10 +212,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;
} }
+12 -9
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;
@@ -70,13 +71,15 @@ public sealed class RagonPlayerCache
} }
} }
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;
}
} }
} }
+3 -1
View File
@@ -28,7 +28,8 @@ namespace Ragon.Client
public int MinPlayers => _information.Min; public int MinPlayers => _information.Min;
public int MaxPlayers => _information.Max; public int MaxPlayers => _information.Max;
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,
@@ -55,6 +56,7 @@ namespace Ragon.Client
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, IRagonPayload? 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, IRagonPayload? payload) => _entityCache.Destroy(entityId, payload);
@@ -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);
}
}
+15
View File
@@ -321,6 +321,7 @@ namespace Ragon.Protocol
_read += size; _read += size;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteSpan(ref ReadOnlySpan<uint> data, int size) public void WriteSpan(ref ReadOnlySpan<uint> data, int size)
{ {
var used = _write & 0x0000001F; var used = _write & 0x0000001F;
@@ -352,6 +353,20 @@ namespace Ragon.Protocol
_write = 0; _write = 0;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromBuffer(RagonBuffer buffer, int size)
{
ReadOnlySpan<uint> data = buffer._buckets.AsSpan();
WriteSpan(ref data, size);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBuffer(RagonBuffer buffer, int size)
{
var data = buffer._buckets.AsSpan();
ReadSpan(ref data, 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,
} }
} }
+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",
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<RootNamespace>Ragon.WebSockets</RootNamespace> <RootNamespace>Ragon.WebSockets</RootNamespace>
@@ -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>();
+6 -3
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)
@@ -163,7 +164,9 @@ public class RagonEntity: IRagonEntity
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;
} }
@@ -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);
@@ -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);
}
}
@@ -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)
{
}
}
+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}/");
@@ -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,6 +43,7 @@ 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();
@@ -53,12 +54,12 @@ public struct Configuration
{"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;
} }
+2 -2
View File
@@ -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)
+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