Ciao, avventuriero!
We will upgrade our old combat and animation system to improve performance in areas with many players alongside the release of Season of the Guardian. This new system (which we affectionately call Slayer Script) will also make it easier to improve our combat going forward. We’ve done our best to keep the feel of the game the same, but would love to hear your feedback following these changes. From the development process to challenges, join Tech Lead Kevin Christensen for a deep dive into what this system means for the future of New World.
Slayer Script
Slayer Script is a C++ based scripting language. It is natively compiled and dynamically loaded by New World in order to provide excellent performance as well as live updates to scripts. It can cause events (spawn enemies, play sounds, etc), respond to events (if an enemy dies, if a player enters a room, etc.), play animations, control movement, and more. A lot of work can be packed into a few lines of code.
Development Process
New World has an enormous amount of objects that update frequently, making it difficult to efficiently use traditional scripting languages. A scripting language, for example Lua, is interpreted and cannot capitalize on hardware optimizations. While the execution performance of Lua is good, it would be used for hundreds of objects in New World. The overhead and memory cost was not going to cut it. We needed a solution to be as fast as possible with an acceptable impact to development iteration.
Our original character scripting system ran well during development, but eventually began to struggle with performance, memory, and runtime allocation as New World continued to grow. This led to Slayer Script as an alternative side project. Slayer Script reduced this cost to a few allocations, and its natively compiled code is very compact, which significantly reduced the runtime memory.
The initial idea was to use Slayer Script to control the player. The player is by far the most expensive game object in New World. Much of the design was focused on reading player input and controlling animations. This task was going to take a large amount of time. Turns out, the Expedition Team was the first to use Slayer Script, which didn’t require player input or animations. This is when Slayer Script changed to be a more general purpose scripting language. It wasn’t until recently that Slayer Script was used for its intended purpose.
Obiettivi
Over 400 actions have been converted into the new system by hand to ensure gameplay remains one-to-one. Our goals were:
Use natively compiled C++ to be as fast as possible.
Reduce memory cost by decreasing the amount of state that needs to be stored.
Improve scalability by using an architecture that has a smaller impact on execution for new behaviors.
Be hot loadable in order to allow runtime development.
Be easier to debug.
Reducing the memory cost turned out to be the easiest problem to solve. Slayer Script was designed to store the state in one location, and all of the behavior was created in a manner that can be shared amongst all instances of a script.
Scalability will be an ongoing task. Even C++ can be used in an inefficient manner. Care must be taken when adding new features, but C++ provides extensive solutions for tracking performance and observing operation execution.
The previous system was difficult to debug. Tools were created to help but being able to step through execution was not possible. Any designer with a debugger can now set breakpoints, inspect memory and step through the script’s execution. Debugging the previous system was a time sink, just due to the process. Debugging complex scripts is still hard but at least the method is easy.
Sfide
The biggest challenge has been to keep iteration fast. Designers need to be able to see the results of their work quickly. With a compiled language, this would normally mean closing the game, making edits, compiling and then running the game again to see the results. Slayer Script is built into a module that can be loaded while the game is running. Dynamically reloading a module can be tricky, so any references to objects within the module must be released before the module is unloaded, and reacquired after the module is reloaded. If this is not handled correctly, the game or tools will crash.
By using C++, the memory and performance cost of the system starts out with great potential. C++ is intended to develop high performance applications and be as efficient as possible. It is a mature language with many tools to help development and measure performance.
Another challenge was hiding the complexities of C++ from the people who will use Slayer Script. C++ can be a difficult language to use, but when used as a scripting language, it doesn’t have to be any more complex than any other scripting language. There is still a lot of room for improvement on this topic. It will continue to be a goal.
We look forward to your feedback in the Season of the Guardian PTR. Grazie per il supporto. Ci vediamo su Aeternum!