Started on spawning a player actor
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Prospect.Unreal.Core;
|
||||||
|
|
||||||
|
public enum ENetRole
|
||||||
|
{
|
||||||
|
/** No role at all. */
|
||||||
|
ROLE_None,
|
||||||
|
/** Locally simulated proxy of this actor. */
|
||||||
|
ROLE_SimulatedProxy,
|
||||||
|
/** Locally autonomous proxy of this actor. */
|
||||||
|
ROLE_AutonomousProxy,
|
||||||
|
/** Authoritative control over the actor. */
|
||||||
|
ROLE_Authority,
|
||||||
|
ROLE_MAX,
|
||||||
|
}
|
||||||
@@ -1,6 +1,35 @@
|
|||||||
namespace Prospect.Unreal.Net.Actors;
|
using Prospect.Unreal.Core;
|
||||||
|
|
||||||
|
namespace Prospect.Unreal.Net.Actors;
|
||||||
|
|
||||||
public class AActor
|
public class AActor
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the value of Role without causing other side effects to this instance.
|
||||||
|
/// </summary>
|
||||||
|
public void SetRole(ENetRole inRole)
|
||||||
|
{
|
||||||
|
// TODO: Implement
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set whether this actor replicates to network clients. When this actor is spawned on the server it will be sent to clients as well.
|
||||||
|
/// Properties flagged for replication will update on clients if they change on the server.
|
||||||
|
/// Internally changes the RemoteRole property and handles the cases where the actor needs to be added to the network actor list.
|
||||||
|
/// </summary>
|
||||||
|
public void SetReplicates(bool bInReplicates)
|
||||||
|
{
|
||||||
|
// TODO: Implement
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether or not this Actor is an autonomous proxy, which is an actor on a network client that is controlled by a user on that client.
|
||||||
|
/// </summary>
|
||||||
|
public void SetAutonomousProxy(bool bInAutonomousProxy, bool bAllowForcePropertyCompare = true)
|
||||||
|
{
|
||||||
|
// TODO: Implement
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Prospect.Unreal.Net.Actors;
|
||||||
|
|
||||||
|
public class AController : AActor
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
namespace Prospect.Unreal.Net.Actors;
|
using Prospect.Unreal.Core;
|
||||||
|
using Prospect.Unreal.Runtime;
|
||||||
|
|
||||||
|
namespace Prospect.Unreal.Net.Actors;
|
||||||
|
|
||||||
public class AGameModeBase : AInfo
|
public class AGameModeBase : AInfo
|
||||||
{
|
{
|
||||||
@@ -7,4 +10,16 @@ public class AGameModeBase : AInfo
|
|||||||
// Login unique id must match server expected unique id type OR No unique id could mean game doesn't use them
|
// Login unique id must match server expected unique id type OR No unique id could mean game doesn't use them
|
||||||
errorMessage = null;
|
errorMessage = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public APlayerController? Login(UPlayer newPlayer, ENetRole inRemoteRole, string portal, string options, FUniqueNetIdRepl uniqueId, out string errorMessage)
|
||||||
|
{
|
||||||
|
errorMessage = string.Empty;
|
||||||
|
throw new NotImplementedException();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PostLogin(APlayerController newPlayer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,18 @@
|
|||||||
namespace Prospect.Unreal.Net.Player;
|
using Prospect.Unreal.Runtime;
|
||||||
|
|
||||||
public class APlayerController
|
namespace Prospect.Unreal.Net.Actors;
|
||||||
|
|
||||||
|
public class APlayerController : AController
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Index identifying players using the same base connection (splitscreen clients)
|
||||||
|
/// Used by netcode to match replicated PlayerControllers to the correct splitscreen viewport and child connection
|
||||||
|
/// replicated via special internal code, not through normal variable replication
|
||||||
|
/// </summary>
|
||||||
|
public byte NetPlayerIndex { get; set; }
|
||||||
|
|
||||||
|
public void SetPlayer(UPlayer inPlayer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ using Prospect.Unreal.Net.Packets.Bunch;
|
|||||||
using Prospect.Unreal.Net.Packets.Control;
|
using Prospect.Unreal.Net.Packets.Control;
|
||||||
using Prospect.Unreal.Net.Packets.Header;
|
using Prospect.Unreal.Net.Packets.Header;
|
||||||
using Prospect.Unreal.Net.Packets.Header.Sequence;
|
using Prospect.Unreal.Net.Packets.Header.Sequence;
|
||||||
using Prospect.Unreal.Net.Player;
|
using Prospect.Unreal.Runtime;
|
||||||
using Prospect.Unreal.Serialization;
|
using Prospect.Unreal.Serialization;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
@@ -240,6 +240,11 @@ public abstract class UNetConnection : UPlayer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string ClientResponse { get; set; }
|
public string ClientResponse { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// URL requested by client
|
||||||
|
/// </summary>
|
||||||
|
public string RequestURL { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The last time an ack was received
|
/// The last time an ack was received
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace Prospect.Unreal.Net.Player;
|
using Prospect.Unreal.Net.Actors;
|
||||||
|
|
||||||
|
namespace Prospect.Unreal.Runtime;
|
||||||
|
|
||||||
public class UPlayer
|
public class UPlayer
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Prospect.Unreal.Core;
|
||||||
|
using Prospect.Unreal.Net;
|
||||||
|
using Prospect.Unreal.Net.Actors;
|
||||||
|
|
||||||
|
namespace Prospect.Unreal.Runtime;
|
||||||
|
|
||||||
|
public partial class UWorld
|
||||||
|
{
|
||||||
|
private APlayerController? SpawnPlayActor(UPlayer newPlayer, ENetRole remoteRole, FUrl inURL, FUniqueNetIdRepl uniqueId, out string error, byte inNetPlayerIndex = 0)
|
||||||
|
{
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
// Make the option string.
|
||||||
|
var optionsBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (var op in inURL.Options)
|
||||||
|
{
|
||||||
|
optionsBuilder.Append('?');
|
||||||
|
optionsBuilder.Append(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = optionsBuilder.ToString();
|
||||||
|
|
||||||
|
var gameMode = GetAuthGameMode();
|
||||||
|
if (gameMode != null)
|
||||||
|
{
|
||||||
|
var newPlayerController = gameMode.Login(newPlayer, remoteRole, inURL.Portal, options, uniqueId, out error);
|
||||||
|
if (newPlayerController == null)
|
||||||
|
{
|
||||||
|
Logger.Warning("Login failed: {Error}", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logger.Debug("{A} got player {B} [{C}]", newPlayerController);
|
||||||
|
|
||||||
|
// Possess the newly-spawned player.
|
||||||
|
newPlayerController.NetPlayerIndex = inNetPlayerIndex;
|
||||||
|
newPlayerController.SetRole(ENetRole.ROLE_Authority);
|
||||||
|
newPlayerController.SetReplicates(remoteRole != ENetRole.ROLE_None);
|
||||||
|
if (remoteRole == ENetRole.ROLE_AutonomousProxy)
|
||||||
|
{
|
||||||
|
newPlayerController.SetAutonomousProxy(true);
|
||||||
|
}
|
||||||
|
newPlayerController.SetPlayer(newPlayer);
|
||||||
|
gameMode.PostLogin(newPlayerController);
|
||||||
|
return newPlayerController;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Warning("Login failed: No game mode set");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Text;
|
||||||
using Prospect.Unreal.Core;
|
using Prospect.Unreal.Core;
|
||||||
using Prospect.Unreal.Core.Names;
|
using Prospect.Unreal.Core.Names;
|
||||||
using Prospect.Unreal.Exceptions;
|
using Prospect.Unreal.Exceptions;
|
||||||
@@ -10,7 +11,7 @@ using Serilog;
|
|||||||
|
|
||||||
namespace Prospect.Unreal.Runtime;
|
namespace Prospect.Unreal.Runtime;
|
||||||
|
|
||||||
public abstract class UWorld : FNetworkNotify, IAsyncDisposable
|
public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
|
||||||
{
|
{
|
||||||
private static readonly ILogger Logger = Log.ForContext<UWorld>();
|
private static readonly ILogger Logger = Log.ForContext<UWorld>();
|
||||||
|
|
||||||
@@ -203,27 +204,28 @@ public abstract class UWorld : FNetworkNotify, IAsyncDisposable
|
|||||||
case NMT.Login:
|
case NMT.Login:
|
||||||
{
|
{
|
||||||
// Admit or deny the player here.
|
// Admit or deny the player here.
|
||||||
if (NMT_Login.Receive(bunch, out var clientResponse, out var requestUrl, out var uniqueIdRepl, out var onlinePlatformName))
|
if (NMT_Login.Receive(bunch, out var clientResponse, out var tmpRequestUrl, out var uniqueIdRepl, out var onlinePlatformName))
|
||||||
{
|
{
|
||||||
connection.ClientResponse = clientResponse;
|
connection.ClientResponse = clientResponse;
|
||||||
|
connection.RequestURL = tmpRequestUrl;
|
||||||
|
|
||||||
// Only the options/portal for the URL should be used during join
|
// Only the options/portal for the URL should be used during join
|
||||||
var newRequestUrl = requestUrl;
|
var newRequestUrl = connection.RequestURL;
|
||||||
|
|
||||||
var oneIndex = requestUrl.IndexOf('?');
|
var oneIndex = newRequestUrl.IndexOf('?');
|
||||||
var twoIndex = requestUrl.IndexOf('#');
|
var twoIndex = newRequestUrl.IndexOf('#');
|
||||||
|
|
||||||
if (oneIndex != -1 && twoIndex != -1)
|
if (oneIndex != -1 && twoIndex != -1)
|
||||||
{
|
{
|
||||||
newRequestUrl = requestUrl.Substring(Math.Min(oneIndex, twoIndex));
|
newRequestUrl = newRequestUrl.Substring(Math.Min(oneIndex, twoIndex));
|
||||||
}
|
}
|
||||||
else if (oneIndex != -1)
|
else if (oneIndex != -1)
|
||||||
{
|
{
|
||||||
newRequestUrl = requestUrl.Substring(oneIndex);
|
newRequestUrl = newRequestUrl.Substring(oneIndex);
|
||||||
}
|
}
|
||||||
else if (twoIndex != -1)
|
else if (twoIndex != -1)
|
||||||
{
|
{
|
||||||
newRequestUrl = requestUrl.Substring(twoIndex);
|
newRequestUrl = newRequestUrl.Substring(twoIndex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -244,8 +246,8 @@ public abstract class UWorld : FNetworkNotify, IAsyncDisposable
|
|||||||
|
|
||||||
if (!inUrl.Valid)
|
if (!inUrl.Valid)
|
||||||
{
|
{
|
||||||
requestUrl = newRequestUrl;
|
connection.RequestURL = newRequestUrl;
|
||||||
Logger.Error("NMT_Login: Invalid URL {Url}", requestUrl);
|
Logger.Error("NMT_Login: Invalid URL {Url}", connection.RequestURL);
|
||||||
bunch.SetError();
|
bunch.SetError();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -256,10 +258,10 @@ public abstract class UWorld : FNetworkNotify, IAsyncDisposable
|
|||||||
inUrl.Options.Remove("SplitscreenCount");
|
inUrl.Options.Remove("SplitscreenCount");
|
||||||
inUrl.Options.Add($"SplitscreenCount={splitscreenCount}");
|
inUrl.Options.Add($"SplitscreenCount={splitscreenCount}");
|
||||||
|
|
||||||
requestUrl = inUrl.ToString();
|
connection.RequestURL = inUrl.ToString();
|
||||||
|
|
||||||
// skip to the first option in the URL
|
// skip to the first option in the URL
|
||||||
var tmp = requestUrl.Substring(requestUrl.IndexOf('?'));
|
var tmp = connection.RequestURL.Substring(connection.RequestURL.IndexOf('?'));
|
||||||
|
|
||||||
// keep track of net id for player associated with remote connection
|
// keep track of net id for player associated with remote connection
|
||||||
connection.PlayerId = uniqueIdRepl;
|
connection.PlayerId = uniqueIdRepl;
|
||||||
@@ -295,6 +297,21 @@ public abstract class UWorld : FNetworkNotify, IAsyncDisposable
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case NMT.Join:
|
||||||
|
{
|
||||||
|
if (connection.PlayerController == null)
|
||||||
|
{
|
||||||
|
// Spawn the player-actor for this network player.
|
||||||
|
Logger.Debug("Join request: {Request}", connection.RequestURL);
|
||||||
|
|
||||||
|
// TODO: Proper constructor
|
||||||
|
var inURL = new FUrl();
|
||||||
|
|
||||||
|
connection.PlayerController = SpawnPlayActor(connection, ENetRole.ROLE_AutonomousProxy, inURL, connection.PlayerId, out var errorMsg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw new NotImplementedException($"Unhandled control message {messageType}");
|
throw new NotImplementedException($"Unhandled control message {messageType}");
|
||||||
|
|||||||
Reference in New Issue
Block a user