Dec: One VM to Rule Them All!
One Lua Virtual Machine to Rule Them All!
One Lua Virtual Machine
After much analysis, study and refactoring. I am happily introducing the new way the Packages will work! This was heavily motivated by the lack of possibility of creating extensions or customized items in an easy way.
In addition to the last new Entity System update, this change will heavily add to the possibilities of modding & scripting capabilities to nanos world!
Those changes are meant to have as little as possible impact and breaking changes, all tests I did so far assured everything is still backward compatible!
So far, we had one VM (Virtual Machine - or lua_State
) created per Package. This caused each Package to be completely isolated from each other. Therefore it was necessary to create mechanisms for communication between the Packages, such as Events and Package.Export/Package.Call methods, which allowed (in a limited way) Packages to communicate with each other.
But as mentioned, this brought many limitations, such as it was not possible for Packages to access variables or call functions directly from other Packages, or even worse (which become more evident from the last update of Entity System): It was not possible to share custom classes between Packages!
However now all of this will be solved! I reworked the entire internal scripting system, and now instead of having a new virtual machine per Package, we will have a virtualized sandboxed environment (using Lua environment _ENV
feature), separating the scope of each Package but allowing them to access a global shared environment!
This will allow the Packages to define classes, expose functions and share libraries globally! So that everyone else can use without the need for workaround mechanisms to do so!
Now, for example you can just load additional scripts together the sandbox
game-mode which loads custom Classes of tools or weapons, and those will appear automatically in the Spawn Menu, no need for manually adding them anymore!
Each Package will still have it's own sub-global environment, so defining global variables or functions will not make them available to other packages immediately.
Call & Export
Package.Call
and Package.Export
are not necessary in the traditional way anymore. As now we can share the global environment, we can define methods and expose them to be called directly, without the need to Package.Call
them.
The Package.Export
will still exist and work similarly. But now it will be possible to "expose" any value to the global scope! Example:
local my_table = { 123, 456 }
function DoSomething(var1)
return var1 + 123
end
Package.Export("MyTable", my_table)
Package.Export("DoSomething", DoSomething)
Console.Log(MyTable[1])
-- 123
Console.Log(DoSomething(456))
-- 579
Inherited Classes
Now all Inherited Classes will be available to all Packages, as they will be created and exposed to the Global scope automatically.
The first parameter of it will now be used as the variable name to set the class in the global scope. Also, it just got a new optional 2nd parameter to define a custom table contained custom values to be set in the class table before it's created:
-- Note we are assigning the return of Inherit to a variable called
-- MyPropClassLocal, but also MyPropClass will be defined globally
-- as being our class, both variables points to the same Class table
MyPropClassLocal = Prop.Inherit("MyPropClass", {
"my_custom_value" = 123,
"my_another_value" = "hello"
})
local val = MyPropClass.my_custom_value
-- val == 123
We've also added a new static event for getting when a new Inherited Class is registered: ClassRegister
:
Prop.Subscribe("ClassRegister", function(class)
-- Do something with the new class
end)
Library Package Type
With this new way Package work, library
types are no longer needed. As now we can communicate directly with other packages with exposed global methods, we can just define the methods to be exported with Package.Export
and use them whenever we want.
In this way we will only have two types of "lua script" Packages: game-mode
and script
. All existing library
packages will be automatically converted to script
when loaded.
RequirePackage
Therefore, Package.RequirePackage
will becomes unnecessary as well. As we can now reuse the same script globally, this method will be depreciated in favor of adding your package in the package_dependencies
list of your Package's Package.toml.
Package requiring the default nanos-world-vehicles
or nanos-world-weapons
will load them as a standalone Package, as now they export the NanosWorldWeapons
and NanosWorldVehicles
tables globally.
GameMode Settings
We are introducing the concept of custom settings for game-modes! These settings can be defined in Package.toml like that:
# game-mode custom settings configurations
[custom_settings]
my_toggle = { label = "enable PVP", type = "boolean", description = "whether to enable PVP or not", default = true }
my_text_input = { label = "type anything", type = "text", description = "custom text!", default = "hello world!" }
These settings can be configured through server arguments --custom_settings "my_toggle = true, my_text_input = 'awesome text!', ..."
, or through the New Game screen, which parses and displays the configuration dynamically when creating a new game:
The values defined can be accessed through the new method Server.GetCustomSettings()
.
Please refer to the updated Documentation Page for more information.
Configuration Files
As announced on previous blogs, the format of the configuration files are changing in the next update!
All Package.toml and Assets.toml in the old format will automatically self-convert to the new format as soon as they load for the first time.
Meta Block
Now we have a new common header among all Assets.toml and Package.toml: [meta]
.
It will have the following format, which will be used to define general configurations mainly used by the store:
loading...
Package
For the Packages, we will have a new format to differentiate their Types. Each Package type will have an independent and different block of configurations. Now the Package type will be determined by defining a block [game_mode]
, [script]
or [loading-screen]
.
This is how a game-mode Package.toml will look like:
loading...
Configuration Images
As you may have noticed, there is no more setting image
on Package.toml, the same applies to Assets.toml and for the server image in the Config.toml.
Now, the images should be physically placed next to the .toml file with the name Package.jpg
, Assets.jpg
or Server.jpg
.
This is a standardization to solve the image inconsistency between the store and the config file, as well as to avoid external and malicious links to be placed there. But this brings the drawback that only dedicated servers can display an image on the Server List from now on.
New Static Classes
Finally we are releasing the update with all the Static Class refactoring! This will give us a great new organization to find things at the docs, as now specific methods will be grouped into classes with names that make sense!
List of all new Static Classes:
- 💬 Chat
- 🔤 Console
- 🐛 Debug
- ☎️ Discord
- 🏝️ Level
- 🚢 Navigation
- 🖼️ PostProcess
- 🌅 Sky
- 🎮 Steam
- 🔍 Trace
- 📺 Viewport
Also, 🕹️ Input got a bunch of new methods and events as well from Client.
Many of the methods from ⌨️ Client and the old 🌍 World were migrated to those classes! Check their pages for accurate information!
Renamed Events
Due our last poll, we are starting to change all events names which were with wrong names. We are standardizing them to the present tense, so events like CharacterEntered
will be renamed to CharacterEnter
for example.
All changes will keep the old event working as deprecated. Please get attention to the new warnings to update them to the newer version!
Assets Plugin Content
Now it is possible to create Asset Packs from Plugin Content, this will be the preferred way of creating content from now on as it prevents assets paths colliding with others.
For that, we added a new setting in Assets.toml to define if the Asset Pack is a plugin content: is_plugin_content
.
Please refer to the updated Documentation Page for more information.
Store Improvements
Last month MegaThorx launched an update to the store, which greatly improves the upload flow of new versions. Now we have a progress bar, as well as special scripts to verify for syntax errors and potential problems. More features will be added in the future as well!
Conclusion
I was not very much satisfied on how nanos world was handling the possibilities of modding and scripting. It felt very limited and non natural the way scripters had to do to make packages to communicate with each other, it wasn't allowing much customization or extensibility.
With the last month's Entity System and now with this change to how Packages work, I feel that a huge door of possibilities has just opened even more, which will give a good breath to new things to be added!
An excellent example of what now is possible to achieve is creating a blank script
package with a custom special inherited Weapon, and just loading the Sandbox game-mode together with your script to make it show up in the Spawn Menu, without needing any special call or workaround! This is huge and tie all the remaining knots! 🥳
This change to a single VM was a big change, at first I thought it was not going to work, but after done and performing tests I was very surprised and happy with the results! Now we have to refine and improve it even more!
Modding goes brrr!! Thank you for the support! See you next month! 💪💪