More actor and UObject progress

This commit is contained in:
AeonLucid
2022-01-17 23:02:10 +01:00
parent fe97b7a145
commit 458bae0523
24 changed files with 421 additions and 18 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ internal class Client
public async Task<UIpNetDriver> Connect(string ipAddr, int port, FUrl worldUrl) public async Task<UIpNetDriver> Connect(string ipAddr, int port, FUrl worldUrl)
{ {
var connection = new UIpNetDriver(System.Net.IPAddress.Parse(ipAddr), port, false); var connection = new UIpNetDriver(System.Net.IPAddress.Parse(ipAddr), port, false);
await using (var world = new ProspectWorld(worldUrl)) await using (var world = new ProspectWorld())
connection.InitConnect(world, new FUrl { Host = System.Net.IPAddress.Parse(ipAddr), Port = port }); connection.InitConnect(world, new FUrl { Host = System.Net.IPAddress.Parse(ipAddr), Port = port });
UnitConn = connection.ServerConnection; UnitConn = connection.ServerConnection;
connection.ServerConnection.Handler?.BeginHandshaking(SendInitialJoin); connection.ServerConnection.Handler?.BeginHandshaking(SendInitialJoin);
+6
View File
@@ -0,0 +1,6 @@
namespace Prospect.Unreal.Core.Math;
public class FQuat
{
}
@@ -0,0 +1,6 @@
namespace Prospect.Unreal.Core.Math;
public class FRotator
{
}
@@ -0,0 +1,7 @@
namespace Prospect.Unreal.Core.Math;
public ref struct FTransform
{
public FVector Location { get; set; }
public FRotator Rotation { get; set; }
}
+6
View File
@@ -0,0 +1,6 @@
namespace Prospect.Unreal.Core.Math;
public class FVector
{
}
@@ -1,4 +1,4 @@
namespace Prospect.Unreal.Core; namespace Prospect.Unreal.Core.Objects;
[Flags] [Flags]
public enum EObjectFlags public enum EObjectFlags
@@ -0,0 +1,18 @@
namespace Prospect.Unreal.Core.Objects;
/// <summary>
/// Custom class to help with <code>T::StaticClass()</code> code.
/// </summary>
public class GUClassArray
{
public static UClass StaticClass<T>()
{
return StaticClass(typeof(T));
}
public static UClass StaticClass(Type type)
{
// TODO: Implement
return new UClass();
}
}
@@ -0,0 +1,6 @@
namespace Prospect.Unreal.Core.Objects;
public static class GUObjectArray
{
}
@@ -0,0 +1,8 @@
using Prospect.Unreal.Core.Properties;
namespace Prospect.Unreal.Core.Objects;
public class UClass : UStruct
{
}
@@ -0,0 +1,6 @@
namespace Prospect.Unreal.Core.Objects;
public class UObject : UObjectBaseUtility
{
}
@@ -0,0 +1,85 @@
using System.Runtime.CompilerServices;
using Prospect.Unreal.Core.Names;
namespace Prospect.Unreal.Core.Objects;
public class UObjectBase
{
/// <summary>
/// Flags used to track and report various object states.
/// </summary>
private EObjectFlags _objectFlags;
/// <summary>
/// Index into GObjectArray...very private.
/// </summary>
private int _internalIndex;
/// <summary>
/// Class the object belongs to.
/// </summary>
private UClass _classPrivate;
/// <summary>
/// Name of this object.
/// </summary>
private FName _namePrivate;
/// <summary>
/// Object this object resides in.
/// </summary>
private UObject? _outerPrivate;
public UObjectBase()
{
}
/// <summary>
/// Returns the unique ID of the object...these are reused so it is only unique while the object is alive.
/// Useful as a tag.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint GetUniqueID()
{
return (uint)_internalIndex;
}
/// <summary>
/// Returns the UClass that defines the fields of this object.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public UClass GetClass()
{
return _classPrivate;
}
/// <summary>
/// Returns the UObject this object resides in.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public UObject? GetOuter()
{
return _outerPrivate;
}
/// <summary>
/// Returns the logical name of this object.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public FName GetFName()
{
return _namePrivate;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected void SetFlagsTo(EObjectFlags newFlags)
{
_objectFlags = newFlags;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EObjectFlags GetFlags()
{
return _objectFlags;
}
}
@@ -0,0 +1,79 @@
using System.Runtime.CompilerServices;
namespace Prospect.Unreal.Core.Objects;
public class UObjectBaseUtility : UObjectBase
{
/*
* Flags
*/
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetFlags(EObjectFlags newFlags)
{
SetFlagsTo(GetFlags() | newFlags);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ClearFlags(EObjectFlags newFlags)
{
SetFlagsTo(GetFlags() | ~newFlags);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasAnyFlags(EObjectFlags flagsToCheck)
{
return (GetFlags() & flagsToCheck) != 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasAllFlags(EObjectFlags flagsToCheck)
{
return (GetFlags() & flagsToCheck) == flagsToCheck;
}
/*
* Marks
*/
public bool IsUnreachable()
{
// TODO: GUObjectArray
return false;
}
/*
* Outer & Package
*/
public UObject? GetTypedOuter(UClass target)
{
UObject? result = null;
for (var nextOuter = GetOuter(); result == null && nextOuter != null; nextOuter = nextOuter.GetOuter())
{
if (nextOuter.IsA(target))
{
result = nextOuter;
}
}
return result;
}
public T? GetTypedOuter<T>() where T : UObject
{
return (T?)GetTypedOuter(GUClassArray.StaticClass<T>());
}
/*
* Class
*/
public bool IsChildOfWorkaround(UClass objClass, UClass testClass)
{
return objClass.IsChildOf(testClass);
}
public bool IsA(UClass someBase)
{
var someBaseClass = someBase;
var thisClass = GetClass();
return IsChildOfWorkaround(thisClass, someBaseClass);
}
}
@@ -0,0 +1,8 @@
using Prospect.Unreal.Core.Objects;
namespace Prospect.Unreal.Core.Properties;
public class UField : UObject
{
}
@@ -0,0 +1,37 @@
namespace Prospect.Unreal.Core.Properties;
public class UStruct : UField
{
private UStruct? _superStruct;
public bool IsChildOf(UStruct? someBase)
{
if (someBase == null)
{
return false;
}
var bOldResult = false;
for (var tempStruct = this; tempStruct != null; tempStruct = tempStruct.GetSuperStruct())
{
if (tempStruct == someBase)
{
bOldResult = true;
break;
}
}
return bOldResult;
}
public UStruct? GetSuperStruct()
{
return _superStruct;
}
public virtual void SetSuperStruct(UStruct newSuperStruct)
{
_superStruct = newSuperStruct;
}
}
+11 -2
View File
@@ -1,8 +1,10 @@
using Prospect.Unreal.Net.Actors; using Prospect.Unreal.Core.Objects;
using Prospect.Unreal.Net.Actors;
using Prospect.Unreal.Runtime;
namespace Prospect.Unreal.Core; namespace Prospect.Unreal.Core;
public class ULevel public class ULevel : UObject
{ {
public ULevel() public ULevel()
{ {
@@ -19,6 +21,13 @@ public class ULevel
/// </summary> /// </summary>
public List<AActor> Actors { get; private set; } public List<AActor> Actors { get; private set; }
/// <summary>
/// The World that has this level in its Levels array.
/// This is not the same as GetOuter(), because GetOuter() for a streaming level is a vestigial world that is not used.
/// It should not be accessed during BeginDestroy(), just like any other UObject references, since GC may occur in any order.
/// </summary>
public UWorld OwningWorld { get; private set; }
public void InitializeNetworkActors() public void InitializeNetworkActors()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
-6
View File
@@ -1,6 +0,0 @@
namespace Prospect.Unreal.Core;
public class UObject
{
}
+39 -3
View File
@@ -1,12 +1,19 @@
using Prospect.Unreal.Core; using Prospect.Unreal.Core;
using Prospect.Unreal.Core.Objects;
using Prospect.Unreal.Runtime; using Prospect.Unreal.Runtime;
namespace Prospect.Unreal.Net.Actors; namespace Prospect.Unreal.Net.Actors;
public class AActor public class AActor : UObject
{ {
private bool bActorInitialized; private bool bActorInitialized;
// TODO: UPROPERTY(BlueprintReadWrite, ReplicatedUsing=OnRep_Instigator, meta=(ExposeOnSpawn=true, AllowPrivateAccess=true), Category=Actor)
/// <summary>
/// Pawn responsible for damage and other gameplay events caused by this actor.
/// </summary>
private APawn? _instigator;
/// <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>
@@ -36,9 +43,38 @@ public class AActor
throw new NotImplementedException(); throw new NotImplementedException();
} }
public UWorld GetWorld() public UWorld? GetWorld()
{ {
// if () if (!HasAnyFlags(EObjectFlags.RF_ClassDefaultObject))
{
var outer = GetOuter();
if (outer == null)
{
return null;
}
if (!outer.HasAnyFlags(EObjectFlags.RF_BeginDestroyed) &&
!outer.IsUnreachable())
{
var level = GetLevel();
if (level != null)
{
return level.OwningWorld;
}
}
}
return null;
}
public ULevel? GetLevel()
{
return GetTypedOuter<ULevel>();
}
public APawn? GetInstigator()
{
return _instigator;
} }
public bool IsActorInitialized() public bool IsActorInitialized()
@@ -1,4 +1,5 @@
using Prospect.Unreal.Core; using Prospect.Unreal.Core;
using Prospect.Unreal.Core.Objects;
using Prospect.Unreal.Runtime; using Prospect.Unreal.Runtime;
namespace Prospect.Unreal.Net.Actors; namespace Prospect.Unreal.Net.Actors;
@@ -19,6 +20,12 @@ public class AGameModeBase : AInfo
public virtual void InitGame(string mapName, string options, out string errorMessage) public virtual void InitGame(string mapName, string options, out string errorMessage)
{ {
// Default error.
errorMessage = string.Empty;
// Find world.
var world = GetWorld();
// Save Options for future use // Save Options for future use
OptionsString = options; OptionsString = options;
@@ -28,7 +35,7 @@ public class AGameModeBase : AInfo
ObjectFlags = EObjectFlags.RF_Transient ObjectFlags = EObjectFlags.RF_Transient
}; };
GameSession = World.SpawnActor(); // GameSession = world.SpawnActor();
} }
public virtual void InitGameState() public virtual void InitGameState()
+6
View File
@@ -0,0 +1,6 @@
namespace Prospect.Unreal.Net.Actors;
public class APawn : AActor
{
}
@@ -1,5 +1,6 @@
using Prospect.Unreal.Core; using Prospect.Unreal.Core;
using Prospect.Unreal.Core.Names; using Prospect.Unreal.Core.Names;
using Prospect.Unreal.Core.Objects;
using Prospect.Unreal.Net.Actors; using Prospect.Unreal.Net.Actors;
namespace Prospect.Unreal.Net; namespace Prospect.Unreal.Net;
@@ -10,7 +11,7 @@ public ref struct FActorSpawnParameters
/// A name to assign as the Name of the Actor being spawned. /// 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]. /// If no value is specified, the name of the spawned Actor will be automatically generated using the form [Class]_[Number].
/// </summary> /// </summary>
public FName? Name { get; set; } public FName Name { get; set; } = EName.None;
/// <summary> /// <summary>
/// An Actor to use as a template when spawning the new Actor. /// An Actor to use as a template when spawning the new Actor.
+10 -1
View File
@@ -1,4 +1,6 @@
using Prospect.Unreal.Core; using Prospect.Unreal.Core;
using Prospect.Unreal.Core.Objects;
using Prospect.Unreal.Net;
using Prospect.Unreal.Net.Actors; using Prospect.Unreal.Net.Actors;
namespace Prospect.Unreal.Runtime; namespace Prospect.Unreal.Runtime;
@@ -8,6 +10,13 @@ public class UGameInstance
public AGameModeBase? CreateGameModeForURL(FUrl inUrl, UWorld inWorld) public AGameModeBase? CreateGameModeForURL(FUrl inUrl, UWorld inWorld)
{ {
// TODO: World.SpawnActor // TODO: World.SpawnActor
return new AGameModeBase();
var spawnInfo = new FActorSpawnParameters
{
SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod.AlwaysSpawn,
ObjectFlags = EObjectFlags.RF_Transient
};
return inWorld.SpawnActor<AGameModeBase>(GUClassArray.StaticClass<AGameModeBase>(), spawnInfo);
} }
} }
@@ -1,5 +1,7 @@
using System.Text; using System.Text;
using Prospect.Unreal.Core; using Prospect.Unreal.Core;
using Prospect.Unreal.Core.Math;
using Prospect.Unreal.Core.Objects;
using Prospect.Unreal.Net; using Prospect.Unreal.Net;
using Prospect.Unreal.Net.Actors; using Prospect.Unreal.Net.Actors;
@@ -42,4 +44,54 @@ public partial class UWorld
Logger.Warning("Login failed: No game mode set"); Logger.Warning("Login failed: No game mode set");
return null; return null;
} }
public AActor SpawnActor(UClass? clazz, FVector? location, FRotator? rotation, FActorSpawnParameters spawnParameters)
{
var transform = new FTransform();
if (location != null)
{
transform.Location = location;
}
if (rotation != null)
{
// TODO: FQuat
// transform.Rotation =
}
return SpawnActor(clazz, transform, spawnParameters);
}
public AActor SpawnActor(UClass? clazz, FTransform userTransform, FActorSpawnParameters spawnParameters)
{
if (clazz == null)
{
Logger.Warning("SpawnActor failed because no class was specified");
return null;
}
// TODO: Bunch of if checks
var levelToSpawnIn = spawnParameters.OverrideLevel;
if (levelToSpawnIn == null)
{
// Spawn in the same level as the owner if we have one.
levelToSpawnIn = (spawnParameters.Owner != null) ? spawnParameters.Owner.GetLevel() : _currentLevel;
}
var newActorName = spawnParameters.Name;
var template = spawnParameters.Template;
if (template == null)
{
// template = clazz.GetDefaultObject();
}
return null;
}
public T SpawnActor<T>(UClass? clazz, FActorSpawnParameters spawnParameters) where T : AActor
{
return (T)SpawnActor(clazz, null, null, spawnParameters);
}
} }
+18 -2
View File
@@ -1,5 +1,6 @@
using Prospect.Unreal.Core; using Prospect.Unreal.Core;
using Prospect.Unreal.Core.Names; using Prospect.Unreal.Core.Names;
using Prospect.Unreal.Core.Objects;
using Prospect.Unreal.Exceptions; using Prospect.Unreal.Exceptions;
using Prospect.Unreal.Net; using Prospect.Unreal.Net;
using Prospect.Unreal.Net.Actors; using Prospect.Unreal.Net.Actors;
@@ -16,8 +17,18 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
private UGameInstance? _owningGameInstance; private UGameInstance? _owningGameInstance;
private AGameModeBase? _authorityGameMode; private AGameModeBase? _authorityGameMode;
/// <summary>
/// Array of levels currently in this world. Not serialized to disk to avoid hard references.
/// </summary>
private List<ULevel> _levels; private List<ULevel> _levels;
/// <summary>
/// Pointer to the current level being edited.
/// Level has to be in the Levels array and == PersistentLevel in the game.
/// </summary>
private ULevel? _currentLevel;
public UWorld() public UWorld()
{ {
_owningGameInstance = null; _owningGameInstance = null;
@@ -40,6 +51,11 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
/// </summary> /// </summary>
public bool bActorsInitialized { get; private set; } public bool bActorsInitialized { get; private set; }
/// <summary>
/// Is the world in its actor initialization phase.
/// </summary>
public bool bStartup { get; private set; }
/// <summary> /// <summary>
/// Whether BeginPlay has been called on actors /// Whether BeginPlay has been called on actors
/// </summary> /// </summary>
@@ -149,9 +165,9 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable
if (!AreActorsInitialized()) if (!AreActorsInitialized())
{ {
// Initialize network actors and start execution. // Initialize network actors and start execution.
for (int i = 0; i < _levels.Count; i++) foreach (var level in _levels)
{ {
_levels[i].InitializeNetworkActors(); level.InitializeNetworkActors();
} }
// Enable actor script calls. // Enable actor script calls.
@@ -1,5 +1,6 @@
using Prospect.Unreal.Core; using Prospect.Unreal.Core;
using Prospect.Unreal.Core.Names; using Prospect.Unreal.Core.Names;
using Prospect.Unreal.Core.Objects;
using Prospect.Unreal.Net; using Prospect.Unreal.Net;
namespace Prospect.Unreal.Serialization; namespace Prospect.Unreal.Serialization;