SpawnActor stuff
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
namespace Prospect.Unreal.Core.Math;
|
namespace Prospect.Unreal.Core.Math;
|
||||||
|
|
||||||
public ref struct FTransform
|
public class FTransform
|
||||||
{
|
{
|
||||||
public FVector Location { get; set; }
|
public FVector Location { get; set; }
|
||||||
public FRotator Rotation { get; set; }
|
public FRotator Rotation { get; set; }
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Prospect.Unreal.Core.Objects;
|
||||||
|
|
||||||
|
public struct FObjectInstancingGraph
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,6 +13,6 @@ public class GUClassArray
|
|||||||
public static UClass StaticClass(Type type)
|
public static UClass StaticClass(Type type)
|
||||||
{
|
{
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
return new UClass();
|
return new UClass(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,5 +4,30 @@ namespace Prospect.Unreal.Core.Objects;
|
|||||||
|
|
||||||
public class UClass : UStruct
|
public class UClass : UStruct
|
||||||
{
|
{
|
||||||
|
public UClass(Type type)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type Type { get; }
|
||||||
|
|
||||||
|
public UObject GetDefaultObject<T>() where T : UObject
|
||||||
|
{
|
||||||
|
// TODO: Implement
|
||||||
|
var obj = (UObject) Activator.CreateInstance<T>();
|
||||||
|
|
||||||
|
obj.SetFlags(EObjectFlags.RF_Public | EObjectFlags.RF_ClassDefaultObject | EObjectFlags.RF_ArchetypeObject);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UObject GetDefaultObject(bool bCreateIfNeeded = true)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UObject CreateDefaultObject()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,5 +2,9 @@
|
|||||||
|
|
||||||
public class UObject : UObjectBaseUtility
|
public class UObject : UObjectBaseUtility
|
||||||
{
|
{
|
||||||
|
public bool CheckDefaultSubobjects(bool bForceCheck = false)
|
||||||
|
{
|
||||||
|
// TODO: Implement
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -39,6 +39,12 @@ public class UObjectBaseUtility : UObjectBase
|
|||||||
// TODO: GUObjectArray
|
// TODO: GUObjectArray
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsPendingKill()
|
||||||
|
{
|
||||||
|
// TODO: GUObjectArray
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Outer & Package
|
* Outer & Package
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using Prospect.Unreal.Core.Names;
|
||||||
|
using Prospect.Unreal.Exceptions;
|
||||||
|
|
||||||
|
namespace Prospect.Unreal.Core.Objects;
|
||||||
|
|
||||||
|
public class UObjectGlobals
|
||||||
|
{
|
||||||
|
public static T? NewObject<T>(UObject outer,
|
||||||
|
UClass clazz,
|
||||||
|
FName? name = null,
|
||||||
|
EObjectFlags flags = EObjectFlags.RF_NoFlags,
|
||||||
|
UObject? template = null,
|
||||||
|
bool bCopyTransientsFromClassDefaults = false,
|
||||||
|
FObjectInstancingGraph? inInstanceGraph = null,
|
||||||
|
UPackage? externalPackage = null)
|
||||||
|
{
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
name = EName.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewObject
|
||||||
|
// StaticConstructObject_Internal
|
||||||
|
// StaticAllocateObject
|
||||||
|
|
||||||
|
var obj = Activator.CreateInstance(clazz.Type);
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
throw new UnrealException("Failed to create object.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T?) obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Prospect.Unreal.Core;
|
using Prospect.Unreal.Core;
|
||||||
|
using Prospect.Unreal.Core.Math;
|
||||||
using Prospect.Unreal.Core.Objects;
|
using Prospect.Unreal.Core.Objects;
|
||||||
using Prospect.Unreal.Runtime;
|
using Prospect.Unreal.Runtime;
|
||||||
|
|
||||||
@@ -7,13 +8,20 @@ namespace Prospect.Unreal.Net.Actors;
|
|||||||
public class AActor : UObject
|
public class AActor : UObject
|
||||||
{
|
{
|
||||||
private bool bActorInitialized;
|
private bool bActorInitialized;
|
||||||
|
private bool bActorIsBeingDestroyed;
|
||||||
|
|
||||||
// TODO: UPROPERTY(BlueprintReadWrite, ReplicatedUsing=OnRep_Instigator, meta=(ExposeOnSpawn=true, AllowPrivateAccess=true), Category=Actor)
|
// TODO: UPROPERTY(BlueprintReadWrite, ReplicatedUsing=OnRep_Instigator, meta=(ExposeOnSpawn=true, AllowPrivateAccess=true), Category=Actor)
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pawn responsible for damage and other gameplay events caused by this actor.
|
/// Pawn responsible for damage and other gameplay events caused by this actor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private APawn? _instigator;
|
private APawn? _instigator;
|
||||||
|
|
||||||
|
// TODO: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Actor)
|
||||||
|
/// <summary>
|
||||||
|
/// Controls how to handle spawning this actor in a situation where it's colliding with something else. "Default" means AlwaysSpawn here.
|
||||||
|
/// </summary>
|
||||||
|
public ESpawnActorCollisionHandlingMethod SpawnCollisionHandlingMethod { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the value of Role without causing other side effects to this instance.
|
/// Sets the value of Role without causing other side effects to this instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -81,4 +89,22 @@ public class AActor : UObject
|
|||||||
{
|
{
|
||||||
return bActorInitialized;
|
return bActorInitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsPendingKillPending()
|
||||||
|
{
|
||||||
|
return bActorIsBeingDestroyed || IsPendingKill();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PostSpawnInitialize(FTransform userSpawnTransform, AActor? inOwner, AActor? inInstigator, bool bRemoteOwned, bool bNoFail, bool bDeferConstruction)
|
||||||
|
{
|
||||||
|
// General flow here is like so
|
||||||
|
// - Actor sets up the basics.
|
||||||
|
// - Actor gets PreInitializeComponents()
|
||||||
|
// - Actor constructs itself, after which its components should be fully assembled
|
||||||
|
// - Actor components get OnComponentCreated
|
||||||
|
// - Actor components get InitializeComponent
|
||||||
|
// - Actor gets PostInitializeComponents() once everything is set up
|
||||||
|
//
|
||||||
|
// This should be the same sequence for deferred or nondeferred spawning.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using Prospect.Unreal.Core.Names;
|
using Prospect.Unreal.Core.Names;
|
||||||
using Prospect.Unreal.Exceptions;
|
using Prospect.Unreal.Exceptions;
|
||||||
|
using Prospect.Unreal.Net.Actors;
|
||||||
using Prospect.Unreal.Net.Channels;
|
using Prospect.Unreal.Net.Channels;
|
||||||
using Prospect.Unreal.Net.Channels.Actor;
|
using Prospect.Unreal.Net.Channels.Actor;
|
||||||
using Prospect.Unreal.Net.Channels.Control;
|
using Prospect.Unreal.Net.Channels.Control;
|
||||||
@@ -269,6 +270,29 @@ public abstract class UNetDriver : IAsyncDisposable
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddNetworkActor(AActor actor)
|
||||||
|
{
|
||||||
|
// if (!IsDormInitialStartupActor(Actor))
|
||||||
|
// {
|
||||||
|
// GetNetworkObjectList().FindOrAdd(Actor, this);
|
||||||
|
// if (ReplicationDriver)
|
||||||
|
// {
|
||||||
|
// ReplicationDriver->AddNetworkActor(Actor);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveNetworkActor(AActor actor)
|
||||||
|
{
|
||||||
|
// Remove from renamed list if destroyed
|
||||||
|
// RenamedStartupActors.Remove(Actor->GetFName());
|
||||||
|
//
|
||||||
|
// if (ReplicationDriver)
|
||||||
|
// {
|
||||||
|
// ReplicationDriver->RemoveNetworkActor(Actor);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
public virtual ValueTask DisposeAsync()
|
public virtual ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
return ValueTask.CompletedTask;
|
return ValueTask.CompletedTask;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using Prospect.Unreal.Core;
|
using Prospect.Unreal.Core;
|
||||||
using Prospect.Unreal.Core.Math;
|
using Prospect.Unreal.Core.Math;
|
||||||
|
using Prospect.Unreal.Core.Names;
|
||||||
using Prospect.Unreal.Core.Objects;
|
using Prospect.Unreal.Core.Objects;
|
||||||
|
using Prospect.Unreal.Exceptions;
|
||||||
using Prospect.Unreal.Net;
|
using Prospect.Unreal.Net;
|
||||||
using Prospect.Unreal.Net.Actors;
|
using Prospect.Unreal.Net.Actors;
|
||||||
|
|
||||||
@@ -63,7 +65,7 @@ public partial class UWorld
|
|||||||
return SpawnActor(clazz, transform, spawnParameters);
|
return SpawnActor(clazz, transform, spawnParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AActor SpawnActor(UClass? clazz, FTransform userTransform, FActorSpawnParameters spawnParameters)
|
public AActor SpawnActor(UClass? clazz, FTransform? userTransformPtr, FActorSpawnParameters spawnParameters)
|
||||||
{
|
{
|
||||||
if (clazz == null)
|
if (clazz == null)
|
||||||
{
|
{
|
||||||
@@ -84,10 +86,91 @@ public partial class UWorld
|
|||||||
|
|
||||||
if (template == null)
|
if (template == null)
|
||||||
{
|
{
|
||||||
// template = clazz.GetDefaultObject();
|
template = (AActor)clazz.GetDefaultObject<AActor>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newActorName == EName.None)
|
||||||
|
{
|
||||||
|
// If we are using a template object and haven't specified a name, create a name relative to the template, otherwise let the default object naming behavior in Stat
|
||||||
|
if (!template.HasAnyFlags(EObjectFlags.RF_ClassDefaultObject))
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* else if (StaticFindObjectFast(nullptr, LevelToSpawnIn, NewActorName)) */
|
||||||
|
|
||||||
|
// See if we can spawn on ded.server/client only etc (check NeedsLoadForClient & NeedsLoadForServer)
|
||||||
|
// TODO: CanCreateInCurrentContext
|
||||||
|
|
||||||
|
var userTransform = userTransformPtr ?? new FTransform(); // TODO: FTransform::Identity
|
||||||
|
var collisionHandlingOverride = spawnParameters.SpawnCollisionHandlingOverride;
|
||||||
|
|
||||||
|
// "no fail" take preedence over collision handling settings that include fails
|
||||||
|
if (spawnParameters.bNoFail)
|
||||||
|
{
|
||||||
|
// maybe upgrade to disallow fail
|
||||||
|
if (collisionHandlingOverride == ESpawnActorCollisionHandlingMethod.AdjustIfPossibleButDontSpawnIfColliding)
|
||||||
|
{
|
||||||
|
collisionHandlingOverride = ESpawnActorCollisionHandlingMethod.AdjustIfPossibleButAlwaysSpawn;
|
||||||
|
}
|
||||||
|
else if (collisionHandlingOverride == ESpawnActorCollisionHandlingMethod.DontSpawnIfColliding)
|
||||||
|
{
|
||||||
|
collisionHandlingOverride = ESpawnActorCollisionHandlingMethod.AlwaysSpawn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use override if set, else fall back to actor's preference
|
||||||
|
var collisionHandlingMethod = (collisionHandlingOverride == ESpawnActorCollisionHandlingMethod.Undefined)
|
||||||
|
? template.SpawnCollisionHandlingMethod
|
||||||
|
: collisionHandlingOverride;
|
||||||
|
|
||||||
|
// see if we can avoid spawning altogether by checking native components
|
||||||
|
// note: we can't handle all cases here, since we don't know the full component hierarchy until after the actor is spawned
|
||||||
|
if (collisionHandlingMethod == ESpawnActorCollisionHandlingMethod.DontSpawnIfColliding)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var actorFlags = spawnParameters.ObjectFlags;
|
||||||
|
UPackage? externalPackage = null;
|
||||||
|
|
||||||
|
// actually make the actor object
|
||||||
|
var actor = UObjectGlobals.NewObject<AActor>(levelToSpawnIn, clazz, newActorName, actorFlags, template, false, null, externalPackage);
|
||||||
|
|
||||||
|
if (actor == null)
|
||||||
|
{
|
||||||
|
throw new UnrealException("Failed to create actor");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor.GetLevel() != levelToSpawnIn)
|
||||||
|
{
|
||||||
|
throw new UnrealException("Actor spawned with the incorrect level");
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
// tell the actor what method to use, in case it was overridden
|
||||||
|
actor.SpawnCollisionHandlingMethod = collisionHandlingMethod;
|
||||||
|
|
||||||
|
actor.PostSpawnInitialize(userTransform, spawnParameters.Owner, spawnParameters.Instigator, spawnParameters.bRemoteOwned, spawnParameters.bNoFail, spawnParameters.bDeferConstruction);
|
||||||
|
|
||||||
|
// if we are spawning an external actor, clear the dirty flag after post spawn initialize which might have dirtied the level package through running construction scripts
|
||||||
|
if (externalPackage != null)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor.IsPendingKill() && !spawnParameters.bNoFail)
|
||||||
|
{
|
||||||
|
// TODO: GetPathName
|
||||||
|
Logger.Debug("SpawnActor failed because the spawned actor %s IsPendingKill");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
actor.CheckDefaultSubobjects();
|
||||||
|
|
||||||
|
// Add this newly spawned actor to the network actor list. Do this after PostSpawnInitialize so that actor has "finished" spawning.
|
||||||
|
AddNetworkActor(actor);
|
||||||
|
|
||||||
|
return actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T SpawnActor<T>(UClass? clazz, FActorSpawnParameters spawnParameters) where T : AActor
|
public T SpawnActor<T>(UClass? clazz, FActorSpawnParameters spawnParameters) where T : AActor
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
|
|||||||
_owningGameInstance = null;
|
_owningGameInstance = null;
|
||||||
_authorityGameMode = null;
|
_authorityGameMode = null;
|
||||||
_levels = new List<ULevel>();
|
_levels = new List<ULevel>();
|
||||||
|
|
||||||
|
Url = new FUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -64,7 +66,7 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The URL that was used when loading this World.
|
/// The URL that was used when loading this World.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FUrl? Url { get; private set; }
|
public FUrl Url { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time in seconds since level began play, but IS paused when the game is paused, and IS dilated/clamped.
|
/// Time in seconds since level began play, but IS paused when the game is paused, and IS dilated/clamped.
|
||||||
@@ -156,7 +158,7 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
|
|||||||
var options = inUrl.OptionsToString();
|
var options = inUrl.OptionsToString();
|
||||||
|
|
||||||
// Set level info.
|
// Set level info.
|
||||||
if (!string.IsNullOrEmpty(inUrl.GetOption("load", null)))
|
if (string.IsNullOrEmpty(inUrl.GetOption("load", null)))
|
||||||
{
|
{
|
||||||
Url = inUrl;
|
Url = inUrl;
|
||||||
}
|
}
|
||||||
@@ -446,6 +448,49 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
|
|||||||
connection.SetClientLoginState(EClientLoginState.Welcomed);
|
connection.SetClientLoginState(EClientLoginState.Welcomed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AddNetworkActor(AActor? actor)
|
||||||
|
{
|
||||||
|
if (actor == null)
|
||||||
|
{
|
||||||
|
Logger.Verbose("Failed to add actor, null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor.IsPendingKillPending())
|
||||||
|
{
|
||||||
|
Logger.Verbose("Failed to add actor, IsPendingKillPending");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var level = actor.GetLevel();
|
||||||
|
if (level == null || !ContainsLevel(level))
|
||||||
|
{
|
||||||
|
Logger.Verbose("Failed to add actor, world does not contain level");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NetDriver != null)
|
||||||
|
{
|
||||||
|
NetDriver.AddNetworkActor(actor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveNetworkActor(AActor? actor)
|
||||||
|
{
|
||||||
|
if (actor != null)
|
||||||
|
{
|
||||||
|
if (NetDriver != null)
|
||||||
|
{
|
||||||
|
NetDriver.RemoveNetworkActor(actor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ContainsLevel(ULevel inLevel)
|
||||||
|
{
|
||||||
|
return _levels.Contains(inLevel);
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsServer()
|
public bool IsServer()
|
||||||
{
|
{
|
||||||
if (NetDriver != null)
|
if (NetDriver != null)
|
||||||
|
|||||||
Reference in New Issue
Block a user