Skip to main content

2022 Nov: Entity System, UDS & UE5.1!

· 9 min read
Gabriel T. Nardy
nanos world developer (SyedMuhammad)

Entity System, UDS & UE5.1!

Refactor Releases​

As announced in the last Blog News, we are performing a series of refactoring in the API to standardize it better. We have a long list of changes and I'm doing them gradually.

The main one that allowed us to make more changes without breaking compatibility is the compatibility_version released in the last update. This configuration on Package.toml will ensure that the package continues to work in future updates in cases of breakage changes.

Also we've already got our first feature to try the compatibility_version system: the new Events.SubscribeRemote method! This method will subscribe only for remote called methods, splitting completely the behavior of subscribing for Local and Remote events. The change of this method caused a breaking change because all existing Events.Subscribe will no longer trigger with remote Events. But compatibility_version ensures that they continue to work until you update the value to version 1.22 or more recent.

I'm working on several Static Class refactoring as well and also changing some names of methods (e.g. HTTP.RequestSync will be standardized into just HTTP.Request and the async version would become HTTP.RequestAsync).

I reinforce again that if you have suggestions on other changes such as event or methods names, do not hesitate to say it! Big refactoring opportunities like this are rare!

Entity & Inheriting System​

This is a very special update which I've been working in the past months! 🥳

The new Inheriting System is an addition that completely changes the paradigm of creating scripts! This system allows you to inherit existing classes to create your own custom classes and spawn them as if they were native!

-- Creates a new Class called "MyNewClass" inheriting from Prop
MyNewClass = Prop.Inherit("MyNewClass")

-- Spawn it using the default constructor
local ent = MyNewClass(Vector(), Rotator(), "nanos-world::SM_Cube")

Built-in Events​

Native events will return your class instead of the native class. E.g.:

-- This will trigger for all Props and it's descendents,
-- and the value of 'prop' will be the children itself
Prop.Subscribe("Destroy", function(prop)
-- You can check if an entity is from a inherited Class type!
-- IsA checks recursively if any parent is from that type
if (NanosUtils.IsA(prop, MyCube)) then
-- prop is of type MyCube
end
end)

Custom Methods​

Easily add new methods to your class!

MyNewClass = Prop.Inherit("MyNewClass")

function MyNewClass:MyMethod()
-- Do something
end

Custom Constructors​

This system also allows the creation of personalized constructors:

-- Creates a new Class called "MyCube" inheriting from Prop
MyCube = Prop.Inherit("MyCube")

-- Defines my constructor with any parameters you desire
function MyCube:Constructor(loc, rot)
-- Do any kind of logic here
loc = loc + Vector(0, 0, 100)

-- Calls Super Constructor to finalize the construction
self.Super:Constructor(loc, rot, "nanos-world::SM_Cube")
end

-- Spawn it using your custom constructor
local cube = MyCube(Vector(123, 456, 100), Rotator())

Multiple Inheritance​

We can inherit from other inherited classes as well!

MyCube = Prop.Inherit("MyCube")
MyMiniCube = MyCube.Inherit("MyMiniCube")
MySuperMiniCube = MyMiniCube.Inherit("MySuperMiniCube")

Custom Entity Events​

Now we have the possibility to trigger remote events on custom Classes, to allow easy networking communication:

Client/Index.lua
function MyCube:OnMyAnotherEvent(my_param)
Console.Log(my_param)
end

MyCube.SubscribeRemote("MyAnotherEvent", MyCube.OnMyAnotherEvent)

local my_cube = MyCube()
my_cube:CallRemoteEvent("MyCustomEvent", 123)
Server/Index.lua
function MyCube:OnMyCustomEvent(player, my_param)
self:BroadcastRemoteEvent("MyAnotherCustomEvent", "hello")
end

MyCube.SubscribeRemote("MyCustomEvent", MyCube.OnMyCustomEvent)

Global Registry​

Through the parent class, we can get a list of all children classes of that class, having a global registry of all existing classes!

local children_classes = ToolGun.GetInheritedClasses()
for _, class in pairs(children_classes) do
-- 'class' is a custom inherited class! we can spawn it
local p = class()
end

Further Reading​

There's much more! Like entity events or calling parent methods! Read about everything at the Dedicated Documentation Page.

Sandbox Improvements​

With this new Entity System, I'm taking the time to do some improvements in Sandbox game-mode, as now this system allows a better organization of how things interacts with each other.

Entities​

I'm converting almost everything into this Entity System, for example the Torch (Melee at spawn menu) now becomes a Torch entity inherited from Melee:

Torch = Melee.Inherit("Torch")

function Torch:Constructor(location, rotation)
self.Super:Constructor(location or Vector(), rotation or Rotator(), "nanos-world::SM_Torch")
self:AddAnimationCharacterUse("nanos-world::AM_Mannequin_Torch_Attack")
self:SetImpactSound(SurfaceType.Flesh, "nanos-world::A_Punch_Cue")
self:SetDamageSettings(0.5, 0.25)
self:SetCooldown(1.5)
self:SetBaseDamage(25)

local light = Light(Vector(), Rotator(), Color(1, 0.7, 0.4), LightType.Point, 100, 1000)
light:AttachTo(self, AttachmentRule.SnapToTarget, "", 0)
light:SetRelativeLocation(Vector(0, 0, 75))

local particle = Particle(Vector(), Rotator(), "nanos-world::P_Fire", false)
particle:AttachTo(self, AttachmentRule.SnapToTarget, "", 0)
particle:SetRelativeLocation(Vector(0, 0, 50))
end

And we can spawn it like that:

local my_torch = Torch(Vector(), Rotator())

Spawn Menu​

I'm trying to get rid of the "AddSpawnMenuItem" functions. And instead replace everything by the Inherit Registry System which you inherit from a Class and it shows up in the Spawn Menu like magic!

For example we are be able to Melee.GetInheritedClasses() and get all custom Melees Classes (like Torch) which were defined in this Package, and display them in the Spawn Menu automatically!

Tools​

Now we will have a base class for the Tools called ToolGun. With that we can just inherit from this class to create new Tools, which will be automatically displayed on Spawn Menu and work as a Tool Gun!

See how the Balloon Gun is defined now:

BalloonGun = ToolGun.Inherit("BalloonGun")

function BalloonGun:Constructor(location, rotation)
-- Calls parent ToolGun constructor
ToolGun.Constructor(self, location, rotation, Color.VIOLET)
end

function BalloonGun:OnSpawnBalloon(player, location, ...)
-- Do the original logic here...
...

-- Spawns a Balloon entity!
local balloon = Balloon(location, rotation, ...)
end

BalloonGun.SubscribeRemote("SpawnBalloon", BalloonGun.OnSpawnBalloon)

And on Client we just define it and set some properties which will be read from the Tool Gun and the Spawn Menu:

BalloonGun = ToolGun.Inherit("BalloonGun")

-- Defines some properties used by ToolGun and SpawnMenu
BalloonGun.name = "Balloon"
BalloonGun.image = "package://sandbox/Client/Tools/BalloonGun.webp"
BalloonGun.tutorials = {
{ key = "LeftClick", text = "spawn balloon" },
{ key = "Undo", text = "undo spawn" },
{ key = "ContextMenu", text = "balloon settings" },
}

function BalloonGun:OnFire(shooter)
-- Do the original logic here...
...

-- Calls remote to spawn the Balloon
self:CallRemoteEvent("SpawnBalloon", location, rotation, ...)
end

BalloonGun.Subscribe("Fire", BalloonGun.OnFire)

And that's it! No needs to call any "AddToSpawnMenu" function anymore! We just need to inherit a known class of it!

tip

Note we have defined a class called Balloon which is the new implementation of the balloon. 😉

Context Menu​

Also, I'm doing some improvements on the Context Menu and make it more modular. Now it allows adding new entries dynamically, which I'll be integrating with the ToolGun systems to allow tools customization, look at this example of using the Balloon Gun with it:

This new ContextMenu allows customizing it 100% through Lua, without needing to add new hardcoded HTML/JS entries on it.

Unreal Engine 5.1​

This month, Epic Games released Unreal Engine 5.1. This is a long-awaited version for us, especially for the expected corrections.

The upgrade is being smooth, the hardest part of those upgrades is forcing everyone to upgrade it's assets and projects too.

Physics and Cables​

Cables rendering and Physics Constraints were completely broken since 5.0, I've even reported that as bug to Epic and they fixed both problems but delayed the release just to 5.1.

But finally we can be happy again with the balloons physics working perfectly! 😎

Nanite & Lumen​

Both system got great upgrades since 5.0, but one drawback of using the newest technologies is that we will need to enforce the game client uses DirectX 12, as it's a requirement for Nanite and some Lumen features to work.

I will still do some studies on if we should or not force DX12, I don't want to have unforeseen consequences in the future by taking a decision like that.

Ultra Dynamic Sky​

Ultra Dynamic Sky is one of best Unreal Marketplace Asset Packs, it provides a dynamic sky and weather solution for games!

I decided to include this sky system natively in nanos world. It will replace our existing DefaultSun (on World class) with a new Static Class: Sky, which will be released soon™ along with the Unreal 5.1 update!

If you don't know it yet, see this product video of your features:

Conclusion​

The update of the new entity system is huge! And I am very happy with the result, it's usability got really simple and that opens too many new possibilities!

This change will allow nanos world to advance to another level on scripting capabilities. I'm studying more ways to allow even easier methods for creating custom scripts extensions, such as a way for you to create your entities that are dynamically loaded on a package, without you need to manually load them by Package.Require in the original package.

Just by the fact that now we can simply define a new class inheriting from another and that is enough for it to be displayed in the Sandbox's Spawn Menu is already amazing!

I wish to finish the still-going refactoring of the Static Classes, and also to start renaming some non-standardized Class methods. The compatibility mode feature will help a lot of us keeping things working with those changes. And as soon as possible my wish to release the UE 5.1 update to everyone, this last one will be the most painful one as require us to recook and update all assets in the store. 😜

Also, I wish to start a discussion at Discord about the future of the Extending Classes, it's currently working regardless of the new Inheriting system, but it has several problems that I want your opinion to decide the future of it.

Hope you enjoy it! Feedback appreciated! See you next month!