SpawnActor stuff

This commit is contained in:
AeonLucid
2022-01-18 03:13:56 +01:00
parent 458bae0523
commit 16ab2aeb48
11 changed files with 262 additions and 9 deletions
@@ -1,7 +1,9 @@
using System.Text;
using Prospect.Unreal.Core;
using Prospect.Unreal.Core.Math;
using Prospect.Unreal.Core.Names;
using Prospect.Unreal.Core.Objects;
using Prospect.Unreal.Exceptions;
using Prospect.Unreal.Net;
using Prospect.Unreal.Net.Actors;
@@ -63,7 +65,7 @@ public partial class UWorld
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)
{
@@ -84,10 +86,91 @@ public partial class UWorld
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
+47 -2
View File
@@ -34,6 +34,8 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
_owningGameInstance = null;
_authorityGameMode = null;
_levels = new List<ULevel>();
Url = new FUrl();
}
/// <summary>
@@ -64,7 +66,7 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
/// <summary>
/// The URL that was used when loading this World.
/// </summary>
public FUrl? Url { get; private set; }
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.
@@ -156,7 +158,7 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
var options = inUrl.OptionsToString();
// Set level info.
if (!string.IsNullOrEmpty(inUrl.GetOption("load", null)))
if (string.IsNullOrEmpty(inUrl.GetOption("load", null)))
{
Url = inUrl;
}
@@ -446,6 +448,49 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
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()
{
if (NetDriver != null)