-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
50 changed files
with
1,848 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
Source/Mocha.Common/Attributes/Networking/ClientOnlyAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace Mocha.Common; | ||
|
||
[AttributeUsage( AttributeTargets.Class | | ||
AttributeTargets.Interface | | ||
AttributeTargets.Struct | | ||
AttributeTargets.Enum | | ||
AttributeTargets.Field | | ||
AttributeTargets.Property | | ||
AttributeTargets.Constructor | | ||
AttributeTargets.Method | | ||
AttributeTargets.Delegate | | ||
AttributeTargets.Event, Inherited = true, AllowMultiple = false )] | ||
public sealed class ClientOnlyAttribute : Attribute | ||
{ | ||
public ClientOnlyAttribute() | ||
{ | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
Source/Mocha.Common/Attributes/Networking/HandlesNetworkedType.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace Mocha; | ||
|
||
[System.AttributeUsage( AttributeTargets.Class, Inherited = false, AllowMultiple = false )] | ||
internal sealed class HandlesNetworkedTypeAttribute<T> : Attribute | ||
{ | ||
} |
2 changes: 2 additions & 0 deletions
2
Source/Mocha.Common/Attributes/Networking/ReplicatedAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[System.AttributeUsage( AttributeTargets.Field | AttributeTargets.Property, Inherited = false, AllowMultiple = false )] | ||
public sealed class SyncAttribute : Attribute { } |
18 changes: 18 additions & 0 deletions
18
Source/Mocha.Common/Attributes/Networking/ServerOnlyAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace Mocha.Common; | ||
|
||
[AttributeUsage( AttributeTargets.Class | | ||
AttributeTargets.Interface | | ||
AttributeTargets.Struct | | ||
AttributeTargets.Enum | | ||
AttributeTargets.Field | | ||
AttributeTargets.Property | | ||
AttributeTargets.Constructor | | ||
AttributeTargets.Method | | ||
AttributeTargets.Delegate | | ||
AttributeTargets.Event, Inherited = true, AllowMultiple = false )] | ||
public sealed class ServerOnlyAttribute : Attribute | ||
{ | ||
public ServerOnlyAttribute() | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
namespace Mocha.Common; | ||
|
||
/// <summary> | ||
/// Represents a client connected to a server. | ||
/// </summary> | ||
public interface IClient | ||
{ | ||
public abstract string Name { get; set; } | ||
public abstract int Ping { get; set; } | ||
public abstract IEntity Pawn { get; set; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
namespace Mocha.Common; | ||
|
||
/// <summary> | ||
/// A NetworkId is a wrapper around a 64-bit unsigned integer value used to identify an entity.<br /> | ||
/// The first bit of the value is used in order to determine whether the value is networked or local.<br /> | ||
/// The binary representation of the value is used to distinguish between local and networked entities.<br /> | ||
/// Note that the same ID (e.g., 12345678) can be used twice - once locally, and once networked - to<br /> | ||
/// refer to two distinct entities. The IDs used within this class should not reflect the native engine<br /> | ||
/// handle for the entity - NetworkIds are unique to a managed context. | ||
/// </summary> | ||
/// <remarks> | ||
/// For example, take an entity with the ID 12345678:<br /> | ||
/// <br /> | ||
/// <b>Local</b><br /> | ||
/// <code>00000000000000000000000000000000000000000000000000000000010111101</code><br /> | ||
/// <br /> | ||
/// <b>Networked</b><br /> | ||
/// <code>10000000000000000000000000000000000000000000000000000000010111101</code><br /> | ||
/// <br /> | ||
/// Note that the first bit is set to 1 in the binary representation of the networked entity. | ||
/// </remarks> | ||
public class NetworkId : IEquatable<NetworkId> | ||
{ | ||
internal ulong Value { get; private set; } | ||
|
||
internal NetworkId( ulong value ) | ||
{ | ||
Value = value; | ||
} | ||
|
||
public NetworkId() { } | ||
|
||
public bool IsNetworked() | ||
{ | ||
// If first bit of the value is set, it's a networked entity | ||
return (Value & 0x8000000000000000) != 0; | ||
} | ||
public bool IsLocal() | ||
{ | ||
// If first bit of the value is not set, it's a local entity | ||
return (Value & 0x8000000000000000) == 0; | ||
} | ||
|
||
public ulong GetValue() | ||
{ | ||
// Returns the value without the first bit | ||
return Value & 0x7FFFFFFFFFFFFFFF; | ||
} | ||
|
||
public static NetworkId CreateLocal() | ||
{ | ||
// Create a local entity by setting the first bit to 0 | ||
// Use EntityRegistry.Instance to get the next available local id | ||
return new( (uint)EntityRegistry.Instance.Count() << 1 ); | ||
} | ||
|
||
public static NetworkId CreateNetworked() | ||
{ | ||
// Create a networked entity by setting the first bit to 1 | ||
// Use EntityRegistry.Instance to get the next available local id | ||
return new( (uint)EntityRegistry.Instance.Count() | 0x8000000000000000 ); | ||
} | ||
|
||
public static implicit operator ulong( NetworkId id ) => id.GetValue(); | ||
public static implicit operator NetworkId( ulong value ) => new( value ); | ||
|
||
public override string ToString() | ||
{ | ||
return $"{(IsNetworked() ? "Networked" : "Local")}: {GetValue()} ({Value})"; | ||
} | ||
|
||
public bool Equals( NetworkId? other ) | ||
{ | ||
if ( other is null ) | ||
return false; | ||
|
||
return Value == other.Value; | ||
} | ||
|
||
public override bool Equals( object? obj ) | ||
{ | ||
if ( obj is NetworkId id ) | ||
return Equals( id ); | ||
|
||
return false; | ||
} | ||
|
||
public static bool operator ==( NetworkId? a, NetworkId? b ) | ||
{ | ||
return a?.Equals( b ) ?? false; | ||
} | ||
|
||
public static bool operator !=( NetworkId? a, NetworkId? b ) | ||
{ | ||
return !(a?.Equals( b ) ?? false); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
using Mocha.Networking; | ||
using System.Reflection; | ||
|
||
namespace Mocha; | ||
public class BaseGameClient : Client | ||
{ | ||
private ServerConnection _connection; | ||
|
||
public BaseGameClient( string ipAddress, ushort port = 10570 ) : base( ipAddress, port ) | ||
{ | ||
_connection = new ServerConnection(); | ||
RegisterHandler<KickedMessage>( OnKickedMessage ); | ||
RegisterHandler<SnapshotUpdateMessage>( OnSnapshotUpdateMessage ); | ||
RegisterHandler<HandshakeMessage>( OnHandshakeMessage ); | ||
} | ||
|
||
public override void OnMessageReceived( byte[] data ) | ||
{ | ||
InvokeHandler( _connection, data ); | ||
} | ||
|
||
public void OnKickedMessage( IConnection connection, KickedMessage kickedMessage ) | ||
{ | ||
Log.Info( $"BaseGameClient: We were kicked: '{kickedMessage.Reason}'" ); | ||
} | ||
|
||
private Type? LocateType( string typeName ) | ||
{ | ||
var type = Type.GetType( typeName )!; | ||
|
||
if ( type != null ) | ||
return type; | ||
|
||
type = Assembly.GetExecutingAssembly().GetType( typeName ); | ||
|
||
if ( type != null ) | ||
return type; | ||
|
||
type = Assembly.GetCallingAssembly().GetType( typeName ); | ||
|
||
if ( type != null ) | ||
return type; | ||
|
||
foreach ( var assembly in AppDomain.CurrentDomain.GetAssemblies() ) | ||
{ | ||
type = assembly.GetType( typeName ); | ||
if ( type != null ) | ||
return type; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
public void OnSnapshotUpdateMessage( IConnection connection, SnapshotUpdateMessage snapshotUpdateMessage ) | ||
{ | ||
foreach ( var entityChange in snapshotUpdateMessage.EntityChanges ) | ||
{ | ||
// Log.Info( $"BaseGameClient: Entity {entityChange.NetworkId} changed" ); | ||
|
||
// Does this entity already exist? | ||
var entity = EntityRegistry.Instance.FirstOrDefault( x => x.NetworkId == entityChange.NetworkId ); | ||
|
||
if ( entity == null ) | ||
{ | ||
// Entity doesn't exist locally - let's create it | ||
var type = LocateType( entityChange.TypeName ); | ||
|
||
if ( type == null ) | ||
{ | ||
// Log.Error( $"BaseGameClient: Unable to locate type '{entityChange.TypeName}'" ); | ||
continue; | ||
} | ||
|
||
entity = (Activator.CreateInstance( type ) as IEntity)!; | ||
|
||
// Set the network ID | ||
entity.NetworkId = entityChange.NetworkId; | ||
|
||
// Log.Info( $"BaseGameClient: Created entity {entity.NetworkId}" ); | ||
} | ||
|
||
foreach ( var memberChange in entityChange.MemberChanges ) | ||
{ | ||
if ( memberChange.Data == null ) | ||
continue; | ||
|
||
var member = entity.GetType().GetMember( memberChange.FieldName ).First()!; | ||
var value = NetworkSerializer.Deserialize( memberChange.Data, member.GetMemberType() ); | ||
|
||
if ( value == null ) | ||
continue; | ||
|
||
if ( member.MemberType == MemberTypes.Field ) | ||
{ | ||
var field = (FieldInfo)member; | ||
field.SetValue( entity, value ); | ||
|
||
// Log.Info( $"BaseGameClient: Entity {entityChange.NetworkId} field {memberChange.FieldName} changed to {value}" ); | ||
} | ||
else if ( member.MemberType == MemberTypes.Property ) | ||
{ | ||
var property = (PropertyInfo)member; | ||
property.SetValue( entity, value ); | ||
|
||
// Log.Info( $"BaseGameClient: Entity {entityChange.NetworkId} property {memberChange.FieldName} changed to {value}" ); | ||
} | ||
|
||
//if ( memberChange.FieldName == "PhysicsSetup" ) | ||
//{ | ||
// // Physics setup changed - let's update the physics setup | ||
// var physicsSetup = (ModelEntity.Physics)value; | ||
|
||
// if ( physicsSetup.PhysicsModelPath != null ) | ||
// ((ModelEntity)entity).SetMeshPhysics( physicsSetup.PhysicsModelPath ); | ||
//} | ||
} | ||
} | ||
} | ||
|
||
public void OnHandshakeMessage( IConnection connection, HandshakeMessage handshakeMessage ) | ||
{ | ||
Log.Info( $"BaseGameClient: Handshake received. Tick rate: {handshakeMessage.TickRate}, nickname: {handshakeMessage.Nickname}" ); | ||
} | ||
} |
Oops, something went wrong.