From 5f3b2d7ed8069c3a0da5e7005a36cdd2344b430b Mon Sep 17 00:00:00 2001 From: Edmand46 Date: Wed, 13 Jul 2022 07:56:44 +0400 Subject: [PATCH] - Added support entities on scene - Improved performance --- Ragon.Common/Protocol/RagonOperation.cs | 1 + .../Configuration/ConfigurationLoader.cs | 2 +- Ragon/Sources/Entity/Entity.cs | 4 +- Ragon/Sources/Game/GameRoom.cs | 130 +++++++++++++----- Ragon/Sources/Server/ENet/ENetServer.cs | 22 +++ Ragon/Sources/Server/ISocketServer.cs | 1 + 6 files changed, 122 insertions(+), 38 deletions(-) diff --git a/Ragon.Common/Protocol/RagonOperation.cs b/Ragon.Common/Protocol/RagonOperation.cs index 567533a..d486d5c 100644 --- a/Ragon.Common/Protocol/RagonOperation.cs +++ b/Ragon.Common/Protocol/RagonOperation.cs @@ -20,6 +20,7 @@ namespace Ragon.Common PLAYER_LEAVED, CREATE_ENTITY, + CREATE_STATIC_ENTITY, DESTROY_ENTITY, SNAPSHOT, diff --git a/Ragon/Sources/Configuration/ConfigurationLoader.cs b/Ragon/Sources/Configuration/ConfigurationLoader.cs index f65da26..e3ba378 100755 --- a/Ragon/Sources/Configuration/ConfigurationLoader.cs +++ b/Ragon/Sources/Configuration/ConfigurationLoader.cs @@ -9,7 +9,7 @@ namespace Ragon.Core public static class ConfigurationLoader { private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); - private static readonly string _serverVersion = "1.0.6-rc"; + private static readonly string _serverVersion = "1.0.9-rc"; private static void CopyrightInfo() { diff --git a/Ragon/Sources/Entity/Entity.cs b/Ragon/Sources/Entity/Entity.cs index 7180aed..48a3468 100644 --- a/Ragon/Sources/Entity/Entity.cs +++ b/Ragon/Sources/Entity/Entity.cs @@ -6,15 +6,17 @@ public class Entity { private static int _idGenerator = 0; public int EntityId { get; private set; } + public int StaticId { get; private set; } public uint OwnerId { get; private set; } public ushort EntityType { get; private set; } public RagonAuthority Authority { get; private set; } public EntityState State { get; private set; } public EntityState Payload { get; private set; } - public Entity(uint ownerId, ushort entityType, RagonAuthority stateAuthority, RagonAuthority eventAuthority) + public Entity(uint ownerId, ushort entityType, int staticId, RagonAuthority stateAuthority, RagonAuthority eventAuthority) { OwnerId = ownerId; + StaticId = staticId; EntityType = entityType; EntityId = _idGenerator++; State = new EntityState(stateAuthority); diff --git a/Ragon/Sources/Game/GameRoom.cs b/Ragon/Sources/Game/GameRoom.cs index 5d2323a..9b9a50f 100755 --- a/Ragon/Sources/Game/GameRoom.cs +++ b/Ragon/Sources/Game/GameRoom.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; - using System.Linq; using NLog; using Ragon.Common; @@ -29,7 +28,7 @@ namespace Ragon.Core private uint[] _readyPlayers = Array.Empty(); private uint[] _allPlayers = Array.Empty(); private Entity[] _entitiesAll = Array.Empty(); - + public GameRoom(IGameThread gameThread, PluginBase pluginBase, string map, int min, int max) { _gameThread = gameThread; @@ -50,7 +49,7 @@ namespace Ragon.Core { _owner = player.PeerId; } - + { _serializer.Clear(); _serializer.WriteOperation(RagonOperation.PLAYER_JOINED); @@ -61,10 +60,10 @@ namespace Ragon.Core var sendData = _serializer.ToArray(); Broadcast(_readyPlayers, sendData, DeliveryType.Reliable); } - + _players.Add(player.PeerId, player); _allPlayers = _players.Select(p => p.Key).ToArray(); - + { _serializer.Clear(); _serializer.WriteOperation(RagonOperation.JOIN_SUCCESS); @@ -94,7 +93,7 @@ namespace Ragon.Core { _allPlayers = _players.Select(p => p.Key).ToArray(); _readyPlayers = _players.Where(p => p.Value.IsLoaded).Select(p => p.Key).ToArray(); - + var isOwnershipChange = player.PeerId == _owner; { @@ -119,9 +118,9 @@ namespace Ragon.Core { var newRoomOwnerId = _allPlayers[0]; var newRoomOwner = _players[newRoomOwnerId]; - + _owner = newRoomOwnerId; - + { _plugin.OnOwnershipChanged(newRoomOwner); @@ -142,10 +141,10 @@ namespace Ragon.Core { var operation = (RagonOperation) rawData[0]; var payloadRawData = rawData.Slice(1, rawData.Length - 1); - + _serializer.Clear(); _serializer.FromSpan(ref payloadRawData); - + switch (operation) { case RagonOperation.REPLICATE_ENTITY_STATE: @@ -159,6 +158,7 @@ namespace Ragon.Core var entityStateData = _serializer.ReadData(_serializer.Size); ent.State.Write(ref entityStateData); } + break; } case RagonOperation.REPLICATE_ENTITY_EVENT: @@ -176,7 +176,7 @@ namespace Ragon.Core Span payloadRaw = stackalloc byte[_serializer.Size]; var payloadData = _serializer.ReadData(_serializer.Size); payloadData.CopyTo(payloadRaw); - + ReadOnlySpan payload = payloadRaw; if (_plugin.InternalHandle(peerId, entityId, evntId, ref payload)) return; @@ -189,7 +189,7 @@ namespace Ragon.Core _serializer.WriteInt(entityId); _serializer.WriteData(ref payload); var sendData = _serializer.ToArray(); - + Broadcast(_readyPlayers, sendData, DeliveryType.Reliable); break; } @@ -200,7 +200,7 @@ namespace Ragon.Core Span payloadRaw = stackalloc byte[_serializer.Size]; var payloadData = _serializer.ReadData(_serializer.Size); payloadData.CopyTo(payloadRaw); - + ReadOnlySpan payload = payloadRaw; if (_plugin.InternalHandle(peerId, evntId, ref payload)) return; @@ -211,7 +211,49 @@ namespace Ragon.Core _serializer.WriteByte(evntMode); _serializer.WriteUShort(evntId); _serializer.WriteData(ref payload); - + + var sendData = _serializer.ToArray(); + Broadcast(_readyPlayers, sendData, DeliveryType.Reliable); + break; + } + case RagonOperation.CREATE_STATIC_ENTITY: + { + var entityType = _serializer.ReadUShort(); + var staticId = _serializer.ReadUShort(); + var stateAuthority = (RagonAuthority) _serializer.ReadByte(); + var eventAuthority = (RagonAuthority) _serializer.ReadByte(); + var entity = new Entity(peerId, entityType, staticId, stateAuthority, eventAuthority); + + { + var entityPayload = _serializer.ReadData(_serializer.Size); + entity.Payload.Write(ref entityPayload); + } + + var player = _players[peerId]; + player.Entities.Add(entity); + player.EntitiesIds.Add(entity.EntityId); + + var ownerId = (ushort) peerId; + + _entities.Add(entity.EntityId, entity); + _entitiesAll = _entities.Values.ToArray(); + + _plugin.OnEntityCreated(player, entity); + + _serializer.Clear(); + _serializer.WriteOperation(RagonOperation.CREATE_STATIC_ENTITY); + _serializer.WriteUShort(entityType); + _serializer.WriteUShort(staticId); + _serializer.WriteByte((byte) stateAuthority); + _serializer.WriteByte((byte) eventAuthority); + _serializer.WriteInt(entity.EntityId); + _serializer.WriteUShort(ownerId); + + { + var entityPayload = entity.Payload.Read(); + _serializer.WriteData(ref entityPayload); + } + var sendData = _serializer.ToArray(); Broadcast(_readyPlayers, sendData, DeliveryType.Reliable); break; @@ -221,8 +263,8 @@ namespace Ragon.Core var entityType = _serializer.ReadUShort(); var stateAuthority = (RagonAuthority) _serializer.ReadByte(); var eventAuthority = (RagonAuthority) _serializer.ReadByte(); - var entity = new Entity(peerId, entityType, stateAuthority, eventAuthority); - + var entity = new Entity(peerId, entityType, -1, stateAuthority, eventAuthority); + { var entityPayload = _serializer.ReadData(_serializer.Size); entity.Payload.Write(ref entityPayload); @@ -246,12 +288,12 @@ namespace Ragon.Core _serializer.WriteByte((byte) eventAuthority); _serializer.WriteInt(entity.EntityId); _serializer.WriteUShort(ownerId); - + { var entityPayload = entity.Payload.Read(); _serializer.WriteData(ref entityPayload); } - + var sendData = _serializer.ToArray(); Broadcast(_readyPlayers, sendData, DeliveryType.Reliable); break; @@ -298,14 +340,36 @@ namespace Ragon.Core _serializer.WriteUShort((ushort) playerPeerId); _serializer.WriteString(_players[playerPeerId].PlayerName); } - - _serializer.WriteInt(_entitiesAll.Length); - foreach (var entity in _entitiesAll) + + var dynamicCount = _entitiesAll.Where(e => e.StaticId == -1).ToArray(); + _serializer.WriteInt(dynamicCount.Length); + foreach (var entity in dynamicCount) + { + if (entity.StaticId != -1) continue; + + var payload = entity.Payload.Read(); + var state = entity.State.Read(); + + _serializer.WriteInt(entity.EntityId); + _serializer.WriteByte((byte) entity.State.Authority); + _serializer.WriteByte((byte) entity.Authority); + _serializer.WriteUShort(entity.EntityType); + _serializer.WriteUShort((ushort) entity.OwnerId); + _serializer.WriteUShort((ushort) payload.Length); + _serializer.WriteData(ref payload); + _serializer.WriteUShort((ushort) state.Length); + _serializer.WriteData(ref state); + } + + var staticCount = _entitiesAll.Where(e => e.StaticId != -1).ToArray(); + _serializer.WriteInt(staticCount.Length); + foreach (var entity in staticCount) { var payload = entity.Payload.Read(); var state = entity.State.Read(); - + _serializer.WriteInt(entity.EntityId); + _serializer.WriteUShort((ushort) entity.StaticId); _serializer.WriteByte((byte) entity.State.Authority); _serializer.WriteByte((byte) entity.Authority); _serializer.WriteUShort(entity.EntityType); @@ -327,11 +391,11 @@ namespace Ragon.Core } } } - + public void Tick(float deltaTime) { _scheduler.Tick(deltaTime); - + foreach (var entity in _entitiesAll) { if (entity.State.isDirty) @@ -360,7 +424,7 @@ namespace Ragon.Core { foreach (var peerId in _allPlayers) _gameThread.Server.Disconnect(peerId, 0); - + _plugin.OnStop(); _plugin.Detach(); } @@ -368,10 +432,10 @@ namespace Ragon.Core public Player GetPlayerById(uint peerId) => _players[peerId]; public Entity GetEntityById(int entityId) => _entities[entityId]; - + public Player GetOwner() => _players[_owner]; - - public IDispatcher GetThreadDispatcher() => _gameThread.ThreadDispatcher; + + public IDispatcher GetThreadDispatcher() => _gameThread.ThreadDispatcher; public IScheduler GetScheduler() => _scheduler; @@ -382,18 +446,12 @@ namespace Ragon.Core public void Broadcast(uint[] peersIds, byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable) { - foreach (var peer in peersIds) - { - _gameThread.Server.Send(peer, rawData, deliveryType); - } + _gameThread.Server.Broadcast(peersIds, rawData, deliveryType); } public void Broadcast(byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable) { - foreach (var peer in _allPlayers) - { - _gameThread.Server.Send(peer, rawData, deliveryType); - } + _gameThread.Server.Broadcast(_allPlayers, rawData, deliveryType); } } } \ No newline at end of file diff --git a/Ragon/Sources/Server/ENet/ENetServer.cs b/Ragon/Sources/Server/ENet/ENetServer.cs index 4130947..b024a71 100755 --- a/Ragon/Sources/Server/ENet/ENetServer.cs +++ b/Ragon/Sources/Server/ENet/ENetServer.cs @@ -43,6 +43,28 @@ namespace Ragon.Core _logger.Info($"Network listening on {port}"); } + public void Broadcast(uint[] peersIds, byte[] data, DeliveryType type) + { + var newPacket = new Packet(); + var packetFlags = PacketFlags.Instant; + byte channel = 1; + + if (type == DeliveryType.Reliable) + { + packetFlags = PacketFlags.Reliable; + channel = 0; + } + else if (type == DeliveryType.Unreliable) + { + channel = 1; + packetFlags = PacketFlags.None; + } + + newPacket.Create(data, data.Length, packetFlags); + foreach (var peerId in peersIds) + _peers[peerId].Send(channel, ref newPacket); + } + public void Send(uint peerId, byte[] data, DeliveryType type) { var newPacket = new Packet(); diff --git a/Ragon/Sources/Server/ISocketServer.cs b/Ragon/Sources/Server/ISocketServer.cs index b3bd8b6..09c6b9a 100644 --- a/Ragon/Sources/Server/ISocketServer.cs +++ b/Ragon/Sources/Server/ISocketServer.cs @@ -6,5 +6,6 @@ public interface ISocketServer public void Process(); public void Stop(); public void Send(uint peerId, byte[] data, DeliveryType type); + public void Broadcast(uint[] peersIds, byte[] data, DeliveryType type); public void Disconnect(uint peerId, uint errorCode); } \ No newline at end of file