2022-02-14 19:45:58 +00:00
using System.Buffers ;
using System.Collections.Concurrent ;
2022-04-27 06:43:11 +00:00
using System.Diagnostics ;
2022-02-14 19:45:58 +00:00
using System.Net.Sockets ;
2022-03-11 05:59:02 +00:00
using System.Runtime.InteropServices ;
2022-02-10 04:29:10 +00:00
using Shared ;
2022-02-10 08:42:35 +00:00
using Shared.Packet ;
2022-02-08 22:46:12 +00:00
using Shared.Packet.Packets ;
2021-11-29 04:04:34 +00:00
2022-02-10 01:44:50 +00:00
namespace Server ;
2021-11-29 04:04:34 +00:00
public class Client : IDisposable {
2022-03-15 07:23:37 +00:00
public readonly ConcurrentDictionary < string , object? > Metadata = new ConcurrentDictionary < string , object? > ( ) ; // can be used to store any information about a player
2022-02-09 21:56:57 +00:00
public bool Connected = false ;
2023-09-05 23:14:54 +00:00
public bool Ignored = false ;
2024-04-27 15:46:18 +00:00
public bool Banned = false ;
2022-02-14 19:45:58 +00:00
public CostumePacket ? CurrentCostume = null ; // required for proper client sync
public string Name {
get = > Logger . Name ;
set = > Logger . Name = value ;
}
2022-02-10 01:44:50 +00:00
public Guid Id ;
public Socket ? Socket ;
2022-07-28 08:05:32 +00:00
public Server Server { get ; init ; } = null ! ; //init'd in object initializer
2022-02-15 20:26:50 +00:00
public Logger Logger { get ; }
2022-02-10 01:44:50 +00:00
2022-02-15 20:26:50 +00:00
public Client ( Socket socket ) {
Socket = socket ;
2022-03-06 23:19:49 +00:00
Logger = new Logger ( "Unknown User" ) ;
2022-02-15 20:26:50 +00:00
}
2022-03-01 21:08:53 +00:00
2022-09-03 21:04:01 +00:00
// copy Client to use existing data for a new reconnected connection with a new socket
public Client ( Client other , Socket socket ) {
Metadata = other . Metadata ;
Connected = other . Connected ;
CurrentCostume = other . CurrentCostume ;
Id = other . Id ;
Socket = socket ;
Server = other . Server ;
Logger = other . Logger ;
}
2022-02-10 01:44:50 +00:00
public void Dispose ( ) {
2024-04-27 15:23:34 +00:00
if ( Socket ? . Connected is true ) {
2022-02-15 20:26:50 +00:00
Socket . Disconnect ( false ) ;
2024-04-27 15:23:34 +00:00
}
2022-02-10 01:44:50 +00:00
}
2021-11-29 04:04:34 +00:00
2022-03-01 21:08:53 +00:00
2022-02-16 00:35:38 +00:00
public async Task Send < T > ( T packet , Client ? sender = null ) where T : struct , IPacket {
2022-03-11 05:59:02 +00:00
IMemoryOwner < byte > memory = MemoryPool < byte > . Shared . RentZero ( Constants . HeaderSize + packet . Size ) ;
2022-04-27 05:48:13 +00:00
PacketAttribute packetAttribute = Constants . PacketMap [ typeof ( T ) ] ;
2022-04-27 20:09:50 +00:00
try {
2024-04-27 15:46:18 +00:00
// don't send most packets to ignored players
if ( Ignored & & packetAttribute . Type ! = PacketType . Init & & packetAttribute . Type ! = PacketType . ChangeStage ) {
memory . Dispose ( ) ;
return ;
}
2022-04-27 20:17:02 +00:00
Server . FillPacket ( new PacketHeader {
2024-04-27 15:23:34 +00:00
Id = sender ? . Id ? ? Id ,
Type = packetAttribute . Type ,
2022-04-27 20:09:50 +00:00
PacketSize = packet . Size
2022-04-27 20:17:02 +00:00
} , packet , memory . Memory ) ;
2022-04-27 20:09:50 +00:00
}
catch ( Exception e ) {
2022-04-28 03:32:52 +00:00
Logger . Error ( $"Failed to serialize {packetAttribute.Type}" ) ;
Logger . Error ( e ) ;
2022-04-27 20:09:50 +00:00
}
2022-04-27 19:43:03 +00:00
await Socket ! . SendAsync ( memory . Memory [ . . ( Constants . HeaderSize + packet . Size ) ] , SocketFlags . None ) ;
2022-02-16 20:33:21 +00:00
memory . Dispose ( ) ;
2022-02-14 19:45:58 +00:00
}
2022-04-27 20:02:26 +00:00
public async Task Send ( Memory < byte > data , Client ? sender ) {
2022-04-27 06:24:11 +00:00
PacketHeader header = new PacketHeader ( ) ;
header . Deserialize ( data . Span ) ;
2024-04-27 15:23:34 +00:00
2024-04-27 15:46:18 +00:00
if ( ! Connected & & ! Ignored & & header . Type ! = PacketType . Connect ) {
2022-04-27 05:58:43 +00:00
Server . Logger . Error ( $"Didn't send {header.Type} to {Id} because they weren't connected yet" ) ;
2022-02-10 08:42:35 +00:00
return ;
}
2022-02-14 19:45:58 +00:00
2024-04-27 15:46:18 +00:00
// don't send most packets to ignored players
if ( Ignored & & header . Type ! = PacketType . Init & & header . Type ! = PacketType . ChangeStage ) {
return ;
}
2022-04-27 05:58:43 +00:00
await Socket ! . SendAsync ( data [ . . ( Constants . HeaderSize + header . PacketSize ) ] , SocketFlags . None ) ;
2021-11-29 04:04:34 +00:00
}
2023-06-28 15:12:49 +00:00
public void CleanMetadataOnNewConnection ( ) {
object? tmp ;
Metadata . TryRemove ( "time" , out tmp ) ;
Metadata . TryRemove ( "seeking" , out tmp ) ;
Metadata . TryRemove ( "lastCostumePacket" , out tmp ) ;
Metadata . TryRemove ( "lastCapturePacket" , out tmp ) ;
Metadata . TryRemove ( "lastGamePacket" , out tmp ) ;
Metadata . TryRemove ( "lastPlayerPacket" , out tmp ) ;
}
2024-04-24 23:56:30 +00:00
public TagPacket ? GetTagPacket ( ) {
var time = ( Time ? ) this . Metadata ? [ "time" ] ;
var seek = ( bool? ) this . Metadata ? [ "seeking" ] ;
if ( time = = null & & seek = = null ) { return null ; }
return new TagPacket {
UpdateType = ( seek ! = null ? TagPacket . TagUpdate . State : 0 ) | ( time ! = null ? TagPacket . TagUpdate . Time : 0 ) ,
IsIt = seek ? ? false ,
Seconds = ( byte ) ( time ? . Seconds ? ? 0 ) ,
Minutes = ( ushort ) ( time ? . Minutes ? ? 0 ) ,
} ;
}
2022-02-10 01:44:50 +00:00
public static bool operator = = ( Client ? left , Client ? right ) {
return left is { } leftClient & & right is { } rightClient & & leftClient . Id = = rightClient . Id ;
2021-11-29 04:04:34 +00:00
}
2022-02-10 01:44:50 +00:00
public static bool operator ! = ( Client ? left , Client ? right ) {
return ! ( left = = right ) ;
}
2022-07-28 08:05:32 +00:00
public override bool Equals ( object? obj ) {
if ( obj is Client )
return this = = ( Client ) obj ;
else
return false ;
}
public override int GetHashCode ( ) {
return Id . GetHashCode ( ) ; //relies upon same info as == operator.
}
2022-09-03 21:04:01 +00:00
}