Files
Ragon/Ragon.Client/Sources/RagonClient.cs
T

261 lines
9.6 KiB
C#
Raw Permalink Normal View History

2023-03-06 10:06:43 +04:00
/*
* 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;
2023-07-30 21:19:39 +03:00
private readonly NetworkStatistics _stats;
2023-07-09 07:40:06 +03:00
private IRagonEntityListener _entityListener;
private IRagonSceneCollector _sceneCollector;
2023-10-04 14:42:59 +03:00
private IHandler[] _handlers;
2023-03-06 10:06:43 +04:00
private RagonBuffer _readBuffer;
private RagonBuffer _writeBuffer;
private RagonRoom _room;
private RagonSession _session;
2023-07-30 21:19:39 +03:00
private RagonListenerList listeners;
2023-03-06 10:06:43 +04:00
private RagonPlayerCache _playerCache;
private RagonEntityCache _entityCache;
private RagonEventCache _eventCache;
private RagonStatus _status;
2023-07-30 21:46:42 +03:00
2023-10-04 14:42:59 +03:00
private double _serverTimestamp;
2023-03-06 10:29:22 +04:00
private float _replicationRate = 0;
private float _replicationTime = 0;
2023-03-06 10:06:43 +04:00
2023-10-04 14:42:59 +03:00
public double ServerTimestamp => _serverTimestamp;
2023-03-06 10:06:43 +04:00
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;
2023-10-04 14:42:59 +03:00
2023-03-06 10:06:43 +04:00
internal RagonBuffer Buffer => _writeBuffer;
internal INetworkChannel Reliable => _connection.Reliable;
internal INetworkChannel Unreliable => _connection.Unreliable;
#region PUBLIC
2023-07-09 07:40:06 +03:00
public RagonClient(INetworkConnection connection, int rate)
2023-03-06 10:06:43 +04:00
{
2023-10-11 19:37:50 +03:00
listeners = new RagonListenerList(this);
2023-03-06 10:06:43 +04:00
_connection = connection;
_connection.OnData += OnData;
_connection.OnConnected += OnConnected;
_connection.OnDisconnected += OnDisconnected;
2023-10-11 19:37:50 +03:00
2023-03-06 10:29:22 +04:00
_replicationRate = (1000.0f / rate) / 1000.0f;
_replicationTime = 0;
2023-03-06 10:06:43 +04:00
_eventCache = new RagonEventCache();
_stats = new NetworkStatistics();
_status = RagonStatus.DISCONNECTED;
}
2023-07-09 07:40:06 +03:00
public void Configure(IRagonSceneCollector sceneCollector)
{
_sceneCollector = sceneCollector;
}
public void Configure(IRagonEntityListener listener)
{
_entityListener = listener;
}
2023-07-30 21:46:42 +03:00
2023-03-06 10:06:43 +04:00
public void Connect(string address, ushort port, string protocol)
{
2023-07-09 07:40:06 +03:00
if (_sceneCollector == null)
{
RagonLog.Error("Scene collector is not defined!");
return;
}
if (_entityListener == null)
{
RagonLog.Error("Entity Listener is not defined!");
return;
}
2023-07-30 21:46:42 +03:00
2023-03-06 10:06:43 +04:00
_writeBuffer = new RagonBuffer();
_readBuffer = new RagonBuffer();
2023-10-04 14:42:59 +03:00
_session = new RagonSession(this, _writeBuffer);
2023-03-06 10:06:43 +04:00
_playerCache = new RagonPlayerCache();
2023-07-29 10:58:06 +03:00
_entityCache = new RagonEntityCache(this, _playerCache, _sceneCollector);
2023-03-06 10:06:43 +04:00
2023-10-04 14:42:59 +03:00
_handlers = new IHandler[byte.MaxValue];
2023-07-30 21:46:42 +03:00
_handlers[(byte)RagonOperation.AUTHORIZED_SUCCESS] = new AuthorizeSuccessHandler(this, listeners);
2023-07-30 21:19:39 +03:00
_handlers[(byte)RagonOperation.AUTHORIZED_FAILED] = new AuthorizeFailedHandler(listeners);
2023-10-04 14:42:59 +03:00
_handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, listeners, _playerCache, _entityCache);
2023-07-30 21:19:39 +03:00
_handlers[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(listeners);
_handlers[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, listeners, _entityCache);
_handlers[(byte)RagonOperation.OWNERSHIP_ROOM_CHANGED] = new OwnershipRoomHandler(listeners, _playerCache, _entityCache);
_handlers[(byte)RagonOperation.OWNERSHIP_ENTITY_CHANGED] = new EntityOwnershipHandler(listeners, _playerCache, _entityCache);
_handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, listeners);
_handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_entityCache, _playerCache, listeners);
_handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, listeners);
2023-07-29 10:58:06 +03:00
_handlers[(byte)RagonOperation.CREATE_ENTITY] = new EntityCreateHandler(this, _playerCache, _entityCache, _entityListener);
2023-04-14 14:32:04 +04:00
_handlers[(byte)RagonOperation.REMOVE_ENTITY] = new EntityRemoveHandler(_entityCache);
2023-03-06 10:31:42 +04:00
_handlers[(byte)RagonOperation.REPLICATE_ENTITY_STATE] = new StateEntityHandler(_entityCache);
2023-10-04 14:42:59 +03:00
_handlers[(byte)RagonOperation.REPLICATE_ENTITY_EVENT] = new EntityEventHandler(_playerCache, _entityCache);
2023-10-11 19:37:50 +03:00
_handlers[(byte)RagonOperation.REPLICATE_ROOM_EVENT] = new RoomEventHandler(this, _playerCache);
2023-07-30 21:19:39 +03:00
_handlers[(byte)RagonOperation.SNAPSHOT] = new SnapshotHandler(this, listeners, _entityCache, _playerCache, _entityListener);
2023-10-04 14:42:59 +03:00
_handlers[(byte)RagonOperation.TIMESTAMP_SYNCHRONIZATION] = new TimestampHandler(this);
2023-10-11 19:37:50 +03:00
_handlers[(byte)RagonOperation.REPLICATE_RAW_DATA] = new RoomDataHandler(_playerCache, listeners);
2023-03-06 10:06:43 +04:00
var protocolRaw = RagonVersion.Parse(protocol);
_connection.Connect(address, port, protocolRaw);
}
public void Disconnect()
{
_status = RagonStatus.DISCONNECTED;
_room.Cleanup();
_connection.Disconnect();
2023-07-30 21:46:42 +03:00
2023-05-08 00:16:43 +03:00
OnDisconnected(RagonDisconnect.MANUAL);
2023-03-06 10:06:43 +04:00
}
public void Update(float dt)
{
2023-03-31 12:56:23 +04:00
if (_status != RagonStatus.DISCONNECTED)
2023-03-06 10:06:43 +04:00
{
2023-03-31 12:56:23 +04:00
_replicationTime += dt;
if (_replicationTime >= _replicationRate)
{
_replicationTime = 0;
2023-10-04 14:42:59 +03:00
_entityCache.WriteState(_writeBuffer);
SendTimestamp();
2023-03-31 12:56:23 +04:00
}
_stats.Update(_connection.BytesSent, _connection.BytesReceived, _connection.Ping, dt);
2023-03-06 10:06:43 +04:00
}
2023-07-30 21:46:42 +03:00
2023-07-30 21:19:39 +03:00
listeners.Update();
2023-03-06 10:06:43 +04:00
_connection.Update();
}
public void Dispose()
{
2023-10-11 19:37:50 +03:00
if (_status != RagonStatus.DISCONNECTED)
{
_status = RagonStatus.DISCONNECTED;
_connection.Disconnect();
}
2023-03-06 10:06:43 +04:00
_connection.Dispose();
}
2023-07-30 21:19:39 +03:00
public void AddListener(IRagonListener listener) => listeners.Add(listener);
public void AddListener(IRagonAuthorizationListener listener) => listeners.Add(listener);
public void AddListener(IRagonConnectionListener listener) => listeners.Add(listener);
public void AddListener(IRagonFailedListener listener) => listeners.Add(listener);
public void AddListener(IRagonJoinListener listener) => listeners.Add(listener);
public void AddListener(IRagonLeftListener listener) => listeners.Add(listener);
public void AddListener(IRagonOwnershipChangedListener listener) => listeners.Add(listener);
public void AddListener(IRagonPlayerJoinListener listener) => listeners.Add(listener);
public void AddListener(IRagonPlayerLeftListener listener) => listeners.Add(listener);
public void AddListener(IRagonSceneListener listener) => listeners.Add(listener);
public void AddListener(IRagonSceneRequestListener listener) => listeners.Add(listener);
2023-10-11 19:37:50 +03:00
public void AddListener(IRagonDataListener listener) => listeners.Add(listener);
2023-07-30 21:19:39 +03:00
public void RemoveListener(IRagonListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonAuthorizationListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonConnectionListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonFailedListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonJoinListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonLeftListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonOwnershipChangedListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonPlayerJoinListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonPlayerLeftListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonSceneListener listener) => listeners.Remove(listener);
public void RemoveListener(IRagonSceneRequestListener listener) => listeners.Remove(listener);
2023-10-11 19:37:50 +03:00
public void RemoveListener(IRagonDataListener listener) => listeners.Remove(listener);
2023-07-30 21:46:42 +03:00
2023-03-06 10:06:43 +04:00
#endregion
#region INTERNAL
internal void AssignRoom(RagonRoom room)
{
2023-10-09 09:17:43 +03:00
_room?.Dispose();
2023-03-06 10:06:43 +04:00
_room = room;
2023-07-30 21:46:42 +03:00
}
internal void SetStatus(RagonStatus status)
{
_status = status;
2023-03-06 10:06:43 +04:00
}
2023-10-04 14:42:59 +03:00
internal void SetTimestamp(double time)
{
_serverTimestamp = time;
}
2023-03-06 10:06:43 +04:00
#endregion
#region PRIVATE
2023-10-04 14:42:59 +03:00
private void SendTimestamp()
{
var timestamp = RagonTime.CurrentTimestamp();
var value = new DoubleToUInt()
{
Double = timestamp,
};
_writeBuffer.Clear();
_writeBuffer.WriteOperation(RagonOperation.TIMESTAMP_SYNCHRONIZATION);
_writeBuffer.Write(value.Int0, 32);
_writeBuffer.Write(value.Int1, 32);
}
2023-03-06 10:06:43 +04:00
private void OnConnected()
{
RagonLog.Trace("Connected");
2023-07-30 21:19:39 +03:00
listeners.OnConnected();
2023-03-06 10:06:43 +04:00
_status = RagonStatus.CONNECTED;
}
2023-05-08 00:16:43 +03:00
private void OnDisconnected(RagonDisconnect reason)
2023-03-06 10:06:43 +04:00
{
RagonLog.Trace($"Disconnected: {reason}");
2023-07-30 21:19:39 +03:00
listeners.OnDisconnected(reason);
2023-03-06 10:06:43 +04:00
_status = RagonStatus.DISCONNECTED;
}
2023-10-04 14:42:59 +03:00
private void OnData(byte[] data)
2023-03-06 10:06:43 +04:00
{
_readBuffer.Clear();
_readBuffer.FromArray(data);
var operation = _readBuffer.ReadByte();
2023-03-06 10:31:42 +04:00
_handlers[operation].Handle(_readBuffer);
2023-03-06 10:06:43 +04:00
}
#endregion
}
}