major update
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>10</LangVersion>
|
||||
<RootNamespace>Ragon.Client.Simulation</RootNamespace>
|
||||
<Authors>Eduard Kargin (Edmand46)</Authors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DebugType>none</DebugType>
|
||||
<OutputPath>/Users/edmand46/RagonProjects/ragon-unity-sdk/Assets/Ragon/Runtime/Plugins</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<OutputPath>/Users/edmand46/RagonProjects/ragon-unity-sdk/Assets/Ragon/Runtime/Plugins</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ragon.Protocol\Ragon.Protocol.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.Compressor;
|
||||
|
||||
public class FloatCompressor
|
||||
{
|
||||
public float Min { get; private set; }
|
||||
public float Max { get; private set; }
|
||||
public float Precision { get; private set; }
|
||||
public int RequiredBits { get; private set; }
|
||||
|
||||
private uint _mask;
|
||||
|
||||
public FloatCompressor(float min = -1024.0f, float max = 1024.0f, float precision = 0.01f)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
Precision = precision;
|
||||
RequiredBits = DeBruijn.Log2((uint)((Max - Min) * (1f / Precision) + 0.5f)) + 1;
|
||||
|
||||
_mask = (uint)((1L << RequiredBits) - 1);
|
||||
}
|
||||
|
||||
public uint Compress(float value)
|
||||
{
|
||||
return (uint)((value - Min) * 1f / Precision + 0.5f) & _mask;
|
||||
}
|
||||
|
||||
public float Decompress(uint value)
|
||||
{
|
||||
var result = value * Precision + Min;
|
||||
|
||||
if (result < Min)
|
||||
result = Min;
|
||||
else if (result > Max)
|
||||
result = Max;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.Compressor;
|
||||
|
||||
public class IntCompressor
|
||||
{
|
||||
public int Min { get; private set; }
|
||||
public int Max { get; private set; }
|
||||
public int RequiredBits { get; private set; }
|
||||
|
||||
public IntCompressor(int min = -1000, int max = 1000)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
RequiredBits = Bits.Compute(Max);
|
||||
}
|
||||
|
||||
public uint Compress(int value)
|
||||
{
|
||||
return (uint)((value << 1) ^ (value >> 31));;
|
||||
}
|
||||
|
||||
public int Decompress(uint value)
|
||||
{
|
||||
return (int)((value >> 1) ^ -(int)(value & 1));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client
|
||||
{
|
||||
public sealed class RagonEntity
|
||||
{
|
||||
private delegate void OnEventDelegate(RagonPlayer player, RagonBuffer serializer);
|
||||
private RagonClient _client;
|
||||
|
||||
public ushort Id { get; private set; }
|
||||
public ushort Type { get; private set; }
|
||||
public bool Replication { get; private set; }
|
||||
|
||||
public RagonAuthority Authority { get; private set; }
|
||||
public RagonPlayer Owner { get; private set; }
|
||||
public RagonEntityState State { get; private set; }
|
||||
|
||||
public bool IsAttached { get; private set; }
|
||||
public bool HasAuthority { get; private set; }
|
||||
|
||||
public event Action<RagonEntity> Attached;
|
||||
public event Action Detached;
|
||||
public event Action<RagonPlayer, RagonPlayer> OwnershipChanged;
|
||||
|
||||
internal bool PropertiesChanged => _propertiesChanged;
|
||||
internal ushort SceneId => _sceneId;
|
||||
|
||||
private ushort _sceneId;
|
||||
private bool _propertiesChanged;
|
||||
|
||||
private RagonPayload _spawnPayload;
|
||||
private RagonPayload _destroyPayload;
|
||||
|
||||
private Dictionary<int, OnEventDelegate> _events = new();
|
||||
private Dictionary<int, Action<RagonPlayer, IRagonEvent>> _localEvents = new();
|
||||
|
||||
public RagonEntity(ushort type = 0, ushort sceneId = 0)
|
||||
{
|
||||
State = new RagonEntityState(this);
|
||||
Type = type;
|
||||
|
||||
_sceneId = sceneId;
|
||||
}
|
||||
|
||||
internal void Attach(RagonClient client, ushort entityId, ushort entityType, bool hasAuthority, RagonPlayer owner, RagonPayload payload)
|
||||
{
|
||||
Type = entityType;
|
||||
Id = entityId;
|
||||
Owner = owner;
|
||||
IsAttached = true;
|
||||
Replication = true;
|
||||
HasAuthority = hasAuthority;
|
||||
|
||||
_client = client;
|
||||
_spawnPayload = payload;
|
||||
|
||||
Attached?.Invoke(this);
|
||||
}
|
||||
|
||||
internal void Detach(RagonPayload payload)
|
||||
{
|
||||
_destroyPayload = payload;
|
||||
|
||||
Detached?.Invoke();
|
||||
}
|
||||
|
||||
internal T GetPayload<T>(RagonPayload data) where T : IRagonPayload, new()
|
||||
{
|
||||
var buffer = new RagonBuffer();
|
||||
data.Write(buffer);
|
||||
|
||||
var payload = new T();
|
||||
payload.Deserialize(buffer);
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
public T GetSpawnPayload<T>() where T : IRagonPayload, new()
|
||||
{
|
||||
return GetPayload<T>(_spawnPayload);
|
||||
}
|
||||
|
||||
public T GetDestroyPayload<T>() where T : IRagonPayload, new()
|
||||
{
|
||||
return GetPayload<T>(_destroyPayload);
|
||||
}
|
||||
|
||||
public void ReplicateEvent<TEvent>(TEvent evnt, RagonPlayer target, RagonReplicationMode replicationMode)
|
||||
where TEvent : IRagonEvent, new()
|
||||
{
|
||||
var evntId = _client.Event.GetEventCode(evnt);
|
||||
var buffer = _client.Buffer;
|
||||
|
||||
buffer.Clear();
|
||||
buffer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT);
|
||||
buffer.WriteUShort(Id);
|
||||
buffer.WriteUShort(evntId);
|
||||
buffer.WriteByte((byte) replicationMode);
|
||||
buffer.WriteByte((byte) RagonTarget.Player);
|
||||
buffer.WriteUShort((ushort) target.PeerId);
|
||||
|
||||
evnt.Serialize(buffer);
|
||||
|
||||
var sendData = buffer.ToArray();
|
||||
_client.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
public void ReplicateEvent<TEvent>(
|
||||
TEvent evnt,
|
||||
RagonTarget target = RagonTarget.All,
|
||||
RagonReplicationMode replicationMode = RagonReplicationMode.Server)
|
||||
where TEvent : IRagonEvent, new()
|
||||
{
|
||||
if (target != RagonTarget.ExceptOwner)
|
||||
{
|
||||
if (replicationMode == RagonReplicationMode.Local)
|
||||
{
|
||||
var eventCode = _client.Event.GetEventCode(evnt);
|
||||
_localEvents[eventCode].Invoke(_client.Room.Local, evnt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (replicationMode == RagonReplicationMode.LocalAndServer)
|
||||
{
|
||||
var eventCode = _client.Event.GetEventCode(evnt);
|
||||
_localEvents[eventCode].Invoke(_client.Room.Local, evnt);
|
||||
}
|
||||
}
|
||||
|
||||
var evntId = _client.Event.GetEventCode(evnt);
|
||||
var buffer = _client.Buffer;
|
||||
|
||||
buffer.Clear();
|
||||
buffer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT);
|
||||
buffer.WriteUShort(Id);
|
||||
buffer.WriteUShort(evntId);
|
||||
buffer.WriteByte((byte) replicationMode);
|
||||
buffer.WriteByte((byte) target);
|
||||
|
||||
evnt.Serialize(buffer);
|
||||
|
||||
var sendData = buffer.ToArray();
|
||||
_client.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
public void OnEvent<TEvent>(Action<RagonPlayer, TEvent> callback) where TEvent : IRagonEvent, new()
|
||||
{
|
||||
var t = new TEvent();
|
||||
var eventCode = _client.Event.GetEventCode(t);
|
||||
|
||||
if (_events.ContainsKey(eventCode))
|
||||
{
|
||||
RagonLog.Warn($"Event already {eventCode} subscribed");
|
||||
return;
|
||||
}
|
||||
|
||||
_localEvents.Add(eventCode, (player, eventData) => { callback.Invoke(player, (TEvent) eventData); });
|
||||
_events.Add(eventCode, (player, serializer) =>
|
||||
{
|
||||
t.Deserialize(serializer);
|
||||
callback.Invoke(player, t);
|
||||
});
|
||||
}
|
||||
|
||||
internal void Write(RagonBuffer buffer)
|
||||
{
|
||||
buffer.WriteUShort(Id);
|
||||
|
||||
State.WriteState(buffer);
|
||||
|
||||
_propertiesChanged = false;
|
||||
}
|
||||
|
||||
|
||||
internal void Read(RagonBuffer buffer)
|
||||
{
|
||||
State.ReadState(buffer);
|
||||
}
|
||||
|
||||
internal void Event(ushort eventCode, RagonPlayer caller, RagonBuffer buffer)
|
||||
{
|
||||
if (_events.ContainsKey(eventCode))
|
||||
_events[eventCode]?.Invoke(caller, buffer);
|
||||
}
|
||||
|
||||
internal void TrackChangedProperty(RagonProperty property)
|
||||
{
|
||||
_propertiesChanged = true;
|
||||
}
|
||||
|
||||
public void OnOwnershipChanged(RagonPlayer player)
|
||||
{
|
||||
var prevOwner = Owner;
|
||||
|
||||
Owner = player;
|
||||
HasAuthority = player.PeerId == _client.Room.Local.PeerId;
|
||||
|
||||
OwnershipChanged?.Invoke(prevOwner, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public sealed class RagonEntityState
|
||||
{
|
||||
private List<RagonProperty> _properties;
|
||||
private RagonEntity _entity;
|
||||
|
||||
public RagonEntityState(RagonEntity entity)
|
||||
{
|
||||
_entity = entity;
|
||||
_properties = new List<RagonProperty>(6);
|
||||
}
|
||||
|
||||
public void AddProperty(RagonProperty property)
|
||||
{
|
||||
_properties.Add(property);
|
||||
|
||||
property.AssignEntity(_entity);
|
||||
}
|
||||
|
||||
internal void WriteInfo(RagonBuffer buffer)
|
||||
{
|
||||
buffer.WriteUShort((ushort)_properties.Count);
|
||||
foreach (var property in _properties)
|
||||
{
|
||||
buffer.WriteBool(property.IsFixed);
|
||||
buffer.WriteUShort((ushort)property.Size);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ReadState(RagonBuffer buffer)
|
||||
{
|
||||
foreach (var property in _properties)
|
||||
{
|
||||
var changed = buffer.ReadBool();
|
||||
if (changed)
|
||||
property.Deserialize(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteState(RagonBuffer buffer)
|
||||
{
|
||||
foreach (var prop in _properties)
|
||||
{
|
||||
if (prop.IsDirty)
|
||||
{
|
||||
buffer.WriteBool(true);
|
||||
prop.Write(buffer);
|
||||
prop.Flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
prop.AddTick();
|
||||
buffer.WriteBool(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public struct RagonPayload
|
||||
{
|
||||
private uint[] _data = new uint[128];
|
||||
private int _size = 0;
|
||||
|
||||
public RagonPayload(int capacity)
|
||||
{
|
||||
_size = capacity;
|
||||
}
|
||||
public int Size => _size;
|
||||
|
||||
public void Read(RagonBuffer buffer)
|
||||
{
|
||||
var readOnlySpan = _data.AsSpan();
|
||||
|
||||
buffer.ReadSpan(ref readOnlySpan, _size);
|
||||
}
|
||||
|
||||
public void Write(RagonBuffer buffer)
|
||||
{
|
||||
ReadOnlySpan<uint> readOnlySpan = _data.AsSpan();
|
||||
|
||||
buffer.WriteSpan(ref readOnlySpan, _size);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Payload Size: {_size}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
[Serializable]
|
||||
public class RagonProperty
|
||||
{
|
||||
public string Name => _name;
|
||||
public RagonEntity Entity => _entity;
|
||||
|
||||
public event Action Changed;
|
||||
public bool IsDirty => _dirty && _ticks >= _priority;
|
||||
public bool IsFixed => _fixed;
|
||||
public int Size => _size;
|
||||
|
||||
private bool _fixed;
|
||||
private string _name;
|
||||
protected bool _invokeLocal;
|
||||
|
||||
private RagonEntity _entity;
|
||||
private bool _dirty;
|
||||
private int _size;
|
||||
private int _ticks;
|
||||
private int _priority;
|
||||
|
||||
protected RagonProperty(int priority, bool invokeLocal)
|
||||
{
|
||||
_size = 0;
|
||||
_priority = priority;
|
||||
_fixed = false;
|
||||
_invokeLocal = invokeLocal;
|
||||
}
|
||||
|
||||
public void SetName(string name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
protected void SetFixedSize(int size)
|
||||
{
|
||||
_size = size;
|
||||
_fixed = true;
|
||||
}
|
||||
|
||||
protected void InvokeChanged()
|
||||
{
|
||||
if (!_invokeLocal)
|
||||
return;
|
||||
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
protected void MarkAsChanged()
|
||||
{
|
||||
InvokeChanged();
|
||||
|
||||
if (_dirty) return;
|
||||
_dirty = true;
|
||||
|
||||
_entity?.TrackChangedProperty(this);
|
||||
}
|
||||
|
||||
internal void Flush()
|
||||
{
|
||||
_dirty = false;
|
||||
_ticks = 0;
|
||||
}
|
||||
|
||||
internal void AddTick()
|
||||
{
|
||||
_ticks++;
|
||||
}
|
||||
|
||||
internal void AssignEntity(RagonEntity obj)
|
||||
{
|
||||
_entity = obj;
|
||||
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
internal void Write(RagonBuffer buffer)
|
||||
{
|
||||
if (_fixed)
|
||||
{
|
||||
Serialize(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
var sizeOffset = buffer.WriteOffset;
|
||||
buffer.Write(0, 16);
|
||||
var propOffset = buffer.WriteOffset;
|
||||
|
||||
Serialize(buffer);
|
||||
|
||||
var propSize = (uint) (buffer.WriteOffset - propOffset);
|
||||
buffer.Write(propSize, 16, sizeOffset);
|
||||
}
|
||||
|
||||
public virtual void Serialize(RagonBuffer buffer)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Deserialize(RagonBuffer buffer)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 AuthorizeFailedHandler: Handler
|
||||
{
|
||||
private readonly RagonListenerList _listenerList;
|
||||
public AuthorizeFailedHandler(RagonListenerList list)
|
||||
{
|
||||
_listenerList = list;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var message = buffer.ReadString();
|
||||
_listenerList.OnAuthorizationFailed(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 AuthorizeSuccessHandler: Handler
|
||||
{
|
||||
private readonly RagonListenerList _listenerList;
|
||||
|
||||
public AuthorizeSuccessHandler(RagonListenerList listenerList)
|
||||
{
|
||||
_listenerList = listenerList;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var playerId = buffer.ReadString();
|
||||
var playerName = buffer.ReadString();
|
||||
|
||||
_listenerList.OnAuthorizationSuccess(playerId, playerName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 EntityCreateHandler : Handler
|
||||
{
|
||||
private readonly RagonClient _client;
|
||||
private readonly RagonPlayerCache _playerCache;
|
||||
private readonly RagonEntityCache _entityCache;
|
||||
|
||||
public EntityCreateHandler(
|
||||
RagonClient client,
|
||||
RagonPlayerCache playerCache,
|
||||
RagonEntityCache entityCache
|
||||
)
|
||||
{
|
||||
_client = client;
|
||||
_entityCache = entityCache;
|
||||
_playerCache = playerCache;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var attachId = buffer.ReadUShort();
|
||||
var entityType = buffer.ReadUShort();
|
||||
var entityId = buffer.ReadUShort();
|
||||
var ownerId = buffer.ReadUShort();
|
||||
var player = _playerCache.GetPlayerByPeer(ownerId);
|
||||
var payload = new RagonPayload(buffer.Capacity);
|
||||
payload.Read(buffer);
|
||||
|
||||
if (player == null)
|
||||
{
|
||||
RagonLog.Warn($"Owner {ownerId}|{player.Name} not found in players");
|
||||
return;
|
||||
}
|
||||
|
||||
var hasAuthority = _playerCache.LocalPlayer.Id == player.Id;
|
||||
var entity = _entityCache.OnCreate(attachId, entityType, 0, entityId, hasAuthority);
|
||||
entity.Attach(_client, entityId, entityType, hasAuthority, player, payload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 EntityDestroyHandler: Handler
|
||||
{
|
||||
private readonly RagonEntityCache _entityCache;
|
||||
|
||||
public EntityDestroyHandler(RagonEntityCache entityCache)
|
||||
{
|
||||
_entityCache = entityCache;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var entityId = buffer.ReadUShort();
|
||||
var payload = new RagonPayload(buffer.Capacity);
|
||||
payload.Read(buffer);
|
||||
|
||||
_entityCache.OnDestroy(entityId, payload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 EntityEventHandler : Handler
|
||||
{
|
||||
private readonly RagonClient _client;
|
||||
private readonly RagonPlayerCache _playerCache;
|
||||
private readonly RagonEntityCache _entityCache;
|
||||
|
||||
public EntityEventHandler(
|
||||
RagonClient client,
|
||||
RagonPlayerCache playerCache,
|
||||
RagonEntityCache entityCache
|
||||
)
|
||||
{
|
||||
_client = client;
|
||||
_playerCache = playerCache;
|
||||
_entityCache = entityCache;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var eventCode = buffer.ReadUShort();
|
||||
var peerId = buffer.ReadUShort();
|
||||
var executionMode = (RagonReplicationMode)buffer.ReadByte();
|
||||
var entityId = buffer.ReadUShort();
|
||||
|
||||
var player = _playerCache.GetPlayerByPeer(peerId);
|
||||
if (player == null)
|
||||
{
|
||||
RagonLog.Warn($"Player not found for event {eventCode}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.IsMe && executionMode == RagonReplicationMode.LocalAndServer)
|
||||
return;
|
||||
|
||||
_entityCache.OnEvent(player, entityId, eventCode, buffer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 StateEntityHandler: Handler
|
||||
{
|
||||
private readonly RagonEntityCache _entityCache;
|
||||
|
||||
public StateEntityHandler(RagonEntityCache entityCache)
|
||||
{
|
||||
_entityCache = entityCache;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var entitiesCount = buffer.ReadUShort();
|
||||
for (var i = 0; i < entitiesCount; i++)
|
||||
{
|
||||
var entityId = buffer.ReadUShort();
|
||||
_entityCache.OnState(entityId, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface Handler
|
||||
{
|
||||
public void Handle(RagonBuffer buffer);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 JoinFailedHandler: Handler
|
||||
{
|
||||
private readonly RagonListenerList _listenerList;
|
||||
|
||||
public JoinFailedHandler(RagonListenerList listenerList)
|
||||
{
|
||||
_listenerList = listenerList;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var message = buffer.ReadString();
|
||||
_listenerList.OnFailed(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public struct RagonRoomInformation
|
||||
{
|
||||
public RagonRoomInformation(string roomId, string playerId, string ownerId, ushort min, ushort max)
|
||||
{
|
||||
RoomId = roomId;
|
||||
PlayerId = playerId;
|
||||
OwnerId = ownerId;
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public string RoomId { get; private set; }
|
||||
public string PlayerId { get; private set; }
|
||||
public string OwnerId { get; private set; }
|
||||
public ushort Min { get; private set; }
|
||||
public ushort Max { get; private set; }
|
||||
}
|
||||
|
||||
internal class JoinSuccessHandler : Handler
|
||||
{
|
||||
private readonly RagonListenerList _listenerList;
|
||||
private readonly RagonPlayerCache _playerCache;
|
||||
private readonly RagonEntityCache _entityCache;
|
||||
private readonly RagonClient _client;
|
||||
private readonly RagonBuffer _buffer;
|
||||
|
||||
public JoinSuccessHandler(
|
||||
RagonClient client,
|
||||
RagonBuffer buffer,
|
||||
RagonListenerList listenerList,
|
||||
RagonPlayerCache playerCache,
|
||||
RagonEntityCache entityCache
|
||||
)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_client = client;
|
||||
_listenerList = listenerList;
|
||||
_entityCache = entityCache;
|
||||
_playerCache = playerCache;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var roomId = buffer.ReadString();
|
||||
var localId = buffer.ReadString();
|
||||
var ownerId = buffer.ReadString();
|
||||
var min = buffer.ReadUShort();
|
||||
var max = buffer.ReadUShort();
|
||||
var map = buffer.ReadString();
|
||||
|
||||
var scene = new RagonScene(_client, _playerCache, _entityCache);
|
||||
var roomInfo = new RagonRoomInformation(roomId, localId, ownerId, min, max);
|
||||
var room = new RagonRoom(_client, _entityCache, _playerCache, roomInfo, scene);
|
||||
|
||||
_playerCache.SetOwnerAndLocal(ownerId, localId);
|
||||
_client.AssignRoom(room);
|
||||
_listenerList.OnLevel(map);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 LeaveRoomHandler : Handler
|
||||
{
|
||||
private readonly RagonClient _client;
|
||||
private readonly RagonListenerList _listenerList;
|
||||
private readonly RagonEntityCache _entityCache;
|
||||
|
||||
public LeaveRoomHandler(
|
||||
RagonClient client,
|
||||
RagonListenerList listenerList,
|
||||
RagonEntityCache entityCache)
|
||||
{
|
||||
_client = client;
|
||||
_listenerList = listenerList;
|
||||
_entityCache = entityCache;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
_listenerList.OnLeft();
|
||||
_entityCache.Cleanup();
|
||||
_client.Room.Cleanup();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 SceneLoadHandler: Handler
|
||||
{
|
||||
private readonly RagonClient _client;
|
||||
private readonly RagonListenerList _listenerList;
|
||||
|
||||
public SceneLoadHandler(
|
||||
RagonClient ragonClient,
|
||||
RagonListenerList listenerList
|
||||
)
|
||||
{
|
||||
_client = ragonClient;
|
||||
_listenerList = listenerList;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var sceneName = buffer.ReadString();
|
||||
var room = _client.Room;
|
||||
|
||||
room.Cleanup();
|
||||
|
||||
_listenerList.OnLevel(sceneName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
internal class OwnershipHandler: Handler
|
||||
{
|
||||
private readonly RagonListenerList _listenerList;
|
||||
private readonly RagonPlayerCache _playerCache;
|
||||
private readonly RagonEntityCache _entityCache;
|
||||
|
||||
public OwnershipHandler(
|
||||
RagonListenerList listenerList,
|
||||
RagonPlayerCache playerCache,
|
||||
RagonEntityCache entityCache)
|
||||
{
|
||||
_listenerList = listenerList;
|
||||
_playerCache = playerCache;
|
||||
_entityCache = entityCache;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var newOwnerId = buffer.ReadString();
|
||||
var player = _playerCache.GetPlayerById(newOwnerId);
|
||||
|
||||
_playerCache.OnOwnershipChanged(newOwnerId);
|
||||
_listenerList.OnOwnershipChanged(player);
|
||||
|
||||
var entities = buffer.ReadUShort();
|
||||
for (var i = 0; i < entities; i++)
|
||||
{
|
||||
var entityId = buffer.ReadUShort();
|
||||
_entityCache.OnOwnershipChanged(player, entityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 PlayerJoinHandler : Handler
|
||||
{
|
||||
private RagonPlayerCache _playerCache;
|
||||
private RagonListenerList _listenerList;
|
||||
|
||||
public PlayerJoinHandler(
|
||||
RagonPlayerCache playerCache,
|
||||
RagonListenerList listenerList
|
||||
)
|
||||
{
|
||||
_playerCache = playerCache;
|
||||
_listenerList = listenerList;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var playerPeerId = buffer.ReadUShort();
|
||||
var playerId = buffer.ReadString();
|
||||
var playerName = buffer.ReadString();
|
||||
|
||||
_playerCache.AddPlayer(playerPeerId, playerId, playerName);
|
||||
|
||||
var player = _playerCache.GetPlayerById(playerId);
|
||||
if (player != null)
|
||||
_listenerList.OnPlayerJoined(player);
|
||||
else
|
||||
RagonLog.Trace($"[Joined] {playerId}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 PlayerLeftHandler : Handler
|
||||
{
|
||||
private RagonPlayerCache _playerCache;
|
||||
private RagonEntityCache _entityCache;
|
||||
private RagonListenerList _listenerList;
|
||||
|
||||
public PlayerLeftHandler(
|
||||
RagonEntityCache entityCache,
|
||||
RagonPlayerCache playerCache,
|
||||
RagonListenerList listenerList
|
||||
)
|
||||
{
|
||||
_entityCache = entityCache;
|
||||
_playerCache = playerCache;
|
||||
_listenerList = listenerList;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var playerId = buffer.ReadString();
|
||||
var player = _playerCache.GetPlayerById(playerId);
|
||||
if (player != null)
|
||||
{
|
||||
_playerCache.RemovePlayer(playerId);
|
||||
_listenerList.OnPlayerLeft(player);
|
||||
|
||||
var entities = buffer.ReadUShort();
|
||||
var toDeleteIds = new ushort[entities];
|
||||
for (var i = 0; i < entities; i++)
|
||||
{
|
||||
var entityId = buffer.ReadUShort();
|
||||
toDeleteIds[i] = entityId;
|
||||
}
|
||||
|
||||
foreach (var id in toDeleteIds)
|
||||
_entityCache.OnDestroy(id, new RagonPayload());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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 SnapshotHandler : Handler
|
||||
{
|
||||
private RagonClient _client;
|
||||
private RagonListenerList _listenerList;
|
||||
private RagonEntityCache _entityCache;
|
||||
private RagonPlayerCache _playerCache;
|
||||
|
||||
public SnapshotHandler(
|
||||
RagonClient ragonClient,
|
||||
RagonListenerList listenerList,
|
||||
RagonEntityCache entityCache,
|
||||
RagonPlayerCache playerCache
|
||||
)
|
||||
{
|
||||
_client = ragonClient;
|
||||
_listenerList = listenerList;
|
||||
_entityCache = entityCache;
|
||||
_playerCache = playerCache;
|
||||
}
|
||||
|
||||
public void Handle(RagonBuffer buffer)
|
||||
{
|
||||
var playersCount = buffer.ReadUShort();
|
||||
RagonLog.Trace("Players: " + playersCount);
|
||||
for (var i = 0; i < playersCount; i++)
|
||||
{
|
||||
var playerPeerId = buffer.ReadUShort();
|
||||
var playerId = buffer.ReadString();
|
||||
var playerName = buffer.ReadString();
|
||||
|
||||
_playerCache.AddPlayer(playerPeerId, playerId, playerName);
|
||||
}
|
||||
var dynamicEntities = buffer.ReadUShort();
|
||||
RagonLog.Trace("Dynamic Entities: " + dynamicEntities);
|
||||
for (var i = 0; i < dynamicEntities; i++)
|
||||
{
|
||||
var entityType = buffer.ReadUShort();
|
||||
var entityId = buffer.ReadUShort();
|
||||
var ownerPeerId = buffer.ReadUShort();
|
||||
var payloadSize = buffer.ReadUShort();
|
||||
var player = _playerCache.GetPlayerByPeer(ownerPeerId);
|
||||
|
||||
var payload = new RagonPayload(payloadSize);
|
||||
payload.Read(buffer);
|
||||
|
||||
var hasAuthority = _playerCache.LocalPlayer.Id == player.Id;
|
||||
var entity = _entityCache.OnCreate(0, entityType, 0, entityId, hasAuthority);
|
||||
|
||||
entity.Read(buffer);
|
||||
entity.Attach(_client, entityId, entityType, hasAuthority, player, payload);
|
||||
}
|
||||
|
||||
var staticEntities = buffer.ReadUShort();
|
||||
RagonLog.Trace("Scene Entities: " + staticEntities);
|
||||
for (var i = 0; i < staticEntities; i++)
|
||||
{
|
||||
var entityType = buffer.ReadUShort();
|
||||
var entityId = buffer.ReadUShort();
|
||||
var staticId = buffer.ReadUShort();
|
||||
var ownerPeerId = buffer.ReadUShort();
|
||||
var payloadSize = buffer.ReadUShort();
|
||||
var player = _playerCache.GetPlayerByPeer(ownerPeerId);
|
||||
|
||||
var payload = new RagonPayload(payloadSize);
|
||||
payload.Read(buffer);
|
||||
|
||||
var hasAuthority = _playerCache.LocalPlayer.Id == player.Id;
|
||||
var entity = _entityCache.OnCreate(0, entityType, staticId, entityId, hasAuthority);
|
||||
|
||||
entity.Read(buffer);
|
||||
entity.Attach(_client, entityId, entityType, hasAuthority, player, payload);
|
||||
}
|
||||
|
||||
_listenerList.OnJoined();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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,
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface INetworkChannel
|
||||
{
|
||||
void Send(byte[] data);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface INetworkConnection: IRagonConnection
|
||||
{
|
||||
public INetworkChannel Reliable { get; }
|
||||
public INetworkChannel Unreliable { get; }
|
||||
public Action<byte[]> OnData { get; set; }
|
||||
public Action OnConnected { get; set; }
|
||||
public Action<DisconnectReason> OnDisconnected { get; set; }
|
||||
public ulong BytesSent { get; }
|
||||
public ulong BytesReceived { get; }
|
||||
public int Ping { get; }
|
||||
public void Prepare();
|
||||
public void Connect(string address, ushort port, uint protocol);
|
||||
public void Disconnect();
|
||||
public void Update();
|
||||
public void Dispose();
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 class NetworkStatistics
|
||||
{
|
||||
private const double Interval = 1.0d;
|
||||
private double _upstreamBandwidth = 0d;
|
||||
private double _downstreamBandwidth = 0d;
|
||||
private double _time = 0d;
|
||||
private ulong _upstreamData = 0;
|
||||
private ulong _downstreamData = 0;
|
||||
private ulong _sent = 0;
|
||||
private ulong _received = 0;
|
||||
private int _ping;
|
||||
|
||||
public int Ping => _ping;
|
||||
public double UpstreamBandwidth => _upstreamBandwidth;
|
||||
public double DownstreamBandwidth => _downstreamBandwidth;
|
||||
|
||||
public void Update(ulong sent, ulong received, int ping, float dt)
|
||||
{
|
||||
_sent = sent;
|
||||
_received = received;
|
||||
_ping = ping;
|
||||
|
||||
_time += dt;
|
||||
if (_time >= Interval)
|
||||
{
|
||||
if (_upstreamData > 0)
|
||||
{
|
||||
_upstreamData = _sent - _upstreamData;
|
||||
_upstreamBandwidth = (_upstreamData / _time) / 1000 ;
|
||||
}
|
||||
|
||||
if (_downstreamData > 0)
|
||||
{
|
||||
_downstreamData = _received - _downstreamData;
|
||||
_downstreamBandwidth = (_downstreamData / _time) / 1000;
|
||||
}
|
||||
|
||||
_upstreamData = _sent;
|
||||
_downstreamData = _received;
|
||||
_time -= Interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonConnection
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonEntityListener
|
||||
{
|
||||
public void OnEntityCreated(RagonEntity entity);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client
|
||||
{
|
||||
public interface IRagonEvent: IRagonSerializable
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client
|
||||
{
|
||||
public interface IRagonPayload: IRagonSerializable
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonSceneCollector
|
||||
{
|
||||
public RagonEntity[] Collect();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonAuthorizationListener
|
||||
{
|
||||
void OnAuthorizationSuccess(RagonClient client, string playerId, string playerName);
|
||||
void OnAuthorizationFailed(RagonClient client, string message);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonConnectedListener
|
||||
{
|
||||
void OnConnected(RagonClient client);
|
||||
void OnDisconnected(RagonClient client);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonFailedListener
|
||||
{
|
||||
void OnFailed(RagonClient client, string message);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonJoinListener
|
||||
{
|
||||
void OnJoined(RagonClient client);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonLeftListener
|
||||
{
|
||||
void OnLeft(RagonClient client);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonLevelListener
|
||||
{
|
||||
void OnLevel(RagonClient client, string sceneName);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client
|
||||
{
|
||||
public interface IRagonListener :
|
||||
IRagonAuthorizationListener,
|
||||
IRagonConnectedListener,
|
||||
IRagonFailedListener,
|
||||
IRagonJoinListener,
|
||||
IRagonLeftListener,
|
||||
IRagonLevelListener,
|
||||
IRagonOwnershipChangedListener,
|
||||
IRagonPlayerJoinListener,
|
||||
IRagonPlayerLeftListener
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonOwnershipChangedListener
|
||||
{
|
||||
void OnOwnershipChanged(RagonClient client, RagonPlayer player);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonPlayerJoinListener
|
||||
{
|
||||
void OnPlayerJoined(RagonClient client, RagonPlayer player);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public interface IRagonPlayerLeftListener
|
||||
{
|
||||
void OnPlayerLeft(RagonClient client, RagonPlayer player);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Ragon.Client
|
||||
{
|
||||
public interface IRagonLogger
|
||||
{
|
||||
public void Warn(string message);
|
||||
public void Trace(string message);
|
||||
public void Info(string message);
|
||||
public void Error(string message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 class RagonConsoleLogger: IRagonLogger
|
||||
{
|
||||
public void Warn(string message)
|
||||
{
|
||||
Console.WriteLine($"[WARN] {message}");
|
||||
}
|
||||
|
||||
public void Trace(string message)
|
||||
{
|
||||
Console.WriteLine($"[TRACE] {message}");
|
||||
}
|
||||
|
||||
public void Info(string message)
|
||||
{
|
||||
Console.WriteLine($"[INFO] {message}");
|
||||
}
|
||||
|
||||
public void Error(string message)
|
||||
{
|
||||
Console.WriteLine($"[ERROR] {message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 class RagonLog
|
||||
{
|
||||
private static IRagonLogger _ragonLogger;
|
||||
static RagonLog() => _ragonLogger = new RagonConsoleLogger();
|
||||
public static void Set(IRagonLogger logger) => _ragonLogger = logger;
|
||||
public static void Warn(string message) => _ragonLogger.Warn(message);
|
||||
public static void Trace(string message) => _ragonLogger.Trace(message);
|
||||
public static void Info(string message) => _ragonLogger.Info(message);
|
||||
public static void Error(string message) => _ragonLogger.Error(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 RagonLogLevel
|
||||
{
|
||||
ALL,
|
||||
CONNECTION,
|
||||
STATE,
|
||||
EVENT,
|
||||
ROOM,
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client
|
||||
{
|
||||
public sealed class RagonClient
|
||||
{
|
||||
private readonly INetworkConnection _connection;
|
||||
private readonly IRagonEntityListener _entityListener;
|
||||
private readonly IRagonSceneCollector _sceneCollector;
|
||||
private Handler[] _processors;
|
||||
private RagonBuffer _readBuffer;
|
||||
private RagonBuffer _writeBuffer;
|
||||
private RagonRoom _room;
|
||||
private RagonSession _session;
|
||||
private RagonListenerList _listenerList;
|
||||
private RagonPlayerCache _playerCache;
|
||||
private RagonEntityCache _entityCache;
|
||||
private RagonEventCache _eventCache;
|
||||
private RagonStatus _status;
|
||||
private NetworkStatistics _stats;
|
||||
|
||||
private float _replicatationRate = 0;
|
||||
private float _replicatationTime = 0;
|
||||
|
||||
public IRagonConnection Connection => _connection;
|
||||
public RagonStatus Status => _status;
|
||||
public RagonSession Session => _session;
|
||||
public RagonEventCache Event => _eventCache;
|
||||
public RagonEntityCache Entity => _entityCache;
|
||||
public NetworkStatistics Statistics => _stats;
|
||||
public RagonRoom Room => _room;
|
||||
|
||||
internal RagonBuffer Buffer => _writeBuffer;
|
||||
internal INetworkChannel Reliable => _connection.Reliable;
|
||||
internal INetworkChannel Unreliable => _connection.Unreliable;
|
||||
|
||||
#region PUBLIC
|
||||
|
||||
public RagonClient(
|
||||
INetworkConnection connection,
|
||||
IRagonEntityListener entityListener,
|
||||
IRagonSceneCollector sceneCollector,
|
||||
int rate)
|
||||
{
|
||||
_listenerList = new RagonListenerList(this);
|
||||
_entityListener = entityListener;
|
||||
_sceneCollector = sceneCollector;
|
||||
|
||||
_connection = connection;
|
||||
_connection.OnData += OnData;
|
||||
_connection.OnConnected += OnConnected;
|
||||
_connection.OnDisconnected += OnDisconnected;
|
||||
|
||||
_replicatationRate = (1000.0f / rate) / 1000.0f;
|
||||
_replicatationTime = 0;
|
||||
|
||||
_eventCache = new RagonEventCache();
|
||||
_stats = new NetworkStatistics();
|
||||
_status = RagonStatus.DISCONNECTED;
|
||||
}
|
||||
|
||||
public void AddListener(IRagonListener listener)
|
||||
{
|
||||
_listenerList.Add(listener);
|
||||
}
|
||||
|
||||
public void RemoveListener(IRagonListener listener)
|
||||
{
|
||||
_listenerList.Remove(listener);
|
||||
}
|
||||
|
||||
public void Connect(string address, ushort port, string protocol)
|
||||
{
|
||||
_writeBuffer = new RagonBuffer();
|
||||
_readBuffer = new RagonBuffer();
|
||||
_session = new RagonSession(this, _readBuffer);
|
||||
|
||||
_playerCache = new RagonPlayerCache();
|
||||
_entityCache = new RagonEntityCache(this, _playerCache, _entityListener, _sceneCollector);
|
||||
|
||||
_processors = new Handler[byte.MaxValue];
|
||||
_processors[(byte)RagonOperation.AUTHORIZED_SUCCESS] = new AuthorizeSuccessHandler(_listenerList);
|
||||
_processors[(byte)RagonOperation.AUTHORIZED_FAILED] = new AuthorizeFailedHandler(_listenerList);
|
||||
_processors[(byte)RagonOperation.JOIN_SUCCESS] =
|
||||
new JoinSuccessHandler(this, _readBuffer, _listenerList, _playerCache, _entityCache);
|
||||
_processors[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(_listenerList);
|
||||
_processors[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, _listenerList, _entityCache);
|
||||
_processors[(byte)RagonOperation.OWNERSHIP_CHANGED] =
|
||||
new OwnershipHandler(_listenerList, _playerCache, _entityCache);
|
||||
_processors[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, _listenerList);
|
||||
_processors[(byte)RagonOperation.PLAYER_LEAVED] =
|
||||
new PlayerLeftHandler(_entityCache, _playerCache, _listenerList);
|
||||
_processors[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, _listenerList);
|
||||
_processors[(byte)RagonOperation.CREATE_ENTITY] = new EntityCreateHandler(this, _playerCache, _entityCache);
|
||||
_processors[(byte)RagonOperation.DESTROY_ENTITY] = new EntityDestroyHandler(_entityCache);
|
||||
_processors[(byte)RagonOperation.REPLICATE_ENTITY_STATE] = new StateEntityHandler(_entityCache);
|
||||
_processors[(byte)RagonOperation.REPLICATE_ENTITY_EVENT] =
|
||||
new EntityEventHandler(this, _playerCache, _entityCache);
|
||||
_processors[(byte)RagonOperation.SNAPSHOT] =
|
||||
new SnapshotHandler(this, _listenerList, _entityCache, _playerCache);
|
||||
|
||||
var protocolRaw = RagonVersion.Parse(protocol);
|
||||
_connection.Connect(address, port, protocolRaw);
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
_status = RagonStatus.DISCONNECTED;
|
||||
_room.Cleanup();
|
||||
_connection.Disconnect();
|
||||
OnDisconnected(DisconnectReason.MANUAL);
|
||||
}
|
||||
|
||||
public void Update(float dt)
|
||||
{
|
||||
_replicatationTime += dt;
|
||||
if (_replicatationTime >= _replicatationRate)
|
||||
{
|
||||
_entityCache.WriteState(_readBuffer);
|
||||
_replicatationTime = 0;
|
||||
}
|
||||
|
||||
_stats.Update(_connection.BytesSent, _connection.BytesReceived, _connection.Ping, dt);
|
||||
_connection.Update();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_status = RagonStatus.DISCONNECTED;
|
||||
_connection.Disconnect();
|
||||
_connection.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region INTERNAL
|
||||
|
||||
internal void AssignRoom(RagonRoom room)
|
||||
{
|
||||
_room = room;
|
||||
_status = RagonStatus.ROOM;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PRIVATE
|
||||
|
||||
private void OnConnected()
|
||||
{
|
||||
RagonLog.Trace("Connected");
|
||||
|
||||
_listenerList.OnConnected();
|
||||
_status = RagonStatus.CONNECTED;
|
||||
}
|
||||
|
||||
private void OnDisconnected(DisconnectReason reason)
|
||||
{
|
||||
RagonLog.Trace($"Disconnected: {reason}");
|
||||
|
||||
_listenerList.OnDisconnected();
|
||||
_status = RagonStatus.DISCONNECTED;
|
||||
}
|
||||
|
||||
public void OnData(byte[] data)
|
||||
{
|
||||
_readBuffer.Clear();
|
||||
_readBuffer.FromArray(data);
|
||||
|
||||
var operation = _readBuffer.ReadByte();
|
||||
_processors[operation].Handle(_readBuffer);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public sealed class RagonEntityCache
|
||||
{
|
||||
private readonly List<RagonEntity> _entityList = new();
|
||||
private readonly Dictionary<uint, RagonEntity> _entityMap = new();
|
||||
private readonly Dictionary<uint, RagonEntity> _pendingEntities = new();
|
||||
private readonly Dictionary<uint, RagonEntity> _sceneEntities = new();
|
||||
|
||||
private readonly RagonClient _client;
|
||||
private readonly IRagonEntityListener _entityListener;
|
||||
private readonly IRagonSceneCollector _sceneCollector;
|
||||
private readonly RagonPlayerCache _playerCache;
|
||||
|
||||
private int _localEntitiesCounter = 0;
|
||||
|
||||
public RagonEntityCache(
|
||||
RagonClient client,
|
||||
RagonPlayerCache playerCache,
|
||||
IRagonEntityListener listener,
|
||||
IRagonSceneCollector sceneCollector
|
||||
)
|
||||
{
|
||||
_client = client;
|
||||
_entityListener = listener;
|
||||
_sceneCollector = sceneCollector;
|
||||
_playerCache = playerCache;
|
||||
}
|
||||
|
||||
public RagonEntity FindById(ushort id)
|
||||
{
|
||||
return _entityMap[id];
|
||||
}
|
||||
|
||||
public void Create(RagonEntity entity, IRagonPayload? spawnPayload)
|
||||
{
|
||||
var attachId = (ushort) (_playerCache.LocalPlayer.PeerId + _localEntitiesCounter++) ;
|
||||
var buffer = _client.Buffer;
|
||||
|
||||
buffer.Clear();
|
||||
buffer.WriteOperation(RagonOperation.CREATE_ENTITY);
|
||||
buffer.WriteUShort(attachId);
|
||||
buffer.WriteUShort(entity.Type);
|
||||
buffer.WriteByte((byte) entity.Authority);
|
||||
|
||||
entity.State.WriteInfo(buffer);
|
||||
|
||||
spawnPayload?.Serialize(buffer);
|
||||
|
||||
_pendingEntities.Add(attachId, entity);
|
||||
|
||||
var sendData = buffer.ToArray();
|
||||
_client.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
public void Destroy(RagonEntity entity, IRagonPayload? destroyPayload)
|
||||
{
|
||||
if (!entity.IsAttached)
|
||||
{
|
||||
RagonLog.Warn("Can't destroy object, he is not created");
|
||||
return;
|
||||
}
|
||||
var buffer = _client.Buffer;
|
||||
|
||||
buffer.Clear();
|
||||
buffer.WriteOperation(RagonOperation.DESTROY_ENTITY);
|
||||
buffer.WriteUShort(entity.Id);
|
||||
|
||||
destroyPayload?.Serialize(buffer);
|
||||
|
||||
var sendData = buffer.ToArray();
|
||||
_client.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
internal void WriteState(RagonBuffer buffer)
|
||||
{
|
||||
var changedEntities = 0u;
|
||||
|
||||
buffer.Clear();
|
||||
buffer.WriteOperation(RagonOperation.REPLICATE_ENTITY_STATE);
|
||||
|
||||
var offset = buffer.WriteOffset;
|
||||
buffer.Write(0, 16);
|
||||
|
||||
foreach (var ent in _entityList)
|
||||
{
|
||||
if (!ent.IsAttached ||
|
||||
!ent.Replication ||
|
||||
!ent.PropertiesChanged) continue;
|
||||
|
||||
ent.Write(buffer);
|
||||
|
||||
changedEntities++;
|
||||
}
|
||||
|
||||
if (changedEntities <= 0) return;
|
||||
|
||||
buffer.Write(changedEntities, 16, offset);
|
||||
|
||||
var data = buffer.ToArray();
|
||||
_client.Unreliable.Send(data);
|
||||
}
|
||||
|
||||
internal void WriteScene(RagonBuffer buffer)
|
||||
{
|
||||
_sceneEntities.Clear();
|
||||
|
||||
var entities = _sceneCollector.Collect();
|
||||
buffer.WriteUShort((ushort) entities.Length);
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
buffer.WriteUShort(entity.Type);
|
||||
buffer.WriteByte((byte) entity.Authority);
|
||||
buffer.WriteUShort(entity.SceneId);
|
||||
|
||||
entity.State.WriteInfo(buffer);
|
||||
|
||||
_sceneEntities.Add(entity.SceneId, entity);
|
||||
}
|
||||
}
|
||||
|
||||
internal void CacheScene()
|
||||
{
|
||||
_sceneEntities.Clear();
|
||||
|
||||
var entities = _sceneCollector.Collect();
|
||||
foreach (var entity in entities)
|
||||
_sceneEntities.Add(entity.SceneId, entity);
|
||||
}
|
||||
|
||||
internal void Cleanup()
|
||||
{
|
||||
var payload = new RagonPayload();
|
||||
foreach (var ent in _entityList)
|
||||
ent.Detach(payload);
|
||||
|
||||
_entityMap.Clear();
|
||||
_entityList.Clear();
|
||||
}
|
||||
|
||||
internal RagonEntity OnCreate(ushort attachId, ushort entityType, ushort sceneId, ushort entityId, bool hasAuthority)
|
||||
{
|
||||
if (sceneId > 0)
|
||||
{
|
||||
if (_sceneEntities.TryGetValue(sceneId, out var entity))
|
||||
{
|
||||
_entityMap.Add(entityId, entity);
|
||||
|
||||
if (hasAuthority)
|
||||
_entityList.Add(entity);
|
||||
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
if (_pendingEntities.Remove(attachId, out var existsEntity))
|
||||
{
|
||||
_entityMap.Add(entityId, existsEntity);
|
||||
|
||||
if (hasAuthority)
|
||||
_entityList.Add(existsEntity);
|
||||
|
||||
return existsEntity;
|
||||
}
|
||||
else
|
||||
{
|
||||
var entity = new RagonEntity(entityType, sceneId);
|
||||
|
||||
_entityMap.Add(entityId, entity);
|
||||
|
||||
if (hasAuthority)
|
||||
_entityList.Add(entity);
|
||||
|
||||
_entityListener.OnEntityCreated(entity);
|
||||
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal void OnDestroy(ushort entityId, RagonPayload payload)
|
||||
{
|
||||
if (_entityMap.Remove(entityId, out var ragonEntity))
|
||||
{
|
||||
_entityList.Remove(ragonEntity);
|
||||
|
||||
ragonEntity.Detach(payload);
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnState(ushort entityId, RagonBuffer buffer)
|
||||
{
|
||||
if (_entityMap.TryGetValue(entityId, out var entity))
|
||||
entity.Read(buffer);
|
||||
else
|
||||
RagonLog.Warn($"Entity {entityId} not found!");
|
||||
}
|
||||
|
||||
internal void OnEvent(RagonPlayer player, ushort entityId, ushort eventCode, RagonBuffer buffer)
|
||||
{
|
||||
if (_entityMap.TryGetValue(entityId, out var entity))
|
||||
entity.Event(eventCode, player, buffer);
|
||||
else
|
||||
RagonLog.Warn($"Entity {entityId} not found!");
|
||||
}
|
||||
|
||||
internal void OnOwnershipChanged(RagonPlayer player, ushort entityId)
|
||||
{
|
||||
if (_entityMap.TryGetValue(entityId, out var entity))
|
||||
entity.OnOwnershipChanged(player);
|
||||
else
|
||||
RagonLog.Warn($"Entity {entityId} not found!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 class RagonEventCache
|
||||
{
|
||||
private readonly Dictionary<Type, ushort> _eventsRegistryByType = new();
|
||||
private readonly HashSet<ushort> _codes = new();
|
||||
private readonly HashSet<Type> _types = new();
|
||||
private ushort _eventIdGenerator = 0;
|
||||
|
||||
public ushort GetEventCode<TEvent>(TEvent _) where TEvent : IRagonEvent
|
||||
{
|
||||
var type = typeof(TEvent);
|
||||
var evntCode = _eventsRegistryByType[type];
|
||||
return evntCode;
|
||||
}
|
||||
|
||||
public void Register<T>() where T : IRagonEvent, new()
|
||||
{
|
||||
var type = typeof(T);
|
||||
if (_types.Contains(type))
|
||||
{
|
||||
RagonLog.Trace($"[Ragon] Event already registered: {type.Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
RagonLog.Trace($"[Ragon] Registered Event: {type.Name} - {_eventIdGenerator}");
|
||||
|
||||
_eventsRegistryByType.Add(type, _eventIdGenerator);
|
||||
_codes.Add(_eventIdGenerator);
|
||||
_types.Add(type);
|
||||
|
||||
_eventIdGenerator++;
|
||||
}
|
||||
|
||||
public void Register<T>(ushort evntCode) where T : IRagonEvent, new()
|
||||
{
|
||||
var type = typeof(T);
|
||||
if (_codes.Contains(evntCode) || _types.Contains(type))
|
||||
{
|
||||
RagonLog.Warn($"[Ragon] Event already registered: {type.Name} - {evntCode}");
|
||||
return;
|
||||
}
|
||||
|
||||
RagonLog.Trace($"[Ragon] Registered Event: {type.Name} - {evntCode}");
|
||||
|
||||
_codes.Add(evntCode);
|
||||
_types.Add(type);
|
||||
_eventsRegistryByType.Add(type, evntCode);
|
||||
}
|
||||
|
||||
public T Create<T>() where T : IRagonEvent, new()
|
||||
{
|
||||
return new T();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
internal class RagonListenerList
|
||||
{
|
||||
public int Count => _listeners.Count;
|
||||
private List<IRagonListener> _listeners = new();
|
||||
private RagonClient _client;
|
||||
|
||||
public RagonListenerList(RagonClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public void Add(IRagonListener listener)
|
||||
{
|
||||
_listeners.Add(listener);
|
||||
}
|
||||
|
||||
public void Remove(IRagonListener listener)
|
||||
{
|
||||
_listeners.Remove(listener);
|
||||
}
|
||||
|
||||
public void OnAuthorizationSuccess(string playerId, string playerName)
|
||||
{
|
||||
foreach (var listener in _listeners)
|
||||
listener.OnAuthorizationSuccess(_client, playerId, playerName);
|
||||
}
|
||||
|
||||
public void OnAuthorizationFailed(string message)
|
||||
{
|
||||
foreach (var listener in _listeners)
|
||||
listener.OnAuthorizationFailed(_client, message);
|
||||
}
|
||||
|
||||
public void OnLeft()
|
||||
{
|
||||
foreach (var listener in _listeners)
|
||||
listener.OnLeft(_client);
|
||||
}
|
||||
|
||||
public void OnFailed(string message)
|
||||
{
|
||||
foreach (var listener in _listeners)
|
||||
listener.OnFailed(_client, message);
|
||||
}
|
||||
|
||||
public void OnOwnershipChanged(RagonPlayer player)
|
||||
{
|
||||
foreach (var listener in _listeners)
|
||||
listener.OnOwnershipChanged(_client, player);
|
||||
}
|
||||
|
||||
public void OnPlayerLeft(RagonPlayer player)
|
||||
{
|
||||
foreach (var listener in _listeners)
|
||||
listener.OnPlayerLeft(_client, player);
|
||||
}
|
||||
|
||||
public void OnPlayerJoined(RagonPlayer player)
|
||||
{
|
||||
foreach (var listener in _listeners)
|
||||
listener.OnPlayerJoined(_client, player);
|
||||
}
|
||||
|
||||
public void OnLevel(string sceneName)
|
||||
{
|
||||
foreach (var listener in _listeners)
|
||||
listener.OnLevel(_client, sceneName);
|
||||
}
|
||||
|
||||
public void OnJoined()
|
||||
{
|
||||
foreach (var listener in _listeners)
|
||||
listener.OnJoined(_client);
|
||||
}
|
||||
|
||||
public void OnConnected()
|
||||
{
|
||||
foreach (var listener in _listeners)
|
||||
listener.OnConnected(_client);
|
||||
}
|
||||
|
||||
public void OnDisconnected()
|
||||
{
|
||||
foreach (var listener in _listeners)
|
||||
listener.OnDisconnected(_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
[Serializable]
|
||||
public class RagonPlayer
|
||||
{
|
||||
public string Id { get; private set; }
|
||||
public string Name { get; set; }
|
||||
public ushort PeerId { get; set; }
|
||||
public bool IsRoomOwner { get; set; }
|
||||
public bool IsMe { get; set; }
|
||||
|
||||
public RagonPlayer(ushort peerId, string playerId, string name, bool isRoomOwner, bool isMe)
|
||||
{
|
||||
PeerId = peerId;
|
||||
IsRoomOwner = isRoomOwner;
|
||||
IsMe = isMe;
|
||||
Name = name;
|
||||
Id = playerId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 sealed class RagonPlayerCache
|
||||
{
|
||||
private List<RagonPlayer> _players = new List<RagonPlayer>();
|
||||
private Dictionary<string, RagonPlayer> _playersById = new();
|
||||
private Dictionary<ushort, RagonPlayer> _playersByConnection = new();
|
||||
|
||||
public RagonPlayer Owner { get; private set; }
|
||||
public RagonPlayer LocalPlayer { get; private set; }
|
||||
public bool IsRoomOwner => _ownerId == _localId;
|
||||
|
||||
public RagonPlayer? GetPlayerById(string playerId) => _playersById[playerId];
|
||||
public RagonPlayer? GetPlayerByPeer(ushort peerId) => _playersByConnection[peerId];
|
||||
|
||||
private string _ownerId;
|
||||
private string _localId;
|
||||
|
||||
public void SetOwnerAndLocal(string ownerId, string localId)
|
||||
{
|
||||
_ownerId = ownerId;
|
||||
_localId = localId;
|
||||
}
|
||||
|
||||
public void AddPlayer(ushort peerId, string playerId, string playerName)
|
||||
{
|
||||
if (_playersById.ContainsKey(playerId))
|
||||
return;
|
||||
|
||||
var isOwner = playerId == _ownerId;
|
||||
var isLocal = playerId == _localId;
|
||||
|
||||
RagonLog.Trace($"Added player {peerId}|{playerId}|{playerName} IsOwner: {isOwner} isLocal: {isLocal}");
|
||||
|
||||
var player = new RagonPlayer(peerId, playerId, playerName, isOwner, isLocal);
|
||||
|
||||
if (player.IsMe)
|
||||
LocalPlayer = player;
|
||||
|
||||
if (player.IsRoomOwner)
|
||||
Owner = player;
|
||||
|
||||
_players.Add(player);
|
||||
_playersById.Add(player.Id, player);
|
||||
_playersByConnection.Add(player.PeerId, player);
|
||||
}
|
||||
|
||||
public void RemovePlayer(string playerId)
|
||||
{
|
||||
if (_playersById.Remove(playerId, out var player))
|
||||
{
|
||||
_players.Remove(player);
|
||||
_playersByConnection.Remove(player.PeerId);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnOwnershipChanged(string playerId)
|
||||
{
|
||||
foreach (var player in _players)
|
||||
{
|
||||
if (player.Id == playerId)
|
||||
Owner = player;
|
||||
player.IsRoomOwner = player.Id == playerId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
_players.Clear();
|
||||
_playersByConnection.Clear();
|
||||
_playersById.Clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 class RagonRoom
|
||||
{
|
||||
private RagonClient _client;
|
||||
private RagonScene _scene;
|
||||
private RagonEntityCache _entityCache;
|
||||
private RagonPlayerCache _playerCache;
|
||||
private RagonRoomInformation _information;
|
||||
|
||||
public string Id => _information.RoomId;
|
||||
public int MinPlayers => _information.Min;
|
||||
public int MaxPlayers => _information.Max;
|
||||
|
||||
public RagonPlayer Local => _playerCache.LocalPlayer;
|
||||
public RagonPlayer Owner => _playerCache.Owner;
|
||||
|
||||
public RagonRoom(RagonClient client,
|
||||
RagonEntityCache entityCache,
|
||||
RagonPlayerCache playerCache,
|
||||
RagonRoomInformation information,
|
||||
RagonScene scene)
|
||||
{
|
||||
_client = client;
|
||||
_information = information;
|
||||
_entityCache = entityCache;
|
||||
_playerCache = playerCache;
|
||||
_scene = scene;
|
||||
}
|
||||
|
||||
internal void Cleanup()
|
||||
{
|
||||
_entityCache.Cleanup();
|
||||
_playerCache.Cleanup();
|
||||
}
|
||||
|
||||
public void LoadScene(string map) => _scene.Load(map);
|
||||
public void SceneLoaded() => _scene.SceneLoaded();
|
||||
|
||||
public void CreateEntity(RagonEntity entity) => CreateEntity(entity, null);
|
||||
public void CreateEntity(RagonEntity entity, IRagonPayload? payload) => _entityCache.Create(entity, payload);
|
||||
|
||||
public void DestroyEntity(RagonEntity entityId) => DestroyEntity(entityId, null);
|
||||
public void DestroyEntity(RagonEntity entityId, IRagonPayload? payload) => _entityCache.Destroy(entityId, payload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client;
|
||||
|
||||
public class RagonScene
|
||||
{
|
||||
private readonly RagonClient _client;
|
||||
private readonly RagonEntityCache _entityCache;
|
||||
private readonly RagonPlayerCache _playerCache;
|
||||
|
||||
public RagonScene(RagonClient client, RagonPlayerCache playerCache, RagonEntityCache entityCache)
|
||||
{
|
||||
_client = client;
|
||||
_playerCache = playerCache;
|
||||
_entityCache = entityCache;
|
||||
}
|
||||
|
||||
internal void Load(string map)
|
||||
{
|
||||
var buffer = _client.Buffer;
|
||||
|
||||
buffer.Clear();
|
||||
buffer.WriteOperation(RagonOperation.LOAD_SCENE);
|
||||
buffer.WriteString(map);
|
||||
|
||||
var sendData = buffer.ToArray();
|
||||
_client.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
internal void SceneLoaded()
|
||||
{
|
||||
var buffer = _client.Buffer;
|
||||
|
||||
buffer.Clear();
|
||||
buffer.WriteOperation(RagonOperation.SCENE_LOADED);
|
||||
|
||||
if (_playerCache.IsRoomOwner)
|
||||
_entityCache.WriteScene(buffer);
|
||||
else
|
||||
_entityCache.CacheScene();
|
||||
|
||||
var sendData = buffer.ToArray();
|
||||
_client.Reliable.Send(sendData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Client
|
||||
{
|
||||
public class RagonSession
|
||||
{
|
||||
private readonly RagonClient _client;
|
||||
private readonly RagonBuffer _buffer;
|
||||
|
||||
public RagonSession(RagonClient client, RagonBuffer buffer)
|
||||
{
|
||||
_client = client;
|
||||
_buffer = buffer;
|
||||
}
|
||||
|
||||
public void CreateOrJoin(string map, int minPlayers, int maxPlayers)
|
||||
{
|
||||
var parameters = new RagonRoomParameters() {Map = map, Min = minPlayers, Max = maxPlayers};
|
||||
CreateOrJoin(parameters);
|
||||
}
|
||||
|
||||
public void CreateOrJoin(RagonRoomParameters parameters)
|
||||
{
|
||||
_buffer.Clear();
|
||||
_buffer.WriteOperation(RagonOperation.JOIN_OR_CREATE_ROOM);
|
||||
|
||||
parameters.Serialize(_buffer);
|
||||
|
||||
var sendData = _buffer.ToArray();
|
||||
_client.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
public void Create(string map, int minPlayers, int maxPlayers)
|
||||
{
|
||||
Create(null, new RagonRoomParameters() {Map = map, Min = minPlayers, Max = maxPlayers});
|
||||
}
|
||||
|
||||
public void Create(string roomId, string map, int minPlayers, int maxPlayers)
|
||||
{
|
||||
Create(roomId, new RagonRoomParameters() {Map = map, Min = minPlayers, Max = maxPlayers});
|
||||
}
|
||||
|
||||
public void Create(string roomId, RagonRoomParameters parameters)
|
||||
{
|
||||
_buffer.Clear();
|
||||
_buffer.WriteOperation(RagonOperation.CREATE_ROOM);
|
||||
|
||||
if (roomId != null)
|
||||
{
|
||||
_buffer.WriteBool(true);
|
||||
_buffer.WriteString(roomId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffer.WriteBool(false);
|
||||
}
|
||||
|
||||
parameters.Serialize(_buffer);
|
||||
|
||||
var sendData = _buffer.ToArray();
|
||||
_client.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
public void Leave()
|
||||
{
|
||||
var sendData = new[] {(byte) RagonOperation.LEAVE_ROOM};
|
||||
_client.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
public void Join(string roomId)
|
||||
{
|
||||
_buffer.Clear();
|
||||
_buffer.WriteOperation(RagonOperation.JOIN_ROOM);
|
||||
_buffer.WriteString(roomId);
|
||||
|
||||
var sendData = _buffer.ToArray();
|
||||
_client.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
public void AuthorizeWithKey(string key, string playerName, byte[] additonalData)
|
||||
{
|
||||
_buffer.Clear();
|
||||
_buffer.WriteOperation(RagonOperation.AUTHORIZE);
|
||||
_buffer.WriteString(key);
|
||||
_buffer.WriteString(playerName);
|
||||
_buffer.WriteBytes(additonalData);
|
||||
|
||||
var sendData = _buffer.ToArray();
|
||||
_client.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 RagonStatus
|
||||
{
|
||||
DISCONNECTED,
|
||||
CONNECTED,
|
||||
ROOM,
|
||||
LOBBY,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user