Skip to content

An opinionated dotnet core integration for Unreal Engine

Notifications You must be signed in to change notification settings

lambda-snail/UnrealSharp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

73 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Project Paused

After starting this project i discovered that there is another project with the same name (naming stuff is hard) - UnrealSharp and also another project with almost the same name - UnrealCSharp. Since these projects are already doing what I aimed to do, and also have very similar names, I feel that I will have to rename the project and figure out where it is positioned in relation to the projects that already exist.

I have learned a lot from this project thought:

  • Writing plugins for UHT
  • Embedding dotnet in C++
  • Reading the source code of UBT
  • It lead to a PR to the Unreal source code

TL;DR

UnrealSharp attempts to add a dotnet core integration to some parts of Unreal Engine. It does this by creating what the dotnet documentation calls a "native host" in the context of a subsystem, and exposes functionality by generating P/Invoke bindings for dotnet using a header tool plugin. You can read more about this in my other repository dotnet-host-example where I play around with an example from Microsoft, and document some cases that were not really covered in the official channels (as far as I could tell).

The plugin is currently in an early stage and is probably not very useful at the moment.

Current Scope

The scope for version 1.0 is actor (and maybe character) integration and reducing boilerplate. In the future other classes may be supported as well.

My dream is to have a plugin where the user (developer) can work with his/her own dotnet code, using any nuget package they want etc., and using this without touching any of the internals of the plugin (this is currently impossible).

Current State

Dependencies

The UHT plugin that generates the bindings is currently using vyaml to read yaml comfiguration files. However, currently nuget packages do not work with UHT plugins (as far as I can tell).

I have made a pull request to the Unreal repo that should fix the issue, but if it is not accepted I will have to think of something else. The fix required is only one line though, so it's not too hard to do, but requiring users of a plugin to modify the build tool doesn't feel user friendly to me :)

Ticking

Currently, it is possible to register an actor with the subsystem, and have it tick each frame using code written in csharp. The Actor class in dotnet has properties for individually setting and getting the translation, rotation and scale of the C++ Actor, as well as getting and setting the Transform. The example provided uses dotnet to make an Actor float up and down:

public class TestActor : Actor
{
    private bool _shouldGoUp = true;
    private readonly float _speed = 100f;
    
    public override void Tick(float deltaTime)
    {
        Vector vector = Translation;

        float direction = _shouldGoUp ? 1f : -1f;
        vector.Z += (_speed * deltaTime * direction);
        if (vector.Z >= 400f || vector.Z <= 50f)
        {
            _shouldGoUp = !_shouldGoUp;
        }
        
        Translation = vector;
    }
}

This is achieved by creating extern "C" bindings which can then be used to P/Invoke back into the executable. We keep track of which C++ Actor instance is bound to which C# instance by storing a pointer to the actor, which is in turn used to get and set things on the native side. This requires some ugly things but these can be hidden in properties in the base class in C":

public Vector Translation
{
    get
    {
        ActorManager.GetTranslation(ActorPtr, out Vector vector);
        return vector;
    }
    set
    {
        ActorManager.SetTranslation(ActorPtr, ref value);
    }
}

As can be seen in the example, this allows us to expose a fairly intuitive api to the C# user:

Vector vector = Translation;
...
Translation = vector;

Generating Bindings

I am currently working on a Unreal Header Tool plugin that will generate the bindings when building the C++ code. This is done by specifying additional information in the meta tag of the UPROPERTY macro like so:

UPROPERTY(meta = (DotnetReadWrite = "true")) 
uint64 Int64Prop; 

This will generate binding code assuming that the property is public:

extern "C" __declspec(dllexport) inline void Get_Int64Prop(AUnrealSharpDemoActor const* Instance, void* Parameter) {
    auto* TypedPtr = static_cast<uint64*>(Parameter);
    *TypedPtr = Instance->Int64Prop;
}

Maybe we don't want to expose our properties for everyone to read and modify, in which case we can either use the reflection system:

UPROPERTY(meta = (DotnetReadWrite = "true", DotnetAccess = "Reflection")) 
uint32 Int32Prop;

Which leads to the following bindings getting generated:

extern "C" __declspec(dllexport) inline void Get_Int32Prop(AUnrealSharpDemoActor const* Instance, void* Parameter) {
    auto* TypedPtr = static_cast<uint32*>(Parameter);
    static FProperty* Property = AUnrealSharpDemoActor::StaticClass()->FindPropertyByName("Int32Prop");
    uint32 Val;Property->GetValue_InContainer(Instance, &Val);
    *TypedPtr = Val;
}

We can also provide our own member function for getting and setting:

private:
UPROPERTY(meta = (DotnetReadWrite = "true", DotnetAccess = "DoubleProp"))
double  DoubleProp;

public:
double GetDoubleProp() const { return {}; };
void SetDoubleProp(double Prop) {};

"DoubleProp" forms the base for the member function name and will generate bindings for GetDoubleProp and SetDoubleProp:

extern "C" __declspec(dllexport) inline void Get_DoubleProp(AUnrealSharpDemoActor const* Instance, void* Parameter) {
auto* TypedPtr = static_cast<double*>(Parameter);
*TypedPtr = Instance->GetDoubleProp();
}

At the current stage, these haven't been tested yet, so may work like a charm or not at all. I will update this README as I progress.

Configuration

To control the source generation, the plugin expects a yaml cofiguration file called unrealsharp.config.yml to be placed in the project directory.

This is currently a WIP (as many other things in here) and currently it looks something like this:

namespace-settings:
  default-namespace: 'LambdaSnail.UnrealSharp.Samples'
  namespace-perclass: true
  class-namespaceoverrides: # Not in use
    - 'override-1'
    - 'override-2'
dotnet-projectdirectory: 'C:\Users\blomb\Desktop\unrealsharp\'
type-mappings:
  map-overrides:
    FVector:
      dotnet-typename: Vector
      dotnet-namespace: LambdaSnail.UnrealSharp
      is-primitive: false

However, it is currently under heavy development and will be subject to change.

In Progress

  • Extend UHT: Design a way to automate the boilerplate required to set up a read/write of some data.

Todo (actor integration)

More functionality will be coming when I have the time :)

  • Clean up the Host files and incorporate into the subsystem where approproate. "Unrealify" the coding style.
  • See if we can build the UnrealSharpCore assembly automatically as part of Unreal's normal buid process.
  • Set up communication between dotnet and cpp to allow developers to read and write common data (e.g., transform data etc).
  • Decide how to handle common math operations etc that will be needed on the dotnet side. E.g., do we make FVector member functions available through callbacks, do we provide some external package for math operations, or do we leave the users to their own fates in this regard?
    • Thought: Since we are on dotnet core, the user could in theory use any nuget package they wish.
  • Decide what data to support (e.g., do we allow dotnet to get pointers to somehow subsystems, do we make it possible to manipulate animations etc.)
  • Set up a way for developers to provide their own dotnet assembly with their own types and register that in the system.
  • Nice to have Design a clean way for developers to extend the integration, by adding their own read and write callbacks for custom data.
  • Some example classes and documentation

License and Attribution

This project is licensed under the MIT license. It contains modified code from the official dotnet samples repository found here: https://github.com/dotnet/samples/tree/main/core/hosting

About

An opinionated dotnet core integration for Unreal Engine

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published