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

255 lines
9.0 KiB
C#
Raw Normal View History

2023-03-06 10:06:43 +04:00
/*
2024-05-09 10:50:59 +03:00
* Copyright 2023-2024 Eduard Kargin <kargin.eduard@gmail.com>
2023-03-06 10:06:43 +04:00
*
* 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;
2024-11-03 11:36:58 +03:00
2023-10-04 14:42:59 +03:00
private IHandler[] _handlers;
2024-09-28 20:11:56 +03:00
private RagonStream _readBuffer;
private RagonStream _writeBuffer;
2023-03-06 10:06:43 +04:00
private RagonRoom _room;
private RagonSession _session;
2024-04-13 16:17:31 +03:00
private RagonListenerList _listeners;
2023-03-06 10:06:43 +04:00
private RagonPlayerCache _playerCache;
private RagonEventCache _eventCache;
2025-01-18 17:30:03 +03:00
private RagonState _state;
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;
2025-01-18 17:30:03 +03:00
public RagonState State => _state;
2023-03-06 10:06:43 +04:00
public RagonSession Session => _session;
public RagonEventCache Event => _eventCache;
public NetworkStatistics Statistics => _stats;
public RagonRoom Room => _room;
2024-05-09 10:50:59 +03:00
2024-09-28 20:11:56 +03:00
internal RagonStream Buffer => _writeBuffer;
2023-03-06 10:06:43 +04:00
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
{
2024-04-13 16:17:31 +03:00
_listeners = new RagonListenerList(this);
2024-05-09 10:50:59 +03:00
2023-03-06 10:06:43 +04:00
_connection = connection;
_connection.OnData += OnData;
_connection.OnConnected += OnConnected;
_connection.OnDisconnected += OnDisconnected;
2024-05-09 10:50:59 +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();
2024-09-28 20:11:56 +03:00
_writeBuffer = new RagonStream();
_readBuffer = new RagonStream();
2023-03-06 10:06:43 +04:00
_playerCache = new RagonPlayerCache();
2024-05-09 10:50:59 +03:00
_session = new RagonSession(this, _writeBuffer);
2025-01-18 17:30:03 +03:00
_room = new RagonRoom(this, _playerCache);
_stats = new NetworkStatistics();
_state = RagonState.DISCONNECTED;
2023-10-04 14:42:59 +03:00
_handlers = new IHandler[byte.MaxValue];
2024-04-13 16:17:31 +03:00
_handlers[(byte)RagonOperation.AUTHORIZED_SUCCESS] = new AuthorizeSuccessHandler(this, _listeners);
_handlers[(byte)RagonOperation.AUTHORIZED_FAILED] = new AuthorizeFailedHandler(_listeners);
2025-01-18 17:30:03 +03:00
_handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, _room);
2024-04-13 16:17:31 +03:00
_handlers[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(_listeners);
2024-09-28 20:11:56 +03:00
_handlers[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, _listeners);
_handlers[(byte)RagonOperation.OWNERSHIP_ROOM_CHANGED] = new OwnershipRoomHandler(_listeners, _playerCache);
2024-04-13 16:17:31 +03:00
_handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, _listeners);
2024-09-28 20:11:56 +03:00
_handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_playerCache, _listeners);
2023-10-11 19:37:50 +03:00
_handlers[(byte)RagonOperation.REPLICATE_ROOM_EVENT] = new RoomEventHandler(this, _playerCache);
2023-10-04 14:42:59 +03:00
_handlers[(byte)RagonOperation.TIMESTAMP_SYNCHRONIZATION] = new TimestampHandler(this);
2024-04-13 16:17:31 +03:00
_handlers[(byte)RagonOperation.ROOM_LIST_UPDATED] = new RoomListHandler(_session, _listeners);
2024-05-09 10:50:59 +03:00
_handlers[(byte)RagonOperation.ROOM_DATA_UPDATED] = new RoomUserDataHandler(this, _listeners);
_handlers[(byte)RagonOperation.PLAYER_DATA_UPDATED] = new PlayerUserDataHandler(_playerCache, _listeners);
2025-01-18 17:30:03 +03:00
}
public void Connect(string address, ushort port, string protocol)
{
2023-03-06 10:06:43 +04:00
var protocolRaw = RagonVersion.Parse(protocol);
_connection.Connect(address, port, protocolRaw);
}
public void Disconnect()
{
2025-01-18 17:30:03 +03:00
_state = RagonState.DISCONNECTED;
_room.Clear();
2023-03-06 10:06:43 +04:00
_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)
{
2025-01-18 17:30:03 +03:00
if (_state != RagonState.DISCONNECTED)
2023-03-06 10:06:43 +04:00
{
2023-03-31 12:56:23 +04:00
_replicationTime += dt;
if (_replicationTime >= _replicationRate)
{
_replicationTime = 0;
2025-01-18 17:30:03 +03:00
2023-10-04 14:42:59 +03:00
SendTimestamp();
2024-05-09 10:50:59 +03:00
SendRoomUserData();
SendPlayerUserData();
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
2024-04-13 16:17:31 +03:00
_listeners.Update();
2023-03-06 10:06:43 +04:00
_connection.Update();
}
public void Dispose()
{
2025-01-18 17:30:03 +03:00
if (_state != RagonState.DISCONNECTED)
2023-10-11 19:37:50 +03:00
{
2025-01-18 17:30:03 +03:00
_state = RagonState.DISCONNECTED;
2023-10-11 19:37:50 +03:00
_connection.Disconnect();
}
2024-05-09 10:50:59 +03:00
2023-03-06 10:06:43 +04:00
_connection.Dispose();
}
2024-04-13 16:17:31 +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);
2024-04-13 18:25:39 +03:00
public void AddListener(IRagonRoomListListener listener) => _listeners.Add(listener);
2024-05-09 10:50:59 +03:00
public void AddListener(IRagonPlayerUserDataListener listener) => _listeners.Add(listener);
public void AddListener(IRagonRoomUserDataListener listener) => _listeners.Add(listener);
2024-04-13 16:17:31 +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);
2024-04-13 18:25:39 +03:00
public void RemoveListener(IRagonRoomListListener listener) => _listeners.Remove(listener);
2024-05-09 10:50:59 +03:00
public void RemoveListener(IRagonRoomUserDataListener listener) => _listeners.Remove(listener);
public void RemoveListener(IRagonPlayerUserDataListener listener) => _listeners.Remove(listener);
2023-07-30 21:46:42 +03:00
2023-03-06 10:06:43 +04:00
#endregion
#region INTERNAL
2025-01-18 17:30:03 +03:00
internal void UpdateState(RagonState state)
2023-07-30 21:46:42 +03:00
{
2025-01-18 17:30:03 +03:00
_state = state;
2023-03-06 10:06:43 +04:00
}
2025-01-18 17:30:03 +03:00
internal void UpdateTimestamp(double time)
2023-10-04 14:42:59 +03:00
{
_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);
2024-09-28 20:11:56 +03:00
_writeBuffer.WriteInt((int)value.Int0);
_writeBuffer.WriteInt((int)value.Int1);
2023-10-04 14:42:59 +03:00
}
2024-05-09 10:50:59 +03:00
private void SendRoomUserData()
{
if (_room == null) return;
2024-05-09 10:50:59 +03:00
var props = _room.UserData;
2024-05-09 10:50:59 +03:00
if (!props.Dirty) return;
_writeBuffer.Clear();
2024-05-09 10:50:59 +03:00
_writeBuffer.WriteOperation(RagonOperation.ROOM_DATA_UPDATED);
props.Write(_writeBuffer);
var sendData = _writeBuffer.ToArray();
_connection.Reliable.Send(sendData);
}
private void SendPlayerUserData()
{
if (_playerCache.Local == null) return;
var props = _playerCache.Local.UserData;
if (!props.Dirty) return;
_writeBuffer.Clear();
_writeBuffer.WriteOperation(RagonOperation.PLAYER_DATA_UPDATED);
props.Write(_writeBuffer);
var sendData = _writeBuffer.ToArray();
_connection.Reliable.Send(sendData);
}
2023-10-04 14:42:59 +03:00
2023-03-06 10:06:43 +04:00
private void OnConnected()
{
RagonLog.Trace("Connected");
2024-04-13 16:17:31 +03:00
_listeners.OnConnected();
2025-01-18 17:30:03 +03:00
_state = RagonState.CONNECTED;
2023-03-06 10:06:43 +04:00
}
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}");
2024-04-13 16:17:31 +03:00
_listeners.OnDisconnected(reason);
2025-01-18 17:30:03 +03:00
_state = RagonState.DISCONNECTED;
2023-03-06 10:06:43 +04:00
}
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
}
}