Actor progress
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
namespace Prospect.Unreal.Core;
|
||||
|
||||
[Flags]
|
||||
public enum EObjectFlags
|
||||
{
|
||||
// Do not add new flags unless they truly belong here. There are alternatives.
|
||||
// if you change any the bit of any of the RF_Load flags, then you will need legacy serialization
|
||||
RF_NoFlags = 0x00000000, ///< No flags, used to avoid a cast
|
||||
|
||||
// This first group of flags mostly has to do with what kind of object it is. Other than transient, these are the persistent object flags.
|
||||
// The garbage collector also tends to look at these.
|
||||
RF_Public =0x00000001, ///< Object is visible outside its package.
|
||||
RF_Standalone =0x00000002, ///< Keep object around for editing even if unreferenced.
|
||||
RF_MarkAsNative =0x00000004, ///< Object (UField) will be marked as native on construction (DO NOT USE THIS FLAG in HasAnyFlags() etc)
|
||||
RF_Transactional =0x00000008, ///< Object is transactional.
|
||||
RF_ClassDefaultObject =0x00000010, ///< This object is its class's default object
|
||||
RF_ArchetypeObject =0x00000020, ///< This object is a template for another object - treat like a class default object
|
||||
RF_Transient =0x00000040, ///< Don't save object.
|
||||
|
||||
// This group of flags is primarily concerned with garbage collection.
|
||||
RF_MarkAsRootSet =0x00000080, ///< Object will be marked as root set on construction and not be garbage collected, even if unreferenced (DO NOT USE THIS FLAG in HasAnyFlags() etc)
|
||||
RF_TagGarbageTemp =0x00000100, ///< This is a temp user flag for various utilities that need to use the garbage collector. The garbage collector itself does not interpret it.
|
||||
|
||||
// The group of flags tracks the stages of the lifetime of a uobject
|
||||
RF_NeedInitialization =0x00000200, ///< This object has not completed its initialization process. Cleared when ~FObjectInitializer completes
|
||||
RF_NeedLoad =0x00000400, ///< During load, indicates object needs loading.
|
||||
RF_KeepForCooker =0x00000800, ///< Keep this object during garbage collection because it's still being used by the cooker
|
||||
RF_NeedPostLoad =0x00001000, ///< Object needs to be postloaded.
|
||||
RF_NeedPostLoadSubobjects =0x00002000, ///< During load, indicates that the object still needs to instance subobjects and fixup serialized component references
|
||||
RF_NewerVersionExists =0x00004000, ///< Object has been consigned to oblivion due to its owner package being reloaded, and a newer version currently exists
|
||||
RF_BeginDestroyed =0x00008000, ///< BeginDestroy has been called on the object.
|
||||
RF_FinishDestroyed =0x00010000, ///< FinishDestroy has been called on the object.
|
||||
|
||||
// Misc. Flags
|
||||
RF_BeingRegenerated =0x00020000, ///< Flagged on UObjects that are used to create UClasses (e.g. Blueprints) while they are regenerating their UClass on load (See FLinkerLoad::CreateExport()), as well as UClass objects in the midst of being created
|
||||
RF_DefaultSubObject =0x00040000, ///< Flagged on subobjects that are defaults
|
||||
RF_WasLoaded =0x00080000, ///< Flagged on UObjects that were loaded
|
||||
RF_TextExportTransient =0x00100000, ///< Do not export object to text form (e.g. copy/paste). Generally used for sub-objects that can be regenerated from data in their parent object.
|
||||
RF_LoadCompleted =0x00200000, ///< Object has been completely serialized by linkerload at least once. DO NOT USE THIS FLAG, It should be replaced with RF_WasLoaded.
|
||||
RF_InheritableComponentTemplate = 0x00400000, ///< Archetype of the object can be in its super class
|
||||
RF_DuplicateTransient =0x00800000, ///< Object should not be included in any type of duplication (copy/paste, binary duplication, etc.)
|
||||
RF_StrongRefOnFrame =0x01000000, ///< References to this object from persistent function frame are handled as strong ones.
|
||||
RF_NonPIEDuplicateTransient =0x02000000, ///< Object should not be included for duplication unless it's being duplicated for a PIE session
|
||||
RF_Dynamic =0x04000000, ///< Field Only. Dynamic field - doesn't get constructed during static initialization, can be constructed multiple times
|
||||
RF_WillBeLoaded =0x08000000, ///< This object was constructed during load and will be loaded shortly
|
||||
RF_HasExternalPackage =0x10000000, ///< This object has an external package assigned and should look it up when getting the outermost package
|
||||
}
|
||||
@@ -18,6 +18,39 @@ public class FUrl
|
||||
public string Portal { get; set; } = string.Empty;
|
||||
public bool Valid { get; set; } = true;
|
||||
|
||||
public string? GetOption(string match, string? defaultValue)
|
||||
{
|
||||
var len = match.Length;
|
||||
if (len > 0)
|
||||
{
|
||||
foreach (var option in Options)
|
||||
{
|
||||
if (option.StartsWith(match))
|
||||
{
|
||||
if (option[len - 1] == '=' || option[len] == '=' || option.Length == len)
|
||||
{
|
||||
return option.Substring(len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public string OptionsToString()
|
||||
{
|
||||
var optionsBuilder = new StringBuilder();
|
||||
|
||||
foreach (var op in Options)
|
||||
{
|
||||
optionsBuilder.Append('?');
|
||||
optionsBuilder.Append(op);
|
||||
}
|
||||
|
||||
return optionsBuilder.ToString();
|
||||
}
|
||||
|
||||
public string ToString(bool fullyQualified)
|
||||
{
|
||||
var result = new StringBuilder();
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using Prospect.Unreal.Net.Actors;
|
||||
|
||||
namespace Prospect.Unreal.Core;
|
||||
|
||||
public class ULevel
|
||||
{
|
||||
public ULevel()
|
||||
{
|
||||
Actors = new List<AActor>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// URL associated with this level.
|
||||
/// </summary>
|
||||
public FUrl URL { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Array of all actors in this level, used by FActorIteratorBase and derived classes
|
||||
/// </summary>
|
||||
public List<AActor> Actors { get; private set; }
|
||||
|
||||
public void InitializeNetworkActors()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Prospect.Unreal.Core;
|
||||
|
||||
public class UPackage
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
using Prospect.Unreal.Core;
|
||||
using Prospect.Unreal.Runtime;
|
||||
|
||||
namespace Prospect.Unreal.Net.Actors;
|
||||
|
||||
public class AActor
|
||||
{
|
||||
private bool bActorInitialized;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of Role without causing other side effects to this instance.
|
||||
/// </summary>
|
||||
@@ -32,4 +35,14 @@ public class AActor
|
||||
// TODO: Implement
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public UWorld GetWorld()
|
||||
{
|
||||
// if ()
|
||||
}
|
||||
|
||||
public bool IsActorInitialized()
|
||||
{
|
||||
return bActorInitialized;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,37 @@ namespace Prospect.Unreal.Net.Actors;
|
||||
|
||||
public class AGameModeBase : AInfo
|
||||
{
|
||||
public AGameModeBase()
|
||||
{
|
||||
OptionsString = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save options string and parse it when needed
|
||||
/// </summary>
|
||||
public string OptionsString { get; set; }
|
||||
|
||||
public AGameSession? GameSession { get; set; }
|
||||
|
||||
public virtual void InitGame(string mapName, string options, out string errorMessage)
|
||||
{
|
||||
// Save Options for future use
|
||||
OptionsString = options;
|
||||
|
||||
var spawnInfo = new FActorSpawnParameters
|
||||
{
|
||||
Instigator = GetInstigator(),
|
||||
ObjectFlags = EObjectFlags.RF_Transient
|
||||
};
|
||||
|
||||
GameSession = World.SpawnActor();
|
||||
}
|
||||
|
||||
public virtual void InitGameState()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void PreLogin(string options, string address, FUniqueNetIdRepl uniqueId, out string? errorMessage)
|
||||
{
|
||||
// Login unique id must match server expected unique id type OR No unique id could mean game doesn't use them
|
||||
@@ -14,8 +45,21 @@ public class AGameModeBase : AInfo
|
||||
public APlayerController? Login(UPlayer newPlayer, ENetRole inRemoteRole, string portal, string options, FUniqueNetIdRepl uniqueId, out string errorMessage)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
|
||||
if (GameSession == null)
|
||||
{
|
||||
errorMessage = "Failed to spawn player controller, GameSession is null";
|
||||
return null;
|
||||
}
|
||||
|
||||
errorMessage = GameSession.ApproveLogin(options);
|
||||
|
||||
if (!string.IsNullOrEmpty(errorMessage))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
return null;
|
||||
}
|
||||
|
||||
public void PostLogin(APlayerController newPlayer)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Prospect.Unreal.Net.Actors;
|
||||
|
||||
public class AGameSession : AInfo
|
||||
{
|
||||
public string ApproveLogin(string options)
|
||||
{
|
||||
// Check;
|
||||
// - SpectatorOnly
|
||||
// - SplitscreenCount
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Prospect.Unreal.Net;
|
||||
|
||||
public enum ESpawnActorCollisionHandlingMethod
|
||||
{
|
||||
Undefined,
|
||||
AlwaysSpawn,
|
||||
AdjustIfPossibleButAlwaysSpawn,
|
||||
AdjustIfPossibleButDontSpawnIfColliding,
|
||||
DontSpawnIfColliding
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Prospect.Unreal.Net;
|
||||
|
||||
public enum ESpawnActorNameMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Fatal if unavailable, application will assert
|
||||
/// </summary>
|
||||
Required_Fatal,
|
||||
|
||||
/// <summary>
|
||||
/// Report an error return null if unavailable
|
||||
/// </summary>
|
||||
Required_ErrorAndReturnNull,
|
||||
|
||||
/// <summary>
|
||||
/// Return null if unavailable
|
||||
/// </summary>
|
||||
Required_ReturnNull,
|
||||
|
||||
/// <summary>
|
||||
/// If the supplied Name is already in use the generate an unused one using the supplied version as a base
|
||||
/// </summary>
|
||||
Requested
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
using Prospect.Unreal.Core;
|
||||
using Prospect.Unreal.Core.Names;
|
||||
using Prospect.Unreal.Net.Actors;
|
||||
|
||||
namespace Prospect.Unreal.Net;
|
||||
|
||||
public ref struct FActorSpawnParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// A name to assign as the Name of the Actor being spawned.
|
||||
/// If no value is specified, the name of the spawned Actor will be automatically generated using the form [Class]_[Number].
|
||||
/// </summary>
|
||||
public FName? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An Actor to use as a template when spawning the new Actor.
|
||||
/// The spawned Actor will be initialized using the property values of the template Actor.
|
||||
/// If left NULL the class default object (CDO) will be used to initialize the spawned Actor.
|
||||
/// </summary>
|
||||
public AActor? Template { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Actor that spawned this Actor. (Can be left as NULL).
|
||||
/// </summary>
|
||||
public AActor? Owner { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The APawn that is responsible for damage done by the spawned Actor. (Can be left as NULL).
|
||||
/// </summary>
|
||||
public AActor? Instigator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ULevel to spawn the Actor in, i.e. the Outer of the Actor.
|
||||
/// If left as NULL the Outer of the Owner is used. If the Owner is NULL the persistent level is used.
|
||||
/// </summary>
|
||||
public ULevel? OverrideLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The UPackage to set the Actor in.
|
||||
/// If left as NULL the Package will not be set and the actor will be saved in the same package as the persistent level.
|
||||
/// </summary>
|
||||
public UPackage? OverridePackage { get; set; }
|
||||
|
||||
// UChildActorComponent
|
||||
|
||||
/// <summary>
|
||||
/// The Guid to set to this actor. Should only be set when reinstancing blueprint actors.
|
||||
/// </summary>
|
||||
public FGuid? OverrideActorGuid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Method for resolving collisions at the spawn point. Undefined means no override, use the actor's setting.
|
||||
/// </summary>
|
||||
public ESpawnActorCollisionHandlingMethod SpawnCollisionHandlingOverride { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is the actor remotely owned.
|
||||
/// This should only be set true by the package map when it is creating an actor on a client that was replicated from the server.
|
||||
/// </summary>
|
||||
public bool bRemoteOwned { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether spawning will not fail if certain conditions are not met.
|
||||
/// If true, spawning will not fail because the class being spawned is `bStatic=true` or because the class of the template Actor is not the same as the class of the Actor being spawned.
|
||||
/// </summary>
|
||||
public bool bNoFail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the construction script will be run.
|
||||
/// If true, the construction script will not be run on the spawned Actor.
|
||||
/// Only applicable if the Actor is being spawned from a Blueprint.
|
||||
/// </summary>
|
||||
public bool bDeferConstruction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the actor may be spawned when running a construction script.
|
||||
/// If true spawning will fail if a construction script is being run.
|
||||
/// </summary>
|
||||
public bool bAllowDuringConstructionScript { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the begin play cycle will run on the spawned actor when in the editor.
|
||||
/// </summary>
|
||||
public bool bTemporaryEditorActor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the actor should be hidden from the Scene Outliner
|
||||
/// </summary>
|
||||
public bool bHideFromSceneOutliner { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether to create a new package for the actor or not.
|
||||
/// </summary>
|
||||
public bool bCreateActorPackage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// In which way should SpawnActor should treat the supplied Name if not none.
|
||||
/// </summary>
|
||||
public ESpawnActorNameMode NameMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Flags used to describe the spawned actor/object instance.
|
||||
/// </summary>
|
||||
public EObjectFlags ObjectFlags { get; set; }
|
||||
}
|
||||
@@ -12,15 +12,7 @@ public partial class UWorld
|
||||
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 options = inURL.OptionsToString();
|
||||
|
||||
var gameMode = GetAuthGameMode();
|
||||
if (gameMode != null)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Text;
|
||||
using Prospect.Unreal.Core;
|
||||
using Prospect.Unreal.Core.Names;
|
||||
using Prospect.Unreal.Exceptions;
|
||||
@@ -17,17 +16,65 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
|
||||
|
||||
private UGameInstance? _owningGameInstance;
|
||||
private AGameModeBase? _authorityGameMode;
|
||||
private List<ULevel> _levels;
|
||||
|
||||
public UWorld(FUrl url)
|
||||
public UWorld()
|
||||
{
|
||||
Url = url;
|
||||
_owningGameInstance = null;
|
||||
_authorityGameMode = null;
|
||||
_levels = new List<ULevel>();
|
||||
}
|
||||
|
||||
public FUrl Url { get; }
|
||||
/// <summary>
|
||||
/// Persistent level containing the world info, default brush and actors spawned during gameplay among other things
|
||||
/// </summary>
|
||||
public ULevel? PersistentLevel { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The NAME_GameNetDriver game connection(s) for client/server communication
|
||||
/// </summary>
|
||||
public UNetDriver? NetDriver { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether actors have been initialized for play
|
||||
/// </summary>
|
||||
public bool bActorsInitialized { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether BeginPlay has been called on actors
|
||||
/// </summary>
|
||||
public bool bBegunPlay { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The URL that was used when loading this World.
|
||||
/// </summary>
|
||||
public FUrl? Url { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time in seconds since level began play, but IS paused when the game is paused, and IS dilated/clamped.
|
||||
/// </summary>
|
||||
public float TimeSeconds { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time in seconds since level began play, but IS NOT paused when the game is paused, and IS dilated/clamped.
|
||||
/// </summary>
|
||||
public float UnpausedTimeSeconds { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time in seconds since level began play, but IS NOT paused when the game is paused, and IS NOT dilated/clamped.
|
||||
/// </summary>
|
||||
public float RealTimeSeconds { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time in seconds since level began play, but IS paused when the game is paused, and IS NOT dilated/clamped.
|
||||
/// </summary>
|
||||
public float AudioTimeSeconds { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Frame delta time in seconds adjusted by e.g. time dilation.
|
||||
/// </summary>
|
||||
public float DeltaTimeSeconds { get; private set; }
|
||||
|
||||
public void Tick(float deltaTime)
|
||||
{
|
||||
if (NetDriver != null)
|
||||
@@ -77,7 +124,51 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
|
||||
{
|
||||
return _authorityGameMode;
|
||||
}
|
||||
|
||||
|
||||
public void InitializeActorsForPlay(FUrl inUrl, bool bResetTime)
|
||||
{
|
||||
// Don't reset time for seamless world transitions.
|
||||
if (bResetTime)
|
||||
{
|
||||
TimeSeconds = 0.0f;
|
||||
UnpausedTimeSeconds = 0.0f;
|
||||
RealTimeSeconds = 0.0f;
|
||||
AudioTimeSeconds = 0.0f;
|
||||
}
|
||||
|
||||
// Get URL Options
|
||||
var options = inUrl.OptionsToString();
|
||||
|
||||
// Set level info.
|
||||
if (!string.IsNullOrEmpty(inUrl.GetOption("load", null)))
|
||||
{
|
||||
Url = inUrl;
|
||||
}
|
||||
|
||||
// Init level gameplay info.
|
||||
if (!AreActorsInitialized())
|
||||
{
|
||||
// Initialize network actors and start execution.
|
||||
for (int i = 0; i < _levels.Count; i++)
|
||||
{
|
||||
_levels[i].InitializeNetworkActors();
|
||||
}
|
||||
|
||||
// Enable actor script calls.
|
||||
bStartup = true;
|
||||
bActorsInitialized = true;
|
||||
|
||||
// Spawn server actors
|
||||
// TODO: GEngine SpawnServerActors.
|
||||
|
||||
// Init the game mode.
|
||||
if (_authorityGameMode != null && !_authorityGameMode.IsActorInitialized())
|
||||
{
|
||||
_authorityGameMode.InitGame(inUrl.Map /* TODO: FPaths.GetBaseFilename */, options, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Listen()
|
||||
{
|
||||
if (NetDriver != null)
|
||||
@@ -348,6 +439,16 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasBegunPlay()
|
||||
{
|
||||
return bBegunPlay && PersistentLevel != null && PersistentLevel.Actors.Count != 0;
|
||||
}
|
||||
|
||||
public bool AreActorsInitialized()
|
||||
{
|
||||
return bActorsInitialized && PersistentLevel != null && PersistentLevel.Actors.Count != 0;
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user