Hey, testing. Right on. Cool. So, yeah, welcome to my presentation. My name is Matt Doyle. I'm a tech art director on Frostbite at Electronic Arts. And the presentation here is called implementing a scripting solution for your editor. All right. So, that we know what we're talking about when we talk about scripting, uh we're talking about these types of scripting in these customizable tools. So, uh to get a feeling for uh the audience here, who here has not written any scripting or code whatsoever? Show of hands, who's not written any scripting or code whatsoever? So, that's really cool. Um I've given presentations where there's a lot of artists or designers or people that are new to this. Um but being exposed to it realize that
it's not limited only to tech artists and engineers. It's something that a much broader audience can actually uh utilize. So, if you're familiar with Maya, obviously they've got Maya embedded language, um MEL scripting. They also have Python. Uh we have the uh I guess previous uh Softimage had Python and many other scripting languages. Uh 3D Studio Max has MaxScript. Uh Photoshop has uh JavaScript. Um and then when I'm talking about Unity, I'm talking about the Unity editor specifically, um and being able to customize that. So, all of this should kind of start to paint a picture of where we're going with uh this presentation is about the editor that you use to create content and the scripting functionality that you can use in those editors uh for both automation and customizing that. So, let's look at uh what we did with Frostbite and creating something called FB script. Obviously, FB could most likely stand for Frostbite.
Um the the idea that scripting empowers game developers is something I obviously believe in. Um and it does this by providing a framework for customizing uh the existing solution to meet any needs that it might emerge uh during production. You don't always know what you're getting into at the start, right? But obviously, that isn't in a vacuum. It isn't in a bubble. Uh it has to be built on a foundation of something that exists before that. So um we're familiar with the adage that uh success starts with standing on the shoulders of giants, and that's no different here. So there's a few really cool technologies that this is built on. Um Avalon Edit, which I'll go into a little bit of detail on, as well as Iron Python. Um all stacks on top of this Frostbite platform. A key thing to point out here though is that this is all going down into uh the domain of .NET applications. And so uh I know that's a very common domain, but it is uh an an important thing to point out
that it's uh uh a lot of the details that'll be going over do have that uh requirement. And then the largest requirement, the most important thing about all of this isn't really just about creating some script editor where you can write some lines of text and have it execute and do something. Um the really key thing is how this is actually used in production. Uh the game teams that use this effectively and uh and not only using it effectively, but then sharing it across uh a community. So uh that is also very key. So a- as I go through a lot of the implementation details, it'll keep a lot of this in mind. So we'll look at not only building up a scripting editor, uh that scripting API, the language, all of that kind of stuff, the technology that it interfaces, but then as well as how it actually gets used in production, and how to facilitate all of that. Cool. So, for those of you that don't know what Frostbite is, um it's not the uh easiest
Google search. Um execute with caution. Avoid images. Uh the shattered hand should give you some kind of in indication of what you might be in for, but um uh in terms of the name of our technology, this stuff originates from Sweden, which is, I know, half the year in darkness and cold. So, um comes from an inspired place. Um but in terms of creating games, uh the vision of all of this is empowering the game creators to create the future of gaming. So, that's something that we're striving towards. And although we never feel like we're there where we've achieved, you know, the very best technology or the very best editors, that's always what we're aiming towards. And if you look at the game teams that are using this technology and shipping games, I believe it's being used to great success. So, if we look at how scripting has been used in all of these different editors, we've got uh Battlefield here, uh which is a first-person shooter. Got racing, sports, stylized games such as Garden Warfare, uh and Dragon Age: Inquisition. And
here's just a little video to give a flavor of that diversity. So, Frostbite was originally created for Battlefield. And then the next game that used Frostbite outside of Battlefield, outside of DICE, was Need for Speed. And we're seeing it also being used in sports titles now. And this game was really fun to work on and to play, and it's just kind of breaks the mold in terms of, you know, what to expect from, you know, the typical fare of gritty and real. And then we've got, you know, at least on many charts out there, game of the year. Not all of them, but it's still a a proud accomplishment there to uh be in that uh league there. Cool. So, this is how scripting was used in these different games here. We've got uh Battlefield using it for data inspection
and optimizations. Uh we've got uh Need for Speed using it for a number of things, but uh out of the gates uh it was used heavily for stress testing the editor limitations, and we'll look at that what that actually means in just a moment. Uh sports have been using it for batch asset conversion and a whole bunch of other things. Um on Garden Warfare, which I'll look in uh later in a uh a bit more detail, uh it was used to automate the setup of thousands of different assets uh earlier on in production with enough time to actually test uh uh gameplay ramifications. And then as well on uh Dragon Age, an absolutely monstrous game, uh the largest game I've ever seen in production, um and a very high quality, too. So, to actually dig through all of that data that gets generated by so many people actually contributing to create that, uh definitely we leveraged uh scripting to do a lot of testing and optimizations on that project.
So, as I mentioned, Frostbite was originally used um to create the original Battlefield franchise games um and then subsequent versions of Battlefield later. Uh that team uh was DICE, and DICE created while Battlefield and it also created these tools and technology called Frostbite. So, uh they had a solution that worked really well for them, and if they needed to extend it or or add functionality or anything, um they were very well versed in that environment. Um uh the editor that was being used for inside of Frostbite is called Frosted. I guess if you say it fast, it sounds frosted. Uh the um the the key distinction here though is that when you have a a team like this, I mean you're going to find scripting is going to be useful anyways, but they didn't find as much of a need out of the gates because they're still building the technology and every time they bumped into something that they couldn't do, they could add it. But as soon as you start looking at having more than one game and especially
more than one type of game, um, it is really key to be able to have as much flexibility there as possible without needing to go through that whole process of not only designing, implementing, getting first functional testing, and then iterating on that really slow loop, um, can be quite challenging and especially worth noting. Uh, I was one of the members on that Need for Speed: The Run team, which was located in Vancouver, Canada. And the Frostbite team is located in Stockholm, Sweden. So, when their work day would end, just as they're leaving work, we're arriving to work. And so, there wasn't a lot of crossover there and it was really tricky then to kind of wrangle that communication. We could send an email, but then we would expect maybe a result, if we're lucky, some crossover, but mostly the next day. And so, when you have a new team that's using this kind of technology with that kind of a communication gap, um, there's a lot of challenges that present themselves. Uh, not only are the engineers on your team trying to learn the stuff, uh, so that they can later
support you, but that support isn't immediately there. So, it should seem fairly apparent looking at, uh, these two screenshots that racing games can be very different both visually, um, but especially in the experience, uh, compared to a first-person shooter. So, when we're setting out to actually create this game, there's a lot of unknowns. Um, and this all is leading in towards, uh, adding a scripting solution and an editor to accomplish a lot of this stuff, um, but we'll see how we get there in just a second. Um, the Need for Speed: The Run game, this goes back a while and we'll look at some more recent games um soon here, but this was the starting point and it was a really cool ambitious uh project. It the the experience that we were trying to build was a race from San Francisco to New York. And what we ended up building was 5,000 square kilometers of terrain extracted from USGS satellite data um hand-crafted
with extra uh erosion details and all of that kind of funness. And then thousands, hundreds of thousands of assets uh placed in and creating this um a a a sense of speed as we race through that world at 800 m a second, which is, you know, 260 mph in some cars, so. Gives an idea of what we were trying to achieve and then how do we apply technology towards achieving that? Well, we had experience creating racing games, but not creating racing games on this new platform. And so when we started to create uh Need for Speed The Run, we had previous games and lots of data that we could look at that we were really familiar with. And in this case, we had over, you know, 80,000 different assets placed in the world of uh Need for Speed Undercover. So the idea was that we would bring that stuff over into this Frostbite ecosystem, bring it into the editor, uh you know, turn uh slide sliders, turn knobs, get a
feeling for cause and effect on a data set that we were familiar with. But it wasn't as simple as that because the automation systems and everything for dealing and porting an old set of data wasn't uh readily available and so uh so that's something that we actually had to build up. So what we ended up with was uh an experience that was much larger than any previous game that we had created and we had uh over 20 levels with each one of those containing roughly 40,000 different placements in it. Um so that added up easily 10 times as many as uh our previous game. So how we originally got a lot of this stuff through the pipeline was creating C# uh plugins, was extending the initial functionality of the editor, it was making all of these kinds of improvements. In order to accomplish that, it did take weeks uh to get that first functional look at it.
Um even after we had all of that data through and we're looking at like, you know, it's quite a volume of data um just from the previous game. Uh no one person is going to look through all of those different assets and try and start tweaking and tuning it because even once we had a bunch of this stuff in an editor there's a whole lot of stuff that became apparent. It's like, well, how does this stuff get bundled? How do you put it on disk? How do you stream it off of disk? Um how do we do all of these kinds of optimizations for texture compression, level of details of how this stuff will render efficiently or the most efficiently? So all of that stuff takes tuning and a bit of experimentation and iteration. And to iterate over that many that much data is just simply going to take a lot of time if you're going to try and achieve that by hand. But with scripting, you can apply a rule set and then apply that across a broad set of data. I think we get the the high-level concept there. But without that scripting functionality, um that wasn't readily available. So we set out to create this. So what is the Frostbite editor scripting? What is that?
So we had scripting solutions uh to port a lot of data over from, you know, 3D Studio Max to Maya and we could use all of these different scripting languages to do that. We could do data conversion um inside of Photoshop and and uh we had scripting languages to do that. We didn't currently have a scripting language uh inside of Frostbite. So when we implemented this is what it all turned into. And we'll look at actually how to implement this in just a moment. Uh but this was the solution that we came up with. It was Iron Python plus a thin layer. That thin layer I'd have describe as a thin layer instead of an API. Um, and an IDE. And that's what we call FB script. Just give this slide a second to load up here. So, you can see the video playing there. I'm just going to queue off the slide in the background there. So, it was an epic experience that we ended up crafting. Um, it turned out well, especially from a visual point of
view. Um, the worlds looked amazing. Uh, we could travel through all of this awesome terrain between San Francisco to New York. And we could have it as close to real as possible. And in getting there, uh, we built up a lot of scripts to help, uh, not only in the initial data conversion of the previous game, but as well as working with across many different domains, uh, from the worlds, the lighting, the audio, all of that kind of stuff. And the key things there that we, uh, utilize is what you'd use scripting for anything is just to query the hidden information about data. It's not always exposed to you in a UI. Um, to automate the technical and repetitive tasks, uh, gets things done faster and it's less error prone. And you can quickly create tools and extend functionality. And there's all sorts of caveats there in terms of just how much you want to do in scripting versus, uh, something like C# or creating an application. But I can get into a bit more of that later. So, let's look at implementation details.
So, Iron Python's first up. Uh, this is the layer that's built on top of FrostEd. Again, it is a .NET application. And I should say that originally, when I was first looking at that application, I was considering, okay, well, I need an ability to go in there and automate stuff cuz that's just what I'm familiar with. I don't know of an environment or a a production that I haven't been able to do that. Um I originally wanted C#. Um that's something that was really familiar to me. Um I had experience using um just on the side, not uh specifically at EA, but just looking at um the functionality in things like Unity 3D. And they have really nice scripting functionality in there with C#. And not only on the runtime, but in the editor as well. And so, you get a lot of stuff for that. You get an IDE, you could be using MonoDevelop, you could be using Visual Studio. Um you don't have to create a script editor. Uh in that in that environment, you can have access to all of those different
assemblies that you would in your project. So, if you wanted to uh have uh if you want to implement something, that framework is really apparent right away. Um but there are limitations there, and those limitations are things that I wasn't actually fully aware of at the time. Uh Python, especially IronPython, was um a very new technology at the time. This goes back to maybe 2007. Uh that's too far back. 2008 or 9, I think. Um anyways, uh the cool thing, IronPython can actually do absolutely everything that C# can do. It has full access to everything in C#, and it can do more, which is okay, cool. What we're doing is actually starting with C# and adding additional functionality. And that additional functionality is a dynamic environment. And this is a bit tricky to get wrap your head around it. If you're an engineer and you're jumping into Visual Studio, you have an idea about the structure and the framework and then algorithm of sorts of what you're going to be building up. And then you'll build it, compile it, and then test a lot of
assumptions, whereas in the dynamic environment, specifically what we'll be looking at, it's very highly iterative. We use a a terminology called REPL or REPL, so read-eval-print-loop. And sometimes you'll execute it ad hoc. You'll have write a couple lines and then execute those couple lines. No compiling required and then test your assumptions and proceed. So, this is the solution that we created. Um we'll look at it in action. But, what does this actually look like to implement it? Like is it really heavy? Like how do you how do you apply this to an application? Consider you have an application that's written in .NET and you want to add this to it. Is it going to be a big challenge? And the answer to that is no. Um that might seem like a little bit of a daunting wall of text, but that's actually everything that's required to add IronPython to an application. And well, you might very well be able to find this kind of information online somewhere. What we'll be doing is taking it a step
further and looking at how to connect not only IronPython into a .NET application, but then connect that with an editor and uh with a production solution here. So, uh but before we proceed beyond all of this and and this slide right here can get a a little bit much to look at. It's a bit hand-wavy. It's like, "Okay, yeah, sure you can write some code and get a a result." But, let's see it in action. So, that's that's what you see as a screenshot. But, let's actually see this video here play out. Um I think this is worth taking 4 minutes. Um although it's a bit of a a fast ride here. What we're going to see is from the download the IronPython DLLs to setting up a .NET application and applying IronPython in 4 minutes. You know, it's sped up a little bit in some spots just to speed up the download speed or whatnot. But, I think from a high level you'll quickly appreciate that in order to get something like this stood up is it doesn't cost a lot.
So, there we go. We've created a new WinForms project. I know it's a little bit old compared to WPF, but just for simplicity's sake we can see we can block stuff in really quickly here. So, we got a list box, a text box, a button. We've named the button execute. We double click on it and we get that functionality in there for uh what happens when you click that button. And we'll add those details in a moment. And then we'll add a new folder for references cuz that Iron Python DLLs that we just downloaded need some place to put them. So, we'll go and find that zip file. We'll grab those DLLs and drag them into that reference folder. And there you go. You have a place on disk where they're referenced, but now we need to plug them into that solution. So, you go to references, do a browse, browse to that spot on disk that you just saved them to, and now you have
access to all those DLLs in your solution. Cool. Next up, we have to add a little using line there. Just a simple one. So, you just reference in that Microsoft hosting uh scripting one. We set up the script runtime and the engine. Uh distinction there is the engine that is the thing that evaluates uh the scripts, and the runtime is the thing that manages uh memory and scope. And this is just for an example. Uh so, we create an example class and it does not a lot. We have a public function in there that will simply just return a string that says "Hello." And then we initialize that example class. We initialize the script engine. And after you execute a script, it has to output somewhere. Um you could use it somewhere else in an application, or you
could output it as a text uh to some output window. So, in this case, we're just going to fill up that list box with the results that are being output from the script. And here we're initializing uh what are we doing? We're adding the example class as a global variable. This is a big distinction here where you can have any any class whatsoever, any object um exposed to scripting uh in this manner, and that's why it's thrown in a for loop even though even though we're just adding one for right now. Cool. And then we click the button, and that passes the text that we had in the text editor. It passes that into the scripting engine. The results are piped out back to that uh memory stream, and then passed into the list box so that we can see it in the UI. So, that's in really short order setting up absolutely everything that you need. We compile it, build, run. We type in something really simple like 1 + 1. It's a Hey, we've got a calculator. That's using Python to do, you know, Python
scripting. You could type in any Python script there, and it would execute. Um in this case, we have access to .NET functionality as well. So, there we're grabbing our example class. We're executing that method, and it says hello is the result. So, super simple, super high-level, but I think that you can see very quickly that you have implementation implantation details that anyone could utilize. I think it's pretty cool. And I think I probably have a secret agenda in showing that because any application that I find myself using, I would love to find scripting available inside of it because that gives me the hooks available to add in additional functionality in as lightweight a form as possible. All right. So, I'm going into a little bit more of a production solution side from there. We have We can see the groundwork. That's all foundational stuff. Um and if you have that in place, there's a few things that you can add on top of that, and
there you have a production solution. So, the examples that I'm going to be showing are simplified versions to not go into all of the the cruft of whatever it is that you would create. Would definitely look a little bit heavier than what I'm about to show. But, I'll go cover just enough detail to see how everything hooks together, how it all connects. So, let's take a look. Before I look at the coding examples, let's look at it in action. So, this is a video of the editor FrostEd and the scripting editor FB script uh interfacing with each other. And here we have a bunch of things going on. We have the thin wrapper exposed as FB. We have uh an assembly exposed as world render. Uh we have uh a data explorer on the left-hand side. It's just a list of assets, very common in a lot of different editors. We can select those things. And we can store whatever we have selected in a variable we specify. And the command to do that's really simple.
So, you can just say, "Hey, I've got a this thin wrapper called FB." And that FB lets me say something like get assets from data explorer selection. So, that's straightforward. And then we can iterate over that list of assets that we have selected and confirm our assumptions. We can say, "Hey, I think I selected some stuff and I suspect it's going to be in this list of um uh this variable is a list." Test that assumption. Go, "Yep, it actually is." So, we go, "Okay, now I know that each one of these assets that is going to be available now inside of the script um I can store it iteratively inside of that loop as the outdoor light is what I want to get access to from that asset. And then not only can you get assets from a list of assets, you can also kind of pair down into uh assets. So, look at component pieces, however they that happens to be set up. I know this is all very specific to Frostbite, but I think the general principle applies. And then you have access to the member properties and functions. And so there you run a quick query
so the outdoor light sun rotation for X it happens to be at 120. Execute that line that returns the result to the output field. But you can type in any value and execute that. And what I'm clicking on there is just execute current line. So it's not the entire script that gets reevaluated. It's just that one line. So any portion of your script you can always just execute ad hoc that way and find out further information about that or you know, operate on that data. So that's the high-level idea. I mean it's a super simple example, but it's just enough I think to give us an idea of what we're going in for when I start talking about uh further implementation details. All right. So Iron Python exceptions is the thing that was missing from that very first simple example. That very first simple example allows us to do things like 1 + 1 and it will return a value of two. So that's really intuitive and straightforward. Um but if we were to type in something like A + B, it was like, well, what the heck is that? You haven't defined it yet. And you'd want to throw some sort of an exception.
So to do that is actually not that difficult. Um and so I'm not going to go into the details because it's also a solved problem. So just like uh uh some of the other examples I'll be looking at later including Avalon Edit, um there are solutions that are already out there that we can utilize. And so this is a really good resource that I can point you towards devhawk.net um has a lot more than just this particular example, um but this is where I started. And here we can see setting up uh the traceback framework. Here the idea, the awareness uh that it exists is more key than exactly how to do it. But what's going on right here is we have a hook there into that exception. So anytime there's a problem with a script that gets run, it has a mechanism to pipe that exception back and tell us, you know, what's it going to tell us? It's going to say what line number did a script fail and what was the error message?" And then we can do something meaningful with that information. There's a bunch of other stuff going on
in here, um but again, not going to linger on this particular side of things. What I want to do is move on and look at the script engine uh initialization. And in particular, the scope management. So, as long as you have uh exception handling set up, that's great. And you can see right here in the initialization, you've got this engine.settrace, which is kind of kicking all of that stuff off. Um we're going into reset scope. So, this is important because there's a bunch of stuff that's going to happen here that helps us hook into an editor. Let's look at that. All right. So, in scope by default, uh we have assemblies, Python paths, aliases. You could throw in a whole ton of stuff into here. Um but it can also be quite simple. So, in this case, what we want to do is just iterate over all the assemblies that are available in the application that we're having scripting in. So, that's pretty cool. We can go
Everything that you would have access to if you were inside of C#, you now have access to inside of scripting with that simple iteration loop. And then we can also throw a whole bunch of other stuff at it. We can say, uh "Here's a list of Python libraries that we can have access to." And then we can also declare a bunch of objects. You could have singletons or whatever the case may be, but you could build up a bunch of structures in there that you just have access now as well inside of scripting. So, that's how you pass all that stuff in. And that was a very high-level quick overview of Iron Python implementation. And let's look at what that last bit of stuff that we just saw and how that connects with the FB script editor. So, inside of the FB script editor or inside of any kind of scripting editor solution that you would look at, I highly recommend looking at Avalon Edit. I found it really easy to use, um
and it solves all of those common problems that you would expect as a bar of entry for any kind of text editor, would be it LimeWire or Notepad++ or whatever the case may be. You're going to end up with Avalon Edit having syntax highlighting, folding, code completion, all of that fun stuff. So, before getting into a few more code looking slides, you can see a quick video of this stuff in action. And what we're looking at here are just illustrating uh the idea behind importing something that we should be familiar with, the system namespace in uh C# in .NET in particular. And uh in this case, what we're doing is we're as we're typing, we're getting code completion. So, okay, that's cool. Um a couple other things uh that are available here as well as asking for help on giving functions, um as well as and this is a subtle one, I just kind of something I missed too as the video is playing, but right out of the gate, when we executed that first
line, import system, it wasn't in scope. After we executed it is, and so it bold the system. So, syntax highlighting can help us with um more than just keywords and all of that kind of stuff. It can help us understand what's in scope. So, that in the component pieces again is uh easy access to .NET functions. Here, we can see a Iron Python uh script that says, "Hey, what's uh whether a file exists or not." And then we can see the code required to expose that and make it available to the scripting. So, there it is, just adding in all of the assemblies available there. Now, what about that code completion stuff, the drop-down menus and all of that. Like, how where are we pulling that information from? How does that get passed from something that's a script that executes something to an editor that's as you're typing is giving you some feedback. So, that's in two places. It's in a public execute
script method. What does that mean? It means that yeah, okay, when you want to hit that play button or execute script button or whatever it is that executes multiple lines of code or one line of code or whatever the case may be, that same functionality there that you're going to execute a large script with, that same functionality can get called as you're typing. So, you can pass in, and this is the key point to the next one, you can pass in the previous word. So, it is helpful to have a very simple script parser that will parse your script, find what the previous word was, and then pass that into the scripting engine. So, you can do things like, well, let's take a look. You can do things like this where you have access to your script engine. So, you can call that execute script function. And as you're typing, you can get that previous word, and you can do a directory on it. Like, if if you're not familiar with Python, if you type DIR bracket, and then inside of those brackets, you're going to put in a
variable, that variable then will be what will you'll get as an output from that is you'll get a list of the member methods and properties. So, because we're calling that in code there, what we can see here is uh what we can see here is that we have not only the ability to uh execute the script from any anywhere, from any part of your C# application, but we can also execute that on the fly. So, as we're typing that system.io.file, as soon as you hit that dot, that dot triggers an event, and it says, "Okay, cool. I'm going to look for uh a list of members and and attributes that belong to system.io.file." And then it gives us that list in that drop-down menu. And that would be the same thing as if we'd put that whole thing in brackets and get something as an output. Oh, and I just one more thing, sorry, on that last slide there is um yeah, some of these functionalities here
might not look familiar, but uh if you did investigate the Avalon editor because it has such nice interfaces there for building up code completion boxes. Uh here you can see uh those in action as well. And we're just passing in the results into that code completion. Cool. And we can do the same thing with uh Python scripts. So, uh it actually goes beyond that and I'll reiterate this point later with an example in production. Uh But, there's so much more that you can do in this space. So, it's not just about going, "Here's an application. I want to bring everything that the application can see, and now I want to have that in a scripting environment." Obviously here we're looking at an example where we can go, "Okay, here's a whole bunch of Python libraries." But, you can dynamically add a whole bunch of Python libraries later through calls from your script. Not only can you do that, you can also add reference to references to ZAML to help with UI, and you can add in references to DLLs to help with uh well, if you wanted to create an application or uh a
library with a whole bunch of functionality, you wanted to write that in C# using Visual Studio. That's all good. You can have that DLL, as long as it's a .NET DLL, you can have that available inside of the script environment as well. Now, syntax highlighting I'm not going to go long on. We all get um this fairly uh standard bar uh bar of entry into script editing. But, uh just want to reiterate that point that I called out earlier to there. Of if you type in something into this editor, everything is just going to be text. And especially if you know Python, it's going to be very dynamic. So, there's not going to be really any strong typing or anything going on. Um however, after you execute something, it will exist in scope. And it's that reflection of what is in memory that can tell us stuff back to the editor. And so, as soon as we've imported system, um or as soon as we've executed anything that registers something in memory, uh as long as it's been executed and it's there in memory, it's going to go bold to help us give that indication.
So, that's really useful for uh REPL workflows. And uh something else is just more of a um a counterpart to code completion. So, if you hit dot and you get a drop-down list, um in this case, if you hit uh the if you use the Python command help and then throw in any object into help, uh you're going to get some documentation if there's something that exists for that. So, uh in this case, we can get documentation both from Python commands and from uh .NET commands. And that was the FB script editor. I think there's about three slides for the FB modules. Uh it's just a thin wrapper, so it should be fairly light. Um and then we'll look at production examples. All right. So, thin wrapper. Thin wrapper we should be just that. Should be very thin, really light and accessible. Um if you wanted to go, you know, into the guts and and access absolutely everything and do everything, well, you actually do have access
through scripting to do that. You can also go into C# to do that. Um but to make something accessible to a community of people that are going to be building stuff and using it, um documentation helps, but it is really important to make sure that it's as intuitive and easy to use as possible for new users. So, here we're looking at a list of commands um that should seem really simple. Create. Guess what? You want to create some stuff, you got to create command. You want to edit some stuff, you got an edit command. You want to get or query some information, you've got that. The user commands is an interesting aside, but it's a very reflective system. So, the user commands actually helps us reflect into the scripting engine itself and modify parameters about the scripting environment. A bit crazy, but anyways, it's there. And also just various utilities that you'd want to expose. So, this is an example of that. So, here you import that thin wrapper called FB. So, with a thin wrapper imported, and of course obviously in your case, it could be called absolutely anything. Um I go with a two-letter designation, so it's easy to type. One-letter designation,
too easy to conflict if someone else wanted to use a single variable um name. But with FB imported, with that thin wrapper imported, uh we can do things like uh as soon as we hit FB. We get that first list of what do you want to do? Do you want to get or create or what? So, you go, I want to get some information. So, I hit get, and they'll say, "Well, what do you want to get?" And it's like a whole list of assets of like, you know, do you want to get a mesh or a texture or what? And you get that list. And then you go, "Well, I want to get uh I just want to get assets from uh the data explorer selection." So, that gives us a quick, easy-flowing path to actually get the information that we want. And here you can get uh get a high-level idea of how to build up a thin wrapper. Um for me, it's really uh easy to say that it helps to say, you know, if the submodules read like English, it's easier to follow. Um so, uh in this case, uh I don't know, some examples that I would pick out. So, uh you have a level, a
scene, and in that scene is some layers. So, uh you can ask that question. You can say FB.get layers from scene, and then you can pass in maybe a filter to say, "Okay, only get me the layers with this string in it." or something. I think you get the idea there. And we saw that video earlier of of uh executing scripts, seeing that update not only in the properties of an object, but also update in the editor. Um and in this case it's just uh reiterating that point. So here we're saying, yep, we can query assets, we can query components, we can pair down into the data and find the information that we want, and as soon as we have access to that data, we can modify it. So that is what we've accomplished with all of that. And the interesting thing too, and I'll touch on it uh coming up here, is um especially on the Dragon Age side of things, but it's really easy to spend, you know, a small amount of time, but still, you know, maybe that takes a couple of minutes to write, to accomplish what that you could change
with a slider, right? So from a tech art perspective, it always gets a bit tricky to justify how much time to spend scripting something that you can do very readily or easily with a UI. So the key point is always uh tracing it back to how you batch script that and automate it over tens or thousands of assets there. So high-level goals of implementing a thin wrapper, exposing commonly used commands, so you just get a strong base, a a strong uh starting point. Abstract queries to easily access assets, so uh if if that same functionality existed, but it was like nested in some, you know, um some namespace inside of some object inside of some other object subobject. Um if that functionality is buried away, just expose it at a higher level, especially if it's commonly used. Um and then provide a consistent and intuitive way to get started with scripting. All right, production examples. So all of that was the implementation details of how to hook up a scripting
solution in an editor, uh specifically a .NET editor. Um but what value does any of that have if we're not actually using it in production and creating something uh that can be appreciated? So here we're going to look at some production examples from Dragon Age Inquisition, Garden Warfare, and Battlefield. Um should be noted that across uh the community of people using Frostbite uh there's maybe about 200 or more people using uh FB scripts, creating them, and writing them. This includes tech artists, designers, engineers, um a surprisingly wide set of people. And they're using it to help make, you know, the redundant or repetitive parts of their job, you know, a bit faster and less error-prone. So, uh let's take a look at that. So, Garden Warfare is first up. And before I go running down that road going, "Hey, look at what we did on Garden Warfare." Um I know cuz I sit through these
sections, too, in the back of my mind is going, "Well, how can I use that? What does that mean to me?" Um and so, when I go into this detail, um it's important for me to try and find a way that How does this How does this apply to someone outside of Zomboss Academy or EA or wherever? So, let's take a look. So, when I mentioned earlier that in on Garden Warfare that we set up thousands of assets automatically, what does that mean? It's like, "Okay, well, you click a button and you get a thousand assets and they're done." And that's not quite what I meant. Um what I mean is that you set up the framework for those assets. And what does a framework of an asset mean? Like, are we We thought that it was really simple, right? Well, I mean, most of us here I'm guessing are savvy enough to realize that anything that you see rendered on screen isn't just one thing. It's a It's composed of many. And what are those things? So, we start with concept art. We get it. We
have an idea. Maybe it's a word document or something. And then it gets uh uh represented as some concept. Um again, could be text or could be an image. And then when we have that that concept, we apply we start creating something, something physical, but it's still not in the game. It's just like, okay, this is our first steps towards this. And we create models, sometimes really high-res models, and we use ZBrush or whatever the case may be to like sculpt something that's way too big to actually fit in the game. We build up textures, and the textures are like way higher resolution than what we'll actually use in the game. Um and we start building up, you know, like this really nice-looking thing of uh diffuse and specular normals and all of that goodness. And then we start applying it with shaders and materials, and we start building up uh something that we're starting to say, "Hey, I get it. This is what we're making." And then then we start seeing something in the game eventually with but maybe it's not moving yet. Maybe it's just like, "Oh, this is how it renders with this engine, with these lighting conditions, or whatever."
And then we Excuse me, hook up gameplay. Like, how does it respond to button clicks? What is the animation doing? Um the visual effects, um uh we Obviously, all of that requires uh skeletons and character rigs. Um and then the component parts need to get rigged and how they get swapped in and out. Um So, yeah, then we've got uh this guy running around, and he's got a state flow, and how he responds to all of that kind of stuff. And we've got audio as well. So, um that stuff, even though it could be a really simple thing, can be quite complex. So, it's also not something that you understand exactly how it all connects together at the beginning of a project. You figure it out as you go. You go like, "Does this work? Does this connect over here?" And as you kind of build up enough assets, and you start to see how it all connects together, you start identifying patterns. And you're going, "Okay, I get it. You know, this this type of a thing is always going to connect this way."
The interesting thing is after you actually start to digest that, and you start to appreciate just, "Okay, this is what we're doing right now. If you take a moment and pause right there, you realize that it's actually really complex because you came about it organically and you got to that point not because you're like, "Oh, this is the best way to design how everything should get connected together." It's like, "No, this is actually what you know, it's a creative process." Um if that diagram doesn't make your brain melt, um the idea is that each one of those nodes has a lot of properties and additional values beneath it yet. So, it's it's less of a an array of things, it's more of a matrix that goes quite deep. And that's just a single asset. So, you're like, "Wow, okay. You know, there's a lot of button clicking going on just to connect the dots for an artist or a designer or someone to go, "Okay, I'm going to build something." And every time they're building something, they're going, "Okay, this connects to that. This connects to that. This connects to that." That takes a lot of time. So, what we did on this project was once we had that figured out and we had a a
way that was consistent enough, we could script how a lot of this stuff gets connected together using placeholder assets. So, we'd build up a volume, say for a head prop or something like that, and that volume would say, "That's where that head prop, be it a hat or something, um needs to exist within." It's just parameters to say, "Here's your guidelines, but this is this is where it's going to exist. That's how it's going to function, but it's not the real asset yet." And then we would throw the concept art on it and it would look ugly. I mean, the concept art mapped onto uh some geometry it it looks completely out of place, but you get the idea of what it's going to turn into at a glance. Um and then we do a whole bunch of other things, but the end of all of that stuff is that we could use a framework of real assets. So, we could use real geometry, real textures, all of that kind of stuff. It just doesn't look the way it should yet. And the things that that tells us is, you know, how much memory is it going to consume? How is that going to perform in the runtime? Uh how are you going to swap these things out? Uh how is that
going to interface with the UI? How is that going to work with the progression of the game as you unlock things or get weapon upgrades or whatever the case may be. All of those questions that usually you don't get to by the time like it usually comes as an after you've created all of this content. You can front-load a lot of that. So, that was a really cool success and a learning experience from that project. There's a few more guys kicking around and that's just to highlight that it isn't always just physical geometry. Sometimes it's particle effects or visual effects or sometimes it's audio or sometimes I mean it spans across all of those domains. So, that is another thing that I did want to mention was that beyond actually being able to get an early look at how everything fits together, it also helps smooth over as production grease if you will so that a lot of these different domains can be working and they can be building stuff and they don't have to be waiting on the next person to finish whatever it is that they're doing because we have a placeholder for that.
All right, Battlefield. So, Battlefield Daniel Rashid at Battlefield a very talented technical artist created something that you know was way beyond anything I'd imagined FB script would be used for. And he found a lot of new ways to to utilize this technology that I hadn't seen it used before as well. So, that was including using loosely bound Zaml and .net DLLs as I'd mentioned earlier. So, not everything had to be written in scripting. Some of this stuff some of the components of it could be written somewhere else and then imported into this ecosystem. The cool thing is being inside of that ecosystem, you now in a highly iterative environment. So, you can take some of those well-understood component pieces and then add them into this. So, let's see that in action. An interesting thing is we're going to look at something that Daniel made for Battlefield. It's called the level scanner and he made he's made a lot of different types of tools. Uh, we're looking at that.
Uh, and it was used uh to great success on Battlefield for understanding their large data set. But, it was also used as well on Dragon Age. And let's take a look at that. So, here's a video. All right. So, that's the level scanner. And uh it kind of picked up a little bit late there, but we'll come back to that uh starting thing just in a moment. So, the whole thing there is that you've got all of this information about your data. A lot of this information is abstract. It's not ever in one place. It's it's using information from a whole bunch of different places to figure stuff out. Um, you can sort it based on a number of different parameters. And in this particular case, it's found an asset that has reasonably well-implemented LODs, but it's used a lot in one given level. Um, that was the the rock example. And then this other example right here for the door where it's only used once in a level uh is missing the the it has an LOD, but the LOD is not optimized as
much as what's as what it could be. So, this gives you a sense of going, "Oh, we've got all of this data. We're going to dedicate our time and and money and and efforts so that we're going to make this game run as efficiently as possible. But, we can't just start with the very first asset we see and then go from there. We want to have a sense of where to start first." And so, all of this uh all of this UI and everything else um he put into the hands of the art teams. And they could begin a better sense of how to prioritize their efforts of where they wanted to spend time optimizing for runtime performance and and memory and all that. So, that takes us um as a bit of a segue to Dragon Age cuz we saw some Dragon Age assets there. Um, so Jeff Fannell, another really smart guy uh and really practical, too. So, he he had to approach uh solving problems from many different angles. And obviously, not everyone is going to include FB script. Um, and another key thing, too, is that when you set out, you're not going to be creating content, really,
using scripting or automated process. I mean, you can. You can use procedural techniques and everything else. But, ultimately, a creative process is going to be involved. And I And that's going to be the the starting point, anyways. So, the big thing to point out here is that um, on Dragon Age, I mean, my mind short-circuited when I was looking at that project and looking at the data sets and trying to understand even what someone could do, um, to to try and optimize for all of the different platforms that it was released on. And when you look at almost 20,000 different visual effects, um, uh, 20,000 different assets in the visual effects folder alone, um, it's pretty phenomenal. And you click on one of those things. It's like, okay, let's look at this uh, dragon VFX for when it lands hard. And then, you go, okay, open that thing up, and you get like all of these other assets that it's referencing in there. So, you've got, oh, you've got this debris and dust and all of that kind of stuff. And then, you click on one of those, and you go into there, and it's got like all of these things of how to actually render and animate and do all of that kind of stuff with the visual effects.
And then, you've got all of that information for each of the different platforms that it's targeted towards. So, it's a bit much. And I think what they did was a really cool thing is they just targeted ultra quality. They just try and build this thing up for the best possible visual results that they could. And then, they would do, uh, uh, a very smart approach of how to do that to try and get it to progressively be as vis- high visual quality as possible while meeting the memory and performance restraints as you look at the lower-end systems. Um, another key thing, too, about this is that um, if you I I I like his quote here is, "If the process is technical and repetitive, we can script it to save time and reduce user errors." And it's that and reduce user errors that really resonates with me, too, because it's not just about hey, we got this done faster. Um, you can have an army of people getting something done faster. Um, but you also end up with a lot of errors, so uh, it's a just a nice thing that we can use scripting for. And if I look at this next slide here,
too, talks to some of the BioWare's experiences with this. And again, talking to the point, too, of how much time do you spend scripting something uh, versus, you know, if army of people or or if even just a few people just spent like a really a lot of time working on something. And it it there's a tricky balancing act to understand, oh, maybe I spent way too much time doing something that didn't really save a lot of time. So, uh, it was Dave Shaffer, who's a lead SDET at BioWare there, um, did a return on investment uh, analysis. And they measured that they saved 30 months, uh, based on just QA effort QA efforts alone, um, through FB scripts. And not every script saved time, so actually, if I look at that last slide there again, this couple other things I wanted to mention, too, is uh, they had to ask other questions, like some scripts that you're running are actually doing things that are physically not possible, no matter how many button clicks you throw at it. Um, so there are some scripts like that, and
to try to make that distinction of could this have been done by hand? No, this is new functionality added that we just wouldn't have even uh, tried to take on without this. Um, and then in addition to that, of all of the things created, if we see in the lower end spectrum, there were scripts that were arguably a waste of time. So, you know, maybe more time was spent creating something and it wasn't used as much as it was anticipated, um, and uh, you didn't get your return on investment there. But by far and large, you're going to find the medium um, is going to return a significant value. And then every once in a while you hit the jackpot, where you're like, wow, that was really taking us a lot of time by hand, but we really saved a lot of time. Um, and so you see those edge cases there, as well. Oh, and one other thing, too, I wanted to point out to on this slide is um uh this quote here by Darren Clark. Um and just the key thing there is the fact that when you free when you free up the time on your team you can spend more time testing other areas. So, it's if you kind of applying
your scripts to those technical things that can be automated um and that require that technical test, the things that you need creative people and in this case QA are creative people that help us understand what's the quality of our product in this case uh gameplay experiences are, uh we can get their time dedicated in a much more effective way in that way. All right. So, next steps. Um I've talked about Well, let's see here. I've talked a while about stuff in the past and that stuff I mean, it's it's a bit tricky. I'm a generalist and I think of my mind like a revolving door. So, that stuff comes in and then it goes out and then I have to really try hard to go back and dig it up and and understand it again. I'm always far more excited about the next steps. So, uh this stuff has me really excited going forward. It's Okay, we've done some stuff and it was valuable and that's shipped games and that's cool, but what does the future hold and what are we going to do with that? So, Michael Sharp at Criterion has created something that we're we're planning to use internally. It's called
uh he's named it community toolbox. Um while this is not immediately applicable to this audience, you're not going oh, cool, I want to use community toolbox. It's not an uh application that we're trying to pitch or sell or it's going to be used outside of EA, but the idea here is behind how to connect a lot of people that are building stuff and then wanting to share it between teams, studios, domains, whatever the case may be. And so, that's what I want to look at here is how to best uh facilitate that. So, I've got a video. Let's take a peek. All right. So, he set up a web portal um and that's really nice. Everyone can access it across the company. We can download this tool. The installation process is fairly straightforward. Not a lot of options or buttons or fields or things to fill up. We just download it. We launch Frostbite. It matches up the environment system there with that.
And then we've got that new tool that's available in the taskbar. So accessibility is always really key. Here we're looking at a look dev visual environment. We're just getting a feel for how certain things render behave with camera and all that kind of stuff. When you normally move a camera around in Frostbite and most editors, you're using a mouse. You're using a mouse probably alt key or something like that and clicking and dragging and orbiting and zooming and trucking and all that. That's the normal way, but if you want to use a controller, you could. Now this isn't functionality that was created by the Frostbite team. It's something that Mike hooked up with a bunch of other component pieces here to interface with an Xbox controller in the editor. So how did he do that? Well, without closing Frostbite there, he just browsed on the website there that had this available, clicked on that DLL or that plugin and clicked install and then went back to Frostbite and there it is available. So now it's the Xbox controller doing all sorts of additional functionality like tilt and all of that kind of stuff.
So again, less about the exact specifics of what's going on right here, more about the idea behind hey, when you have a framework that actually supports scripting, there's more to just there's more to it than just scripting. There are all these other kind of hooks that you can plug in various plugins into, no pun intended, a lot of additional functionality there. So that's cool. Have something that's really accessible, but this other thing right here is really key too and uh is something that he's created called Script Pad. And the way this functions is inside of that same ecosystem, uh the idea of being able to browse the tools and things that other people are writing uh across multiple teams. And then when you find something that you're interested or want to actually test out that it's readily available there right inside of the editor. So, in this case, uh we've got a test camera there that we're pulling down as a test from Bioware, and we're going,
"Okay, cool. We've got a slider here, and it's adjusting the the zoom of the the camera." We can look at the edit script. So, you can peek behind the functionality of any given tool there. And this is all inside the editor, so it's not like we had need to have Visual Studio open or that we need to have any other kind of uh a bunch of stuff to go and figure out how was something done. All of that stuff is packaged up together there. And then uh because we had previously downloaded uh the script pad, we don't need to do that again. So, it's just illustrating that we can always grab any existing tool that's on the machine, or we can always grab an updated version of it. And in this particular example, we're going, "Okay. Well, it's common in a pipeline to get a good or some sort of reference that isn't exactly the name of an object." So, someone created a tool that will allow us to take a good, put that into a simple text field, hit a button, and it would find where that uh the asset using that good is in a scene and frame it in selection. Um and then we can look at the code
behind that as well. And it's a script, and it references a whole bunch of stuff, but also has lots of revisions. And this is a key thing for me going forward is uh in trying to build to implement, to support, and maintain this kind of a solution, um is easy enough on one team um with a handful of people using it. As you get into the hundreds of people using something, and they're across multiple versions of your editor, and to try and maintain while okay they they have this script but it's for a a different version of the editor. How you maintain all of that? I'm really excited to look at solutions like this that will help manage that. And then there's all sorts of searches and filters and advanced filters to not only find a tool of a given name but also even go deeper than that and say find me all the tools that use this keyword or bit of code in it. All right. Wrapping up. So yes indeed on the shoulders of giants.
Lots of people contributing and helping and supporting and all of that. Not the least of which Ludovic Chopard is the guy who introduced me to Iron Python, helped kick this thing off. I've done a lot of the implementation since then but big shout out to Ludo. DevHawk found is an invaluable resource online. Avalon Edit another invaluable resource. Huge respect for well the initial inventor of Iron Python Jim Hugunin and subsequent maintainer of that Jeff Hardy. And a huge long list of credits and thanks and really the list does go on. And here we are with questions. So and a quick reminder to evaluation. So there you go a little guide. It take three clicks.
Oh, here we got a mic on? Oh. Looks like we need help with the excuse me looks like we need help with the mic here. Hello. Ah, okay. Um, when you were showing when you were showing the auto complete for the um Python, you said you were evaluating the the Python code before that. How are you dealing with side effects in there? Uh, sorry, if I understood the question is when I'm showing the auto complete dialogue Yes. for the Iron Python, what was the second part of the question? Um, how are you dealing with the um with with like if I have code that has side effects that like does something, Mhm. but you're also evaluating it just to do the um auto complete in and then you do the auto complete on the object, Mhm.
Um, if I understand the question is how to uh how do I distinguish the difference between a property on a code completion and a method that's going to do something and perhaps what the parameters are for that method. Am I getting that right? Um, no, it's it's it's like um so if if you're in the script you're creating an object and then later further down the script you're offering all the auto complete options on that object. Mhm. Um if you have to evaluate that multiple times, aren't you creating the object multiple times? And wouldn't you have like lots of side effects from that? Oh, I think it's just for memory and scope management and if you have uh something already in memory and you're looking at a property of that in memory and then another property of that in memory, the concern is about how that exists inside of scope and uh is there any knock-ons or issues with that? Well, also this if if I'm like if I'm in the level I'm creating whole objects, Mhm. like actually placing like I don't know trees in the level or something, Yeah. wouldn't I be running that over and over again just for the auto complete? Um, yeah, the interesting thing about this is that it's actually just referencing it's just references. Mhm.
So, it doesn't duplicate anything in memory. So, when we're looking at an object that is there and we want to access it, we can change a value on it Mhm. and it's changing the value it because it's referenced to the actual object, it changes the value on the object itself. It doesn't exist more than once in Okay, so you're only always re-evaluating the current line, not not the entire script. That's correct, yes. Okay, thanks. Hi. Hi. Uh given that you originally wanted to start with C#, now that Microsoft released Project Roslyn and F# type providers, would you still go back to IronPython? Um that's a good question. I'd actually have to learn more about that. I mean, if you're available afterwards, I'd love to chat. Sure. Cool, thanks. Hi. Hello. Oh, hi. Um I just had a question about uh it's kind of more policy, really. If you're opening up those tools and the the last slide you showed where you've got a kind of an online community where people can share scripts and so on, do you have any
kind of security concerns about basically allowing anybody to write code that effectively runs up running on anybody else's machine? Yeah, that's a really good question. Um it's funny because the amount of stuff that we expose in FrostEd is actually truly terrifying to the engineers that wrote it. Um and they're like, "Well, what if everything breaks? Like, someone's going to use it incorrectly and stuff's just going to, you know, stop working." Um the environment that we work in with Perforce is is a decent safety net. So, you can actually run mayhem on a complete data set, but that's your local copy and nothing gets submitted until it's validated. But, that validation step is really key. So, we did really large batch processes on like tons of data on Dragon Age, for example. But, we spent a day or two with QA validating, making sure all of the runtime Sorry, the runtime implication Let's try that again. The runtime implications of that were all sound. And so, yeah, there is actually due diligence required to make sure that what you're doing, especially in broad strokes,
holds up. Cool, thank you. Hi. How much work did you have to do to the code of your editor to expose all all functionality, or did you get most of it for free because you were doing everything with C sharp? We got most of it for free because we're doing everything with C sharp, especially in .NET. Um there are tricky bits there is if you have really uh risk-averse or really I don't know. I I mean there's there are ways in which you could implement a .NET solution that wouldn't be as readily excuse me readily exposed. Um but yeah, anything that's declared as a public function, if it isn't private or protected, um will be there for you uh to utilize as you need. Cool. Thanks. Hey. Um when you're using the scripts, are you able to like undo and redo the effects that they do? Uh yes and no. Um there are some commands that are wrapped that way inside of the Frost editor and
uh we have a roadmap in place for future improvements towards that to better handle undo redo, but for the most part um especially if we're just doing a a uh property change or whatever. The future is yes, but at the moment it's it's a bit um it's a bit sparse that way. Yeah, so w- how do you explain it is then if you would go in a for loop and go through all the objects and change like one property in all of them, so you would have to undo through each and every object then separately on the like if you did a something wrong? That's possible or yeah, to batch uh of call a reset value or something like that. Yeah. Okay. Thank you. Yeah. While you're working on this, do do you guys end up implementing um debuggers or like ways to visualize like the current state of the Python environment? Yes. Um it's something I did implement fairly early, although I haven't seen it in as wide use in production. Um the DevHawk website has some really good examples of it there in play as well. Um
you absolutely can and I have it hooked up in a prototype fashion where you could put in a breakpoint, hit those breakpoints, and on a breakpoint inspect or watch all sorts of variables and modify those variables on the fly. So, all of that stuff is possible. I've seen it in practice, but getting it really slick so that it's, you know, production ready is a bit more tricky. Oops. Cool. Thank you, everyone.
Auto-generated captions from YouTube — names and numbers may be misheard.
Distilling the key insights…
Game Developers Conference · 2026
Jonas Tyroller · 2025
Comments