# UnrealSharp
## Introduction
UnrealSharp is a plugin for Unreal Engine 5 that allows game developers to use C# in their projects with the power of .NET 9. This plugin bridges the gap between C# and UE5, providing a seamless and efficient workflow for those who prefer C# over C++/Blueprints.
[Workflow Showcase](https://www.youtube.com/watch?v=NdbiysPTztA)
## Features
- **C# Integration**: Write your game logic in C#.
- **Seamless Unreal Engine 5 Compatibility**: Fully integrated with the latest UE5 features and API.
- **Hot reload:** Compile and reload code on the fly without having to restart the engine for changes.
- **Automatic Bindings:** Automatically generates C# API based on what is exposed to reflection.
- **.NET Ecosystem:** Use any NuGet package to extend functionality.
## Sample Project
Check out [UnrealSharp-Cropout](https://github.com/UnrealSharp/UnrealSharp-Cropout/tree/main), an ongoing effort to convert [Cropout](https://www.unrealengine.com/en-US/blog/cropout-casual-rts-game-sample-project), originally created in Blueprints, into C# using UnrealSharp.
## Prerequisites
- Unreal Engine 5.3 - 5.5
- .NET 9.0+
## Frequently Asked Questions
[FAQ](https://www.unrealsharp.com/faq)
## Get Started
Visit the website's [Get Started](https://www.unrealsharp.com/getting-started/quickstart) page!
If you want to contribute with documentation, you can contribute to this [repository](https://github.com/UnrealSharp/unrealsharp.github.io)!
## Code Example
```c#
using UnrealSharp;
using UnrealSharp.Attributes;
using UnrealSharp.Engine;
using UnrealSharp.Niagara;
namespace ManagedSharpProject;
public delegate void OnIsPickedUp(bool bIsPickedUp);
[UClass]
// Partial classes are only a requirement if you want UnrealSharp to generate helper methods.
// Such as: MyCustomComponent foundComponent = MyCustomComponent.Get(actorReference);
public partial class AResourceBase : AActor, IInteractable
{
public AResourceBase()
{
SetReplicates(true);
RespawnTime = 500.0f;
}
// The mesh of the resource
[UProperty(DefaultComponent = true, RootComponent = true)]
public UStaticMeshComponent Mesh { get; set; }
// The health component of the resource, if it has one
[UProperty(DefaultComponent = true)]
public UHealthComponent HealthComponent { get; set; }
[UProperty(PropertyFlags.EditDefaultsOnly)]
public int PickUpAmount { get; set; }
// The time it takes for the resource to respawn
[UProperty(PropertyFlags.EditDefaultsOnly | PropertyFlags.BlueprintReadOnly)]
protected float RespawnTime { get; set; }
// Whether the resource has been picked up, is replicated to clients.
[UProperty(PropertyFlags.BlueprintReadOnly, ReplicatedUsing = nameof(OnRep_IsPickedUp))]
protected bool bIsPickedUp { get; set; }
// The effect to play when the resource is picked up
[UProperty(PropertyFlags.EditDefaultsOnly)]
public TSoftObjectPtr<UNiagaraSystem>? PickUpEffect { get; set; }
// The delegate to call when the resource is picked up, broadcasts on clients too.
[UProperty(PropertyFlags.BlueprintAssignable)]
public TMulticastDelegate<OnIsPickedUp> OnIsPickedUp { get; set; }
protected override void BeginPlay()
{
HealthComponent.OnDeath += OnDeath;
base.BeginPlay();
}
[UFunction]
protected virtual void OnDeath(APlayer player) {}
// Interface method implementation
public void OnInteract(APlayer player)
{
GatherResource(player);
}
[UFunction(FunctionFlags.BlueprintCallable)]
protected void GatherResource(APlayer player)
{
if (bIsPickedUp)
{
return;
}
if (!player.Inventory.AddItem(this, PickUpAmount))
{
return;
}
// Get the ExperienceComponent from the PlayerState using the generated helper methods.
UExperienceComponent experienceComponent = UExperienceComponent.Get(player.PlayerState);
experienceComponent.AddExperience(PickUpAmount);
// Respawn the resource after a certain amount of time
SetTimer(OnRespawned, RespawnTime, false);
bIsPickedUp = true;
OnRep_IsPickedUp();
}
[UFunction]
public void OnRespawned()
{
bIsPickedUp = false;
OnRep_IsPickedUp();
}
// This is called when the bIsPickedUp property is replicated
[UFunction]
public void OnRep_IsPickedUp()
{
if (PickUpEffect is not null)
{
UNiagaraFunctionLibrary.SpawnSystemAtLocation(this, PickUpEffect, GetActorLocation(), GetActorRotation());
}
OnIsPickedUpChanged(bIsPickedUp);
OnIsPickedUp.Invoke(bIsPickedUp);
}
// This can be overridden in blueprints
[UFunction(FunctionFlags.BlueprintEvent)]
public void OnIsPickedUpChanged(bool bIsPickedUp)
{
SetActorHiddenInGame(bIsPickedUp);
}
}
```
## Roadmap
Take a look at the roadmap for planned and developed features!
[Roadmap](https://github.com/orgs/UnrealSharp/projects/3)
## Discord Community
Join the discord community to stay up to date with the recent updates and plugin support!
[Discord community](https://discord.gg/HQuJUYFxeV)
## Contributing
I accept pull requests and any contributions you make are **greatly appreciated**.
## License
Distributed under the MIT License. See `LICENSE` for more information.
## Contact
Discord: **olsson.** (Yes, with a dot at the end.)
Or join the [Discord community](https://discord.gg/HQuJUYFxeV).
## Special Thanks
I'd like to give a huge shoutout to [MonoUE](https://mono-ue.github.io/) (Sadly abandoned :( ) for the great resource for integrating C# into Unreal Engine. Some of the systems are modified versions of their integration, and it's been a real time saver.
**Thank you to the MonoUE team!**