wip
This commit is contained in:
+1
-5
@@ -6,10 +6,6 @@
|
|||||||
<RootNamespace>Game</RootNamespace>
|
<RootNamespace>Game</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Ragon\Ragon.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="NLog.config">
|
<None Update="NLog.config">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
@@ -20,7 +16,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Source\Events" />
|
<ProjectReference Include="..\Ragon\Ragon.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using NetStack.Serialization;
|
||||||
|
using Ragon.Common;
|
||||||
|
|
||||||
|
namespace Game.Source.Events;
|
||||||
|
|
||||||
|
public class TestEvent: IRagonSerializable
|
||||||
|
{
|
||||||
|
public string TestData;
|
||||||
|
|
||||||
|
public void Serialize(BitBuffer buffer)
|
||||||
|
{
|
||||||
|
buffer.AddString(TestData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(BitBuffer buffer)
|
||||||
|
{
|
||||||
|
TestData = buffer.ReadString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
using Ragon.Core;
|
using Ragon.Core;
|
||||||
|
|
||||||
namespace Game.Source
|
namespace Game.Source
|
||||||
@@ -7,6 +8,7 @@ namespace Game.Source
|
|||||||
public string PluginName { get; set; } = "ExamplePlugin";
|
public string PluginName { get; set; } = "ExamplePlugin";
|
||||||
public PluginBase CreatePlugin(string map)
|
public PluginBase CreatePlugin(string map)
|
||||||
{
|
{
|
||||||
|
|
||||||
return new ExamplePlugin();
|
return new ExamplePlugin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,59 @@
|
|||||||
using NLog;
|
using System.Runtime.InteropServices;
|
||||||
|
using Game.Source.Events;
|
||||||
|
using NLog;
|
||||||
using Ragon.Core;
|
using Ragon.Core;
|
||||||
|
|
||||||
namespace Game.Source
|
namespace Game.Source
|
||||||
{
|
{
|
||||||
public class ExamplePlugin: PluginBase
|
public class ExamplePlugin: PluginBase
|
||||||
{
|
{
|
||||||
private ILogger _logger = LogManager.GetCurrentClassLogger();
|
|
||||||
|
|
||||||
public override void OnStart()
|
public override void OnStart()
|
||||||
{
|
{
|
||||||
_logger.Info("Plugin started");
|
_logger.Info("Plugin started");
|
||||||
|
|
||||||
|
Subscribe<TestEvent>(123, OnTestEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnStop()
|
public override void OnStop()
|
||||||
{
|
{
|
||||||
_logger.Info("Plugin stopped");
|
_logger.Info("Plugin stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnTestEvent(Player player, TestEvent myEvent)
|
||||||
|
{
|
||||||
|
_logger.Info("Data " + myEvent.TestData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnPlayerJoined(Player player)
|
||||||
|
{
|
||||||
|
_logger.Info("Player joined " + player.PlayerName);
|
||||||
|
SendEvent(player, 123, new TestEvent() { TestData = "asdf"});
|
||||||
|
|
||||||
|
SendEvent(123, new TestEvent()
|
||||||
|
{
|
||||||
|
TestData = "Hello!",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnPlayerLeaved(Player player)
|
||||||
|
{
|
||||||
|
_logger.Info("Player leaved " + player.PlayerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnEntityCreated(Player creator, Entity entity)
|
||||||
|
{
|
||||||
|
// entity.
|
||||||
|
Subscribe<TestEvent>(entity, 123, OnEntityTestEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnEntityDestroyed(Player destoyer, Entity entity)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEntityTestEvent(Player arg1, int arg2, TestEvent arg3)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-21
@@ -3,25 +3,5 @@
|
|||||||
"server": {
|
"server": {
|
||||||
"port": 5000,
|
"port": 5000,
|
||||||
"skipTimeout": 60
|
"skipTimeout": 60
|
||||||
},
|
}
|
||||||
"blacklist": [
|
|
||||||
"пидор",
|
|
||||||
"сука",
|
|
||||||
"хуидор",
|
|
||||||
"хуй",
|
|
||||||
"Hitler",
|
|
||||||
"Гитлер",
|
|
||||||
"Гей",
|
|
||||||
"Админ",
|
|
||||||
"admin",
|
|
||||||
"падла",
|
|
||||||
"уебок",
|
|
||||||
"собака",
|
|
||||||
"пидорас",
|
|
||||||
"мразь",
|
|
||||||
"ебасос",
|
|
||||||
"еблан",
|
|
||||||
"ебучий",
|
|
||||||
"дрочь"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ using NetStack.Serialization;
|
|||||||
|
|
||||||
namespace Ragon.Common
|
namespace Ragon.Common
|
||||||
{
|
{
|
||||||
public interface IPacket
|
public interface IRagonSerializable
|
||||||
{
|
{
|
||||||
public void Serialize(BitBuffer buffer);
|
public void Serialize(BitBuffer buffer);
|
||||||
public void Deserialize(BitBuffer buffer);
|
public void Deserialize(BitBuffer buffer);
|
||||||
@@ -8,14 +8,14 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<OutputPath>/Users/edmand46/UnityProjects/Ragon-Unity-SDK/Assets/RagonSDK/netstandard2.1/</OutputPath>
|
<OutputPath>/Users/edmand46/UnityProjects/Ragon-Unity-SDK/Assets/RagonSDK/Plugins/</OutputPath>
|
||||||
<DebugSymbols>false</DebugSymbols>
|
<DebugSymbols>false</DebugSymbols>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<DefineConstants>TRACE;NETSTACK_SPAN</DefineConstants>
|
<DefineConstants>TRACE;NETSTACK_SPAN</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
<OutputPath>/Users/edmand46/UnityProjects/Ragon-Unity-SDK/Assets/RagonSDK/netstandard2.1/</OutputPath>
|
<OutputPath>/Users/edmand46/UnityProjects/Ragon-Unity-SDK/Assets/RagonSDK/Plugins/</OutputPath>
|
||||||
<DefineConstants>TRACE;NETSTACK_SPAN</DefineConstants>
|
<DefineConstants>TRACE;NETSTACK_SPAN</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace Ragon.Core
|
|||||||
private readonly Dictionary<RoomThread, int> _roomThreadCounter = new();
|
private readonly Dictionary<RoomThread, int> _roomThreadCounter = new();
|
||||||
private readonly Configuration _configuration;
|
private readonly Configuration _configuration;
|
||||||
private readonly ENetServer _socketServer;
|
private readonly ENetServer _socketServer;
|
||||||
|
private int _roomThreadBalancer = 0;
|
||||||
|
|
||||||
public Application(PluginFactory factory, Configuration configuration, int threadsCount)
|
public Application(PluginFactory factory, Configuration configuration, int threadsCount)
|
||||||
{
|
{
|
||||||
@@ -45,9 +46,13 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
if (evnt.Type == EventType.CONNECTED)
|
if (evnt.Type == EventType.CONNECTED)
|
||||||
{
|
{
|
||||||
var roomThread = _roomThreads.First();
|
if (_roomThreadBalancer >= _roomThreads.Count)
|
||||||
|
_roomThreadBalancer = 0;
|
||||||
|
|
||||||
|
var roomThread = _roomThreads[_roomThreadBalancer];
|
||||||
_roomThreadCounter[roomThread] += 1;
|
_roomThreadCounter[roomThread] += 1;
|
||||||
_socketByRoomThreads.Add(evnt.PeerId, roomThread);
|
_socketByRoomThreads.Add(evnt.PeerId, roomThread);
|
||||||
|
_roomThreadBalancer++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_socketByRoomThreads.TryGetValue(evnt.PeerId, out var existsRoomThread))
|
if (_socketByRoomThreads.TryGetValue(evnt.PeerId, out var existsRoomThread))
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Ragon.Core
|
|||||||
|
|
||||||
_logger.Info("==================================");
|
_logger.Info("==================================");
|
||||||
_logger.Info("= =");
|
_logger.Info("= =");
|
||||||
_logger.Info($"={"Yohoho Server".PadBoth(32)}=");
|
_logger.Info($"={"Ragon".PadBoth(32)}=");
|
||||||
_logger.Info("= =");
|
_logger.Info("= =");
|
||||||
_logger.Info("==================================");
|
_logger.Info("==================================");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,10 @@ namespace Ragon.Core
|
|||||||
private Address _address;
|
private Address _address;
|
||||||
private ENet.Event _netEvent;
|
private ENet.Event _netEvent;
|
||||||
private Peer[] _peers;
|
private Peer[] _peers;
|
||||||
|
|
||||||
private RingBuffer<Event> _receiveBuffer;
|
private RingBuffer<Event> _receiveBuffer;
|
||||||
private RingBuffer<Event> _sendBuffer;
|
private RingBuffer<Event> _sendBuffer;
|
||||||
|
|
||||||
public void WriteEvent(Event evnt) => _sendBuffer.Enqueue(evnt);
|
public void WriteEvent(Event evnt) => _sendBuffer.Enqueue(evnt);
|
||||||
public bool ReadEvent(out Event evnt) => _receiveBuffer.TryDequeue(out evnt);
|
public bool ReadEvent(out Event evnt) => _receiveBuffer.TryDequeue(out evnt);
|
||||||
|
|
||||||
@@ -131,7 +133,8 @@ namespace Ragon.Core
|
|||||||
_netEvent.Packet.CopyTo(data);
|
_netEvent.Packet.CopyTo(data);
|
||||||
_netEvent.Packet.Dispose();
|
_netEvent.Packet.Dispose();
|
||||||
|
|
||||||
var @event = new Event {PeerId = _netEvent.Peer.ID, Type = EventType.DATA, Data = data};
|
var @event = new Event {PeerId = _netEvent.Peer.ID, Type = EventType.DATA, Data = data };
|
||||||
|
|
||||||
_receiveBuffer.Enqueue(@event);
|
_receiveBuffer.Enqueue(@event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ public class Entity
|
|||||||
private static int _idGenerator = 0;
|
private static int _idGenerator = 0;
|
||||||
public int EntityId { get; private set; }
|
public int EntityId { get; private set; }
|
||||||
public uint OwnerId { get; private set; }
|
public uint OwnerId { get; private set; }
|
||||||
|
public ushort EntityType { get; private set; }
|
||||||
public byte[] State { get; set; }
|
public byte[] State { get; set; }
|
||||||
public Dictionary<int, byte[]> Properties { get; set; }
|
public Dictionary<int, byte[]> Properties { get; set; }
|
||||||
|
|
||||||
public Entity(uint ownerId)
|
public Entity(uint ownerId, ushort entityType)
|
||||||
{
|
{
|
||||||
OwnerId = ownerId;
|
OwnerId = ownerId;
|
||||||
|
EntityType = entityType;
|
||||||
EntityId = _idGenerator++;
|
EntityId = _idGenerator++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
public EventType Type;
|
public EventType Type;
|
||||||
public DeliveryType Delivery;
|
public DeliveryType Delivery;
|
||||||
public uint PeerId;
|
|
||||||
public byte[] Data;
|
public byte[] Data;
|
||||||
|
public uint PeerId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,26 +1,49 @@
|
|||||||
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using NetStack.Serialization;
|
using NetStack.Serialization;
|
||||||
|
using NLog;
|
||||||
using Ragon.Common;
|
using Ragon.Common;
|
||||||
|
|
||||||
namespace Ragon.Core
|
namespace Ragon.Core
|
||||||
{
|
{
|
||||||
public class PluginBase
|
public class PluginBase: IDisposable
|
||||||
{
|
{
|
||||||
private delegate void SubscribeDelegate(Player player, ref ReadOnlySpan<byte> data);
|
private delegate void SubscribeDelegate(Player player, ref ReadOnlySpan<byte> data);
|
||||||
private Dictionary<ushort, SubscribeDelegate> _subscribes = new();
|
private delegate void SubscribeEntityDelegate(Player player, Entity entity, ref ReadOnlySpan<byte> data);
|
||||||
private BitBuffer _buffer = new BitBuffer(1024);
|
|
||||||
|
private Dictionary<ushort, SubscribeDelegate> _globalEvents = new();
|
||||||
|
private Dictionary<int, Dictionary<ushort, SubscribeEntityDelegate>> _entityEvents = new();
|
||||||
|
private BitBuffer _buffer = new BitBuffer(8192);
|
||||||
|
|
||||||
protected Room Room { get; private set; }
|
protected Room Room { get; private set; }
|
||||||
|
protected ILogger _logger;
|
||||||
|
|
||||||
public void Attach(Room room) => Room = room;
|
public void Attach(Room room)
|
||||||
public void Detach() => _subscribes.Clear();
|
|
||||||
|
|
||||||
public void Subscribe<T>(ushort evntCode, Action<Player, T> action) where T: IPacket, new()
|
|
||||||
{
|
{
|
||||||
|
_logger = LogManager.GetLogger($"Plugin<{GetType().Name}>");
|
||||||
|
|
||||||
|
Room = room;
|
||||||
|
|
||||||
|
_globalEvents.Clear();
|
||||||
|
_entityEvents.Clear();
|
||||||
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_globalEvents.Clear();
|
||||||
|
_entityEvents.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Subscribe<T>(ushort evntCode, Action<Player, T> action) where T : IRagonSerializable, new()
|
||||||
|
{
|
||||||
|
if (_globalEvents.ContainsKey(evntCode))
|
||||||
|
{
|
||||||
|
_logger.Warn($"Event subscriber already added {evntCode}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var data = new T();
|
var data = new T();
|
||||||
_subscribes.Add(evntCode, (Player player, ref ReadOnlySpan<byte> raw) =>
|
_globalEvents.Add(evntCode, (Player player, ref ReadOnlySpan<byte> raw) =>
|
||||||
{
|
{
|
||||||
_buffer.Clear();
|
_buffer.Clear();
|
||||||
_buffer.FromSpan(ref raw, raw.Length);
|
_buffer.FromSpan(ref raw, raw.Length);
|
||||||
@@ -29,89 +52,146 @@ namespace Ragon.Core
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void Subscribe<T>(RagonOperation operation, Action<Player, Span<byte> action) where T: IPacket, new()
|
public void Subscribe<T>(Entity entity, ushort evntCode, Action<Player, int, T> action) where T : IRagonSerializable, new()
|
||||||
// {
|
|
||||||
// var data = new T();
|
|
||||||
// _subscribes.Add(evntCode, (Player player, ref ReadOnlySpan<byte> raw) =>
|
|
||||||
// {
|
|
||||||
// _buffer.Clear();
|
|
||||||
// _buffer.FromSpan(ref raw, raw.Length);
|
|
||||||
// data.Deserialize(_buffer);
|
|
||||||
// action.Invoke(player, data);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
public void UnsubscribeAll()
|
|
||||||
{
|
{
|
||||||
_subscribes.Clear();
|
if (_entityEvents.ContainsKey(evntCode))
|
||||||
|
{
|
||||||
|
_logger.Warn($"Event subscriber already added {evntCode}");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var data = new T();
|
||||||
|
_entityEvents[entity.EntityId][evntCode] = (Player player, Entity ent, ref ReadOnlySpan<byte> raw) =>
|
||||||
|
{
|
||||||
|
_buffer.Clear();
|
||||||
|
_buffer.FromSpan(ref raw, raw.Length);
|
||||||
|
data.Deserialize(_buffer);
|
||||||
|
action.Invoke(player, ent.EntityId, data);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsubscribeAll()
|
||||||
|
{
|
||||||
|
_globalEvents.Clear();
|
||||||
|
_entityEvents.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool InternalHandle(uint peerId, int entityId, ushort evntCode, ref ReadOnlySpan<byte> payload)
|
||||||
|
{
|
||||||
|
if (!_entityEvents.ContainsKey(entityId))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!_entityEvents[entityId].ContainsKey(evntCode))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var player = Room.GetPlayerById(peerId);
|
||||||
|
var entity = Room.GetEntityById(entityId);
|
||||||
|
_entityEvents[entityId][evntCode].Invoke(player, entity, ref payload);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool InternalHandle(uint peerId, ushort evntCode, ref ReadOnlySpan<byte> payload)
|
public bool InternalHandle(uint peerId, ushort evntCode, ref ReadOnlySpan<byte> payload)
|
||||||
{
|
{
|
||||||
if (_subscribes.ContainsKey(evntCode))
|
if (_globalEvents.ContainsKey(evntCode))
|
||||||
{
|
{
|
||||||
var player = Room.GetPlayerByPeerId(peerId);
|
var player = Room.GetPlayerById(peerId);
|
||||||
_subscribes[evntCode].Invoke(player, ref payload);
|
_globalEvents[evntCode].Invoke(player, ref payload);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Send(Player player, RagonOperation operation, IPacket payload)
|
public void SendEvent(Player player, uint eventCode, IRagonSerializable payload)
|
||||||
{
|
|
||||||
Send(player.PeerId, operation, payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Broadcast(Player[] players, RagonOperation operation, IPacket payload)
|
|
||||||
{
|
|
||||||
var ids = new uint[players.Length];
|
|
||||||
for (int i = 0; i < players.Length; i++)
|
|
||||||
ids[i] = players[i].PeerId;
|
|
||||||
|
|
||||||
Broadcast(ids, operation, payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Send(uint peerId, RagonOperation operation, IPacket payload)
|
|
||||||
{
|
|
||||||
_buffer.Clear();
|
|
||||||
|
|
||||||
payload.Serialize(_buffer);
|
|
||||||
|
|
||||||
Span<byte> data = stackalloc byte[_buffer.Length + 2];
|
|
||||||
Span<byte> bufferSpan = data.Slice(2, data.Length - 2);
|
|
||||||
|
|
||||||
_buffer.ToSpan(ref bufferSpan);
|
|
||||||
|
|
||||||
RagonHeader.WriteUShort((ushort) operation, ref data);
|
|
||||||
|
|
||||||
Room.Send(peerId, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Broadcast(uint[] peersIds, RagonOperation operation, IPacket payload)
|
|
||||||
{
|
{
|
||||||
_buffer.Clear();
|
_buffer.Clear();
|
||||||
payload.Serialize(_buffer);
|
payload.Serialize(_buffer);
|
||||||
|
|
||||||
Span<byte> data = stackalloc byte[_buffer.Length + 2];
|
var sendData = new byte[_buffer.Length + 2];
|
||||||
Span<byte> bufferSpan = data.Slice(2, data.Length - 2);
|
Span<byte> data = sendData.AsSpan();
|
||||||
|
Span<byte> operationData = data.Slice(0, 2);
|
||||||
|
Span<byte> payloadData = data.Slice(2, data.Length - 2);
|
||||||
|
|
||||||
_buffer.ToSpan(ref bufferSpan);
|
_buffer.ToSpan(ref payloadData);
|
||||||
|
|
||||||
RagonHeader.WriteUShort((ushort) operation, ref data);
|
RagonHeader.WriteUShort((ushort) RagonOperation.REPLICATE_EVENT, ref operationData);
|
||||||
|
|
||||||
Room.Broadcast(peersIds, data);
|
Room.Send(player.PeerId, sendData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SendEvent(ushort eventCode, IRagonSerializable payload)
|
||||||
|
{
|
||||||
|
_buffer.Clear();
|
||||||
|
payload.Serialize(_buffer);
|
||||||
|
|
||||||
|
var sendData = new byte[_buffer.Length + 4];
|
||||||
|
Span<byte> data = sendData.AsSpan();
|
||||||
|
Span<byte> operationData = data.Slice(0, 2);
|
||||||
|
Span<byte> eventCodeData = data.Slice(2, 2);
|
||||||
|
Span<byte> payloadData = data.Slice(4, _buffer.Length);
|
||||||
|
|
||||||
|
RagonHeader.WriteUShort((ushort) RagonOperation.REPLICATE_EVENT,ref operationData);
|
||||||
|
RagonHeader.WriteUShort( eventCode, ref eventCodeData);
|
||||||
|
|
||||||
|
_buffer.ToSpan(ref payloadData);
|
||||||
|
|
||||||
|
Room.Broadcast(sendData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendEntityEvent(Player player, Entity entity, IRagonSerializable payload)
|
||||||
|
{
|
||||||
|
_buffer.Clear();
|
||||||
|
payload.Serialize(_buffer);
|
||||||
|
|
||||||
|
var sendData = new byte[_buffer.Length + 6];
|
||||||
|
Span<byte> data = sendData.AsSpan();
|
||||||
|
Span<byte> operationData = data.Slice(0, 2);
|
||||||
|
Span<byte> entityData = data.Slice(2, 4);
|
||||||
|
|
||||||
|
RagonHeader.WriteUShort((ushort) RagonOperation.REPLICATE_EVENT, ref operationData);
|
||||||
|
RagonHeader.WriteInt(entity.EntityId, ref entityData);
|
||||||
|
|
||||||
|
Room.Send(player.PeerId, sendData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendEntityEvent(Entity entity, IRagonSerializable payload)
|
||||||
|
{
|
||||||
|
_buffer.Clear();
|
||||||
|
payload.Serialize(_buffer);
|
||||||
|
|
||||||
|
var sendData = new byte[_buffer.Length + 6];
|
||||||
|
Span<byte> data = sendData.AsSpan();
|
||||||
|
Span<byte> operationData = data.Slice(0, 2);
|
||||||
|
Span<byte> entityData = data.Slice(2, 4);
|
||||||
|
|
||||||
|
RagonHeader.WriteUShort((ushort) RagonOperation.REPLICATE_EVENT, ref operationData);
|
||||||
|
RagonHeader.WriteInt(entity.EntityId, ref entityData);
|
||||||
|
|
||||||
|
Room.Broadcast(sendData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#region VIRTUAL
|
#region VIRTUAL
|
||||||
|
|
||||||
public virtual void OnRoomJoined()
|
public virtual void OnPlayerJoined(Player player)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnPlayerLeaved(Player player)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnOwnerChanged(Player player)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public virtual void OnEntityCreated(Player creator, Entity entity)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OnRoomLeaved()
|
public virtual void OnEntityDestroyed(Player destoyer, Entity entity)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -124,9 +204,8 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OnTick(ulong ticks, float deltaTime)
|
public virtual void OnTick(float deltaTime)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
public interface PluginFactory
|
public interface PluginFactory
|
||||||
{
|
{
|
||||||
public string PluginName { get; set; }
|
|
||||||
public PluginBase CreatePlugin(string map);
|
public PluginBase CreatePlugin(string map);
|
||||||
public AuthorizationManager CreateManager(Configuration configuration);
|
public AuthorizationManager CreateManager(Configuration configuration);
|
||||||
}
|
}
|
||||||
|
|||||||
+93
-54
@@ -1,7 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using NetStack.Serialization;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Ragon.Common;
|
using Ragon.Common;
|
||||||
|
|
||||||
@@ -22,7 +25,6 @@ namespace Ragon.Core
|
|||||||
|
|
||||||
private readonly PluginBase _plugin;
|
private readonly PluginBase _plugin;
|
||||||
private readonly RoomThread _roomThread;
|
private readonly RoomThread _roomThread;
|
||||||
private ulong _ticks = 0;
|
|
||||||
|
|
||||||
// Cache
|
// Cache
|
||||||
private uint[] _readyPlayers = Array.Empty<uint>();
|
private uint[] _readyPlayers = Array.Empty<uint>();
|
||||||
@@ -39,7 +41,7 @@ namespace Ragon.Core
|
|||||||
PlayersMax = max;
|
PlayersMax = max;
|
||||||
Id = Guid.NewGuid().ToString();
|
Id = Guid.NewGuid().ToString();
|
||||||
|
|
||||||
_logger.Info("Room created");
|
_logger.Info($"Room created with plugin: {_plugin.GetType().Name}");
|
||||||
_plugin.Attach(this);
|
_plugin.Attach(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +67,9 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
var idRaw = Encoding.UTF8.GetBytes(Id).AsSpan();
|
var idRaw = Encoding.UTF8.GetBytes(Id).AsSpan();
|
||||||
|
|
||||||
Span<byte> data = stackalloc byte[idRaw.Length + 18];
|
var sendData = new byte[idRaw.Length + 18];
|
||||||
|
var data = sendData.AsSpan();
|
||||||
|
|
||||||
Span<byte> operationData = data.Slice(0, 2);
|
Span<byte> operationData = data.Slice(0, 2);
|
||||||
Span<byte> peerData = data.Slice(2, 4);
|
Span<byte> peerData = data.Slice(2, 4);
|
||||||
Span<byte> ownerData = data.Slice(4, 4);
|
Span<byte> ownerData = data.Slice(4, 4);
|
||||||
@@ -81,19 +85,21 @@ namespace Ragon.Core
|
|||||||
|
|
||||||
idRaw.CopyTo(idData);
|
idRaw.CopyTo(idData);
|
||||||
|
|
||||||
Send(peerId, data);
|
Send(peerId, sendData);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var sceneRawData = Encoding.UTF8.GetBytes(Map).AsSpan();
|
var sceneRawData = Encoding.UTF8.GetBytes(Map).AsSpan();
|
||||||
Span<byte> data = stackalloc byte[sceneRawData.Length + 2];
|
var sendData = new byte[sceneRawData.Length + 2];
|
||||||
|
var data = sendData.AsSpan();
|
||||||
|
|
||||||
Span<byte> operationData = data.Slice(0, 2);
|
Span<byte> operationData = data.Slice(0, 2);
|
||||||
Span<byte> sceneData = data.Slice(2, sceneRawData.Length);
|
Span<byte> sceneData = data.Slice(2, sceneRawData.Length);
|
||||||
|
|
||||||
RagonHeader.WriteUShort((ushort) RagonOperation.LOAD_SCENE, ref operationData);
|
RagonHeader.WriteUShort((ushort) RagonOperation.LOAD_SCENE, ref operationData);
|
||||||
sceneRawData.CopyTo(sceneData);
|
sceneRawData.CopyTo(sceneData);
|
||||||
|
|
||||||
Send(peerId, data, DeliveryType.Reliable);
|
Send(peerId, sendData, DeliveryType.Reliable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,15 +109,18 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
_allPlayers = _players.Select(p => p.Key).ToArray();
|
_allPlayers = _players.Select(p => p.Key).ToArray();
|
||||||
|
|
||||||
|
_plugin.OnPlayerLeaved(player);
|
||||||
|
|
||||||
foreach (var entityId in player.EntitiesIds)
|
foreach (var entityId in player.EntitiesIds)
|
||||||
{
|
{
|
||||||
Span<byte> entityData = stackalloc byte[6];
|
var sendData = new byte[6];
|
||||||
|
var entityData = sendData.AsSpan();
|
||||||
var operationData = entityData.Slice(0, 2);
|
var operationData = entityData.Slice(0, 2);
|
||||||
|
|
||||||
RagonHeader.WriteUShort((ushort) RagonOperation.DESTROY_ENTITY, ref operationData);
|
RagonHeader.WriteUShort((ushort) RagonOperation.DESTROY_ENTITY, ref operationData);
|
||||||
RagonHeader.WriteInt(entityId, ref entityData);
|
RagonHeader.WriteInt(entityId, ref entityData);
|
||||||
|
|
||||||
Broadcast(_allPlayers, entityData);
|
Broadcast(_allPlayers, sendData);
|
||||||
|
|
||||||
_entities.Remove(entityId);
|
_entities.Remove(entityId);
|
||||||
}
|
}
|
||||||
@@ -126,12 +135,14 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
var entityData = rawData.Slice(2, 4);
|
var entityData = rawData.Slice(2, 4);
|
||||||
var entityId = RagonHeader.ReadInt(ref entityData);
|
var entityId = RagonHeader.ReadInt(ref entityData);
|
||||||
if (_entities.TryGetValue(entityId, out var ent))
|
if (_entities.TryGetValue(entityId, out var ent) && ent.OwnerId == peerId)
|
||||||
{
|
{
|
||||||
ent.State = rawData.Slice(6, rawData.Length - 6).ToArray();
|
ent.State = rawData.Slice(6, rawData.Length - 6).ToArray();
|
||||||
|
|
||||||
Span<byte> data = stackalloc byte[rawData.Length];
|
var data = new byte[rawData.Length];
|
||||||
|
|
||||||
rawData.CopyTo(data);
|
rawData.CopyTo(data);
|
||||||
|
|
||||||
Broadcast(_readyPlayers, data);
|
Broadcast(_readyPlayers, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +152,7 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
var entityData = rawData.Slice(2, 4);
|
var entityData = rawData.Slice(2, 4);
|
||||||
var entityId = RagonHeader.ReadInt(ref entityData);
|
var entityId = RagonHeader.ReadInt(ref entityData);
|
||||||
if (_entities.TryGetValue(entityId, out var ent))
|
if (_entities.TryGetValue(entityId, out var ent) && ent.OwnerId == peerId)
|
||||||
{
|
{
|
||||||
var propertyData = rawData.Slice(6, 4);
|
var propertyData = rawData.Slice(6, 4);
|
||||||
var propertyId = RagonHeader.ReadInt(ref propertyData);
|
var propertyId = RagonHeader.ReadInt(ref propertyData);
|
||||||
@@ -153,24 +164,46 @@ namespace Ragon.Core
|
|||||||
else
|
else
|
||||||
props.Add(propertyId, payload);
|
props.Add(propertyId, payload);
|
||||||
|
|
||||||
// Span<byte> sendData = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(rawData), rawData.Length);
|
var sendData = new byte[rawData.Length];
|
||||||
|
|
||||||
Span<byte> sendData = stackalloc byte[rawData.Length];
|
|
||||||
rawData.CopyTo(sendData);
|
rawData.CopyTo(sendData);
|
||||||
|
|
||||||
Broadcast(_readyPlayers, sendData, DeliveryType.Reliable);
|
Broadcast(_readyPlayers, sendData, DeliveryType.Reliable);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RagonOperation.REPLICATE_EVENT:
|
|
||||||
case RagonOperation.REPLICATE_ENTITY_EVENT:
|
case RagonOperation.REPLICATE_ENTITY_EVENT:
|
||||||
|
{
|
||||||
|
var evntCodeData = rawData.Slice(2, 2);
|
||||||
|
var entityIdData = rawData.Slice(4, 4);
|
||||||
|
var evntId = RagonHeader.ReadUShort(ref evntCodeData);
|
||||||
|
var entityId = RagonHeader.ReadInt(ref entityIdData);
|
||||||
|
|
||||||
|
if (_entities[entityId].OwnerId != peerId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var payload = rawData.Slice(8, rawData.Length - 8);
|
||||||
|
if (_plugin.InternalHandle(peerId, entityId, evntId, ref payload))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var data = new byte[rawData.Length];
|
||||||
|
|
||||||
|
rawData.CopyTo(data);
|
||||||
|
|
||||||
|
Broadcast(_readyPlayers, data, DeliveryType.Reliable);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RagonOperation.REPLICATE_EVENT:
|
||||||
{
|
{
|
||||||
var evntCodeData = rawData.Slice(2, 2);
|
var evntCodeData = rawData.Slice(2, 2);
|
||||||
var evntId = RagonHeader.ReadUShort(ref evntCodeData);
|
var evntId = RagonHeader.ReadUShort(ref evntCodeData);
|
||||||
|
|
||||||
if (_plugin.InternalHandle(peerId, evntId, ref rawData)) return;
|
var payload = rawData.Slice(4, rawData.Length - 4);
|
||||||
|
if (_plugin.InternalHandle(peerId, evntId, ref payload))
|
||||||
|
return;
|
||||||
|
|
||||||
Span<byte> data = stackalloc byte[rawData.Length];
|
var data = new byte[rawData.Length];
|
||||||
|
|
||||||
rawData.CopyTo(data);
|
rawData.CopyTo(data);
|
||||||
|
|
||||||
@@ -179,9 +212,12 @@ namespace Ragon.Core
|
|||||||
}
|
}
|
||||||
case RagonOperation.CREATE_ENTITY:
|
case RagonOperation.CREATE_ENTITY:
|
||||||
{
|
{
|
||||||
var entity = new Entity(peerId);
|
var typeData = rawData.Slice(2, 2);
|
||||||
var entityPayload = rawData.Slice(2, rawData.Length - 2);
|
var entityPayloadData = rawData.Slice(4, rawData.Length - 4);
|
||||||
entity.State = entityPayload.ToArray();
|
|
||||||
|
var entityType = RagonHeader.ReadUShort(ref typeData);
|
||||||
|
var entity = new Entity(peerId, entityType);
|
||||||
|
entity.State = entityPayloadData.ToArray();
|
||||||
entity.Properties = new Dictionary<int, byte[]>();
|
entity.Properties = new Dictionary<int, byte[]>();
|
||||||
|
|
||||||
var player = _players[peerId];
|
var player = _players[peerId];
|
||||||
@@ -191,15 +227,20 @@ namespace Ragon.Core
|
|||||||
_entities.Add(entity.EntityId, entity);
|
_entities.Add(entity.EntityId, entity);
|
||||||
_entitiesAll = _entities.Values.ToArray();
|
_entitiesAll = _entities.Values.ToArray();
|
||||||
|
|
||||||
Span<byte> data = stackalloc byte[entityPayload.Length + 10];
|
_plugin.OnEntityCreated(player, entity);
|
||||||
var operationData = data.Slice(0, 2);
|
|
||||||
var entityData = data.Slice(2, 4);
|
|
||||||
var peerData = data.Slice(6, 4);
|
|
||||||
var payload = data.Slice(10, entityPayload.Length);
|
|
||||||
|
|
||||||
entityPayload.CopyTo(payload);
|
var data = new byte[entityPayloadData.Length + 12];
|
||||||
|
var sendData = data.AsSpan();
|
||||||
|
var operationData = sendData.Slice(0, 2);
|
||||||
|
var entityTypeData = sendData.Slice(2, 4);
|
||||||
|
var entityData = sendData.Slice(4, 4);
|
||||||
|
var peerData = sendData.Slice(8, 4);
|
||||||
|
var payload = sendData.Slice(12, entityPayloadData.Length);
|
||||||
|
|
||||||
|
entityPayloadData.CopyTo(payload);
|
||||||
|
|
||||||
RagonHeader.WriteUShort((ushort) RagonOperation.CREATE_ENTITY, ref operationData);
|
RagonHeader.WriteUShort((ushort) RagonOperation.CREATE_ENTITY, ref operationData);
|
||||||
|
RagonHeader.WriteUShort(entityType, ref entityTypeData);
|
||||||
RagonHeader.WriteInt(entity.EntityId, ref entityData);
|
RagonHeader.WriteInt(entity.EntityId, ref entityData);
|
||||||
RagonHeader.WriteInt((int) peerId, ref peerData);
|
RagonHeader.WriteInt((int) peerId, ref peerData);
|
||||||
|
|
||||||
@@ -222,9 +263,13 @@ namespace Ragon.Core
|
|||||||
_entities.Remove(entityId);
|
_entities.Remove(entityId);
|
||||||
_entitiesAll = _entities.Values.ToArray();
|
_entitiesAll = _entities.Values.ToArray();
|
||||||
|
|
||||||
Span<byte> sendData = stackalloc byte[rawData.Length];
|
_plugin.OnEntityDestroyed(player, entity);
|
||||||
|
|
||||||
|
var data = new byte[rawData.Length];
|
||||||
|
Span<byte> sendData = data.AsSpan();
|
||||||
rawData.CopyTo(sendData);
|
rawData.CopyTo(sendData);
|
||||||
Broadcast(_readyPlayers, sendData, DeliveryType.Reliable);
|
|
||||||
|
Broadcast(_readyPlayers, data, DeliveryType.Reliable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,8 +281,9 @@ namespace Ragon.Core
|
|||||||
foreach (var entity in _entities.Values)
|
foreach (var entity in _entities.Values)
|
||||||
{
|
{
|
||||||
var entityState = entity.State.AsSpan();
|
var entityState = entity.State.AsSpan();
|
||||||
|
var data = new byte[entity.State.Length + 10];
|
||||||
|
|
||||||
Span<byte> sendData = stackalloc byte[entity.State.Length + 10];
|
Span<byte> sendData = data.AsSpan();
|
||||||
Span<byte> operationData = sendData.Slice(0, 2);
|
Span<byte> operationData = sendData.Slice(0, 2);
|
||||||
Span<byte> entityData = sendData.Slice(2, 4);
|
Span<byte> entityData = sendData.Slice(2, 4);
|
||||||
Span<byte> ownerData = sendData.Slice(6, 4);
|
Span<byte> ownerData = sendData.Slice(6, 4);
|
||||||
@@ -249,7 +295,7 @@ namespace Ragon.Core
|
|||||||
|
|
||||||
entityState.CopyTo(entityStateData);
|
entityState.CopyTo(entityStateData);
|
||||||
|
|
||||||
Send(peerId, sendData, DeliveryType.Reliable);
|
Send(peerId, data, DeliveryType.Reliable);
|
||||||
}
|
}
|
||||||
|
|
||||||
Send(peerId, RagonOperation.RESTORE_END);
|
Send(peerId, RagonOperation.RESTORE_END);
|
||||||
@@ -259,6 +305,8 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
_players[peerId].IsLoaded = true;
|
_players[peerId].IsLoaded = true;
|
||||||
_readyPlayers = _players.Where(p => p.Value.IsLoaded).Select(p => p.Key).ToArray();
|
_readyPlayers = _players.Where(p => p.Value.IsLoaded).Select(p => p.Key).ToArray();
|
||||||
|
|
||||||
|
_plugin.OnPlayerJoined(_players[peerId]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,16 +314,7 @@ namespace Ragon.Core
|
|||||||
|
|
||||||
public void Tick(float deltaTime)
|
public void Tick(float deltaTime)
|
||||||
{
|
{
|
||||||
_ticks++;
|
_plugin.OnTick(deltaTime);
|
||||||
_plugin.OnTick(_ticks, deltaTime);
|
|
||||||
|
|
||||||
// for (var i = 0; i < _entitiesAll.Length; i++)
|
|
||||||
// {
|
|
||||||
// var entity = _entities[i];
|
|
||||||
// Span<byte> data = stackalloc byte[entity.State.Length];
|
|
||||||
// rawData.CopyTo(data);
|
|
||||||
// Broadcast(_readyPlayers, data);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
@@ -290,66 +329,66 @@ namespace Ragon.Core
|
|||||||
_plugin.OnStop();
|
_plugin.OnStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_logger.Info("Room destroyed");
|
_logger.Info("Room destroyed");
|
||||||
_plugin.Detach();
|
_plugin.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player GetPlayerByPeerId(uint peerId) => _players[peerId];
|
public Player GetPlayerById(uint peerId) => _players[peerId];
|
||||||
|
public Entity GetEntityById(int entityId) => _entities[entityId];
|
||||||
public Player GetOwner() => _players[_owner];
|
public Player GetOwner() => _players[_owner];
|
||||||
|
|
||||||
public void Send(uint peerId, RagonOperation operation, DeliveryType deliveryType = DeliveryType.Unreliable)
|
public void Send(uint peerId, RagonOperation operation, DeliveryType deliveryType = DeliveryType.Unreliable)
|
||||||
{
|
{
|
||||||
Span<byte> data = stackalloc byte[2];
|
var rawData = new byte[2];
|
||||||
RagonHeader.WriteUShort((ushort) operation, ref data);
|
var rawDataSpan = new Span<byte>(rawData);
|
||||||
|
|
||||||
|
RagonHeader.WriteUShort((ushort) operation, ref rawDataSpan);
|
||||||
|
|
||||||
var bytes = data.ToArray();
|
|
||||||
_roomThread.WriteOutEvent(new Event()
|
_roomThread.WriteOutEvent(new Event()
|
||||||
{
|
{
|
||||||
PeerId = peerId,
|
PeerId = peerId,
|
||||||
Data = bytes,
|
Data = rawData,
|
||||||
Type = EventType.DATA,
|
Type = EventType.DATA,
|
||||||
Delivery = deliveryType,
|
Delivery = deliveryType,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Send(uint peerId, Span<byte> payload, DeliveryType deliveryType = DeliveryType.Unreliable)
|
public void Send(uint peerId, byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
|
||||||
{
|
{
|
||||||
var bytes = payload.ToArray();
|
|
||||||
_roomThread.WriteOutEvent(new Event()
|
_roomThread.WriteOutEvent(new Event()
|
||||||
{
|
{
|
||||||
PeerId = peerId,
|
PeerId = peerId,
|
||||||
Data = bytes,
|
Data = rawData,
|
||||||
Type = EventType.DATA,
|
Type = EventType.DATA,
|
||||||
Delivery = deliveryType,
|
Delivery = deliveryType,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Broadcast(uint[] peersIds, Span<byte> rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
|
public void Broadcast(uint[] peersIds, byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
|
||||||
{
|
{
|
||||||
var bytes = rawData.ToArray();
|
|
||||||
foreach (var peer in peersIds)
|
foreach (var peer in peersIds)
|
||||||
{
|
{
|
||||||
_roomThread.WriteOutEvent(new Event()
|
_roomThread.WriteOutEvent(new Event()
|
||||||
{
|
{
|
||||||
PeerId = peer,
|
PeerId = peer,
|
||||||
Data = bytes,
|
Data = rawData,
|
||||||
Type = EventType.DATA,
|
Type = EventType.DATA,
|
||||||
Delivery = deliveryType,
|
Delivery = deliveryType,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Broadcast(Span<byte> rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
|
public void Broadcast(byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
|
||||||
{
|
{
|
||||||
var bytes = rawData.ToArray();
|
|
||||||
foreach (var player in _players.Values.ToArray())
|
foreach (var player in _players.Values.ToArray())
|
||||||
{
|
{
|
||||||
_roomThread.WriteOutEvent(new Event()
|
_roomThread.WriteOutEvent(new Event()
|
||||||
{
|
{
|
||||||
PeerId = player.PeerId,
|
PeerId = player.PeerId,
|
||||||
Data = bytes,
|
Data = rawData,
|
||||||
Type = EventType.DATA,
|
Type = EventType.DATA,
|
||||||
Delivery = deliveryType,
|
Delivery = deliveryType,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace Ragon.Core
|
|||||||
_peersByRoom = new Dictionary<uint, Room>();
|
_peersByRoom = new Dictionary<uint, Room>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ProcessEvent(RagonOperation operation, uint peerId, byte[] payload)
|
public void ProcessEvent(RagonOperation operation, uint peerId, ReadOnlySpan<byte> payload)
|
||||||
{
|
{
|
||||||
switch (operation)
|
switch (operation)
|
||||||
{
|
{
|
||||||
@@ -56,29 +56,30 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
if (_manager.OnAuthorize(peerId, ref payload))
|
if (_manager.OnAuthorize(peerId, ref payload))
|
||||||
{
|
{
|
||||||
Span<byte> data = stackalloc byte[2];
|
var sendData = new byte[2];
|
||||||
|
Span<byte> data = sendData.AsSpan();
|
||||||
|
|
||||||
RagonHeader.WriteUShort((ushort) RagonOperation.AUTHORIZED_SUCCESS, ref data);
|
RagonHeader.WriteUShort((ushort) RagonOperation.AUTHORIZED_SUCCESS, ref data);
|
||||||
|
|
||||||
var bytes = data.ToArray();
|
|
||||||
_roomThread.WriteOutEvent(new Event()
|
_roomThread.WriteOutEvent(new Event()
|
||||||
{
|
{
|
||||||
Delivery = DeliveryType.Reliable,
|
Delivery = DeliveryType.Reliable,
|
||||||
Type = EventType.DATA,
|
Type = EventType.DATA,
|
||||||
Data = bytes,
|
Data = sendData,
|
||||||
PeerId = peerId,
|
PeerId = peerId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Span<byte> data = stackalloc byte[2];
|
var sendData = new byte[2];
|
||||||
|
var data = sendData.AsSpan();
|
||||||
RagonHeader.WriteUShort((ushort) RagonOperation.AUTHORIZED_FAILED, ref data);
|
RagonHeader.WriteUShort((ushort) RagonOperation.AUTHORIZED_FAILED, ref data);
|
||||||
|
|
||||||
var bytes = data.ToArray();
|
|
||||||
_roomThread.WriteOutEvent(new Event()
|
_roomThread.WriteOutEvent(new Event()
|
||||||
{
|
{
|
||||||
Delivery = DeliveryType.Reliable,
|
Delivery = DeliveryType.Reliable,
|
||||||
Type = EventType.DATA,
|
Type = EventType.DATA,
|
||||||
Data = bytes,
|
Data = sendData,
|
||||||
PeerId = peerId,
|
PeerId = peerId,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -133,7 +134,7 @@ namespace Ragon.Core
|
|||||||
return room;
|
return room;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Room Left(uint peerId, byte[] payload)
|
public Room Left(uint peerId, ReadOnlySpan<byte> payload)
|
||||||
{
|
{
|
||||||
_peersByRoom.Remove(peerId, out var room);
|
_peersByRoom.Remove(peerId, out var room);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using DisruptorUnity3d;
|
using DisruptorUnity3d;
|
||||||
|
using NLog;
|
||||||
using Ragon.Common;
|
using Ragon.Common;
|
||||||
|
|
||||||
namespace Ragon.Core
|
namespace Ragon.Core
|
||||||
@@ -13,6 +14,7 @@ namespace Ragon.Core
|
|||||||
private readonly Dictionary<uint, Room> _socketByRooms;
|
private readonly Dictionary<uint, Room> _socketByRooms;
|
||||||
private readonly Thread _thread;
|
private readonly Thread _thread;
|
||||||
private readonly Stopwatch _timer;
|
private readonly Stopwatch _timer;
|
||||||
|
private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
private RingBuffer<Event> _receiveBuffer = new RingBuffer<Event>(8192 + 8192);
|
private RingBuffer<Event> _receiveBuffer = new RingBuffer<Event>(8192 + 8192);
|
||||||
private RingBuffer<Event> _sendBuffer = new RingBuffer<Event>(8192 + 8192);
|
private RingBuffer<Event> _sendBuffer = new RingBuffer<Event>(8192 + 8192);
|
||||||
@@ -60,7 +62,6 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
if (evnt.Type == EventType.DISCONNECTED || evnt.Type == EventType.TIMEOUT)
|
if (evnt.Type == EventType.DISCONNECTED || evnt.Type == EventType.TIMEOUT)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (_socketByRooms.ContainsKey(evnt.PeerId))
|
if (_socketByRooms.ContainsKey(evnt.PeerId))
|
||||||
{
|
{
|
||||||
_roomManager.Disconnected(evnt.PeerId);
|
_roomManager.Disconnected(evnt.PeerId);
|
||||||
@@ -70,16 +71,23 @@ namespace Ragon.Core
|
|||||||
|
|
||||||
if (evnt.Type == EventType.DATA)
|
if (evnt.Type == EventType.DATA)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<byte> data = evnt.Data.AsSpan();
|
var data = new ReadOnlySpan<byte>(evnt.Data);
|
||||||
var operation = (RagonOperation) RagonHeader.ReadUShort(ref data);
|
var operationData = data.Slice(0, 2);
|
||||||
|
var operation = (RagonOperation) RagonHeader.ReadUShort(ref operationData);
|
||||||
if (_socketByRooms.TryGetValue(evnt.PeerId, out var room))
|
if (_socketByRooms.TryGetValue(evnt.PeerId, out var room))
|
||||||
{
|
{
|
||||||
room.ProcessEvent(operation, evnt.PeerId, evnt.Data);
|
try
|
||||||
|
{
|
||||||
|
room.ProcessEvent(operation, evnt.PeerId, data);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_logger.Error(exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var payload = new byte[evnt.Data.Length - 2];
|
var payload = data.Slice(2, data.Length - 2);
|
||||||
Array.Copy(evnt.Data, 2, payload, 0, evnt.Data.Length - 2);
|
|
||||||
_roomManager.ProcessEvent(operation, evnt.PeerId, payload);
|
_roomManager.ProcessEvent(operation, evnt.PeerId, payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Ragon.Core
|
|
||||||
{
|
|
||||||
public struct RoomThreadInfo
|
|
||||||
{
|
|
||||||
public int PlayersCount;
|
|
||||||
public int PlayersMax;
|
|
||||||
public bool Available;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,12 +2,46 @@
|
|||||||
<img src="Images/logo.png" width="200" >
|
<img src="Images/logo.png" width="200" >
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Ragon - high perfomance room based game server with plugin based architecture.
|
## Ragon Server
|
||||||
|
|
||||||
Features:
|
Ragon is fully free high perfomance room based game server with plugin based architecture.
|
||||||
- Room base architecture
|
|
||||||
- Efficient memory management
|
|
||||||
- Flexible plugin system
|
|
||||||
- No CCU limitations
|
|
||||||
- Fully multithreaded
|
|
||||||
|
|
||||||
|
|
||||||
|
<a href="">Documentation</a>
|
||||||
|
<br>
|
||||||
|
<a href="">Get started</a>
|
||||||
|
|
||||||
|
|
||||||
|
### Features:
|
||||||
|
- Free
|
||||||
|
- Flexiable API
|
||||||
|
- Support client authoritative
|
||||||
|
- Support server authoritative
|
||||||
|
- Room based architecture
|
||||||
|
- Extendable room logic via plugin
|
||||||
|
- Custom authorization
|
||||||
|
- No CCU limitations*
|
||||||
|
- Extentable rooms with plugin system
|
||||||
|
- Fully multi-threaded
|
||||||
|
- Engine agnostic
|
||||||
|
- Support any client architecture (OOP, ECS)
|
||||||
|
- UDP
|
||||||
|
|
||||||
|
### Roadmap:
|
||||||
|
- Use native memory
|
||||||
|
- Reduce allocations
|
||||||
|
- Dashboard for monitoring entities and players in realtime
|
||||||
|
- Statistics for monitoring state of server, cpu, memory
|
||||||
|
- Docker support
|
||||||
|
- Add additional API to plugin system
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
* ENet-Sharp
|
||||||
|
* NetStack
|
||||||
|
* RingBuffer-Unity3D
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
|
||||||
|
### Tips
|
||||||
|
* Limited to 4095 CCU by library ENet-Sharp
|
||||||
Reference in New Issue
Block a user