Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign upScripting API #271
Comments
This comment has been minimized.
This comment has been minimized.
|
Thanks for the summary! The point about After the renderer rewrite is merged I'm going to start a game; it may be useful to have a game at hand to evaluate which parts of it could be written more efficiently. |
This comment has been minimized.
This comment has been minimized.
|
Just want to throw in a scripting language I considered, but threw away, because it is quite dead at the moment. I might be a better start than creating a new one from scratch, though: https://github.com/jonathandturner/rhai
Examples: use std::fmt::Display;
extern crate rhai;
use rhai::{Engine, FnRegister};
fn showit<T: Display>(x: &mut T) -> () {
println!("{}", x)
}
fn main() {
let mut engine = Engine::new();
engine.register_fn("print", showit as fn(x: &mut i64)->());
engine.register_fn("print", showit as fn(x: &mut bool)->());
engine.register_fn("print", showit as fn(x: &mut String)->());
}extern crate rhai;
use rhai::{Engine, FnRegister};
#[derive(Clone)]
struct TestStruct {
x: i64
}
impl TestStruct {
fn update(&mut self) {
self.x += 1000;
}
fn new() -> TestStruct {
TestStruct { x: 1 }
}
}
fn showit<T: Display>(x: &mut T) -> () {
println!("{}", x)
}
fn main() {
let mut engine = Engine::new();
engine.register_type::<TestStruct>();
engine.register_fn("update", TestStruct::update);
engine.register_fn("new_ts", TestStruct::new);
if let Ok(result) = engine.eval::<TestStruct>("var x = new_ts(); x.update(); x") {
println!("result: {}", result.x); // prints 1001
}
} |
This comment has been minimized.
This comment has been minimized.
|
I've been thinking about choosing a scripting language, however i think we should be able to do something similar to what gfx does with backends. From my point of view there are two main downsides to this approach:
|
torkleyy
added
diff: normal
pri: normal
project: workflow
labels
Aug 6, 2017
This comment has been minimized.
This comment has been minimized.
|
@torkleyy I think, this is the same discussion as with the config format. Which formats should we allow? Why not all of them? Because:
That's why I am, again, of the opinion, that Amethyst should make a sane choice and be consistent. |
This comment has been minimized.
This comment has been minimized.
|
If we want to decide for one, I cannot support your proposal for Rhai, however. I don't really like how it works; it's also considerably slow, which is unfortunate for using it in a game engine. |
This comment has been minimized.
This comment has been minimized.
|
dyon might be a good choice, it's very likeley that it could become a really fast language and it would probably interact with rust very well. However I'm a bit reluctant due to how young it is, and because its not wideley used its also another thing the user has to learn. Lua is also a popular choice for game engines, it's really fast with luajit and even if the user hasn't used it before there's really not much to learn about it. Not sure how well we would be able to handle running it on multiple cores. Javascript is another choice that might be good, with V8 its definitely fast, and much like hlua there is also a set of high level bindings available. Out of all these ones I would support Lua the most. However, I would still like to argue for allowing the user to choose their own scripting language. I haven't really looked into the config file discussion, so i might be make some points that already were debated there.
I disagree here, I would argue that when you are starting out a new project, having to choose the config file type might be a burden, because, everyhing is new and its another thing just before you can get started. However, I don't think the user will start implementing stuff around the scripting language before they develop something and have a bit of experience with the engine. But then again, they might just want to have a rust backend available if they need more performance and try to implement everthing on the scripting language.
I'll need to have a look at the discussion about this on the config files, however, i would say that we could just separate the documentation / tutorials between the crates, so for example you could explain how to setup the bindings in the amethyst documentation, and also on the bindings crate you could have a more comprehensive set of tutorials on how everything is going to work.
I agree with both of these. |
This comment has been minimized.
This comment has been minimized.
alteous
commented
Aug 6, 2017
|
Here's a crazy idea: How about using a subset of Rust as a scripting language. It has the advantage of being already familiar, and able to be compiled as a dylib if interpreting is too slow. |
This comment has been minimized.
This comment has been minimized.
|
Well, I don't really need a scripting language at all, since Rust is perfectly fine for these simple jobs, I mean it often even feels a bit like a scripting language with all the type inference and expressiveness. But it's really hard to discuss about this without an actual game. I would really vote for postponing this issue. |
This comment has been minimized.
This comment has been minimized.
Careful there! Just because you don't need it does not mean others don't either.
Rust is compiled, so it is no replacement for a proper scripting language. A script can be loaded and executed, but can be replaced or edited and re-loaded at runtime. Rust would have to be compiled and bindings would have to be de-/initialized, given that the dylib has a stable API (which usually is not the case during development)
I don't think that the discussion about the scripting language is dependent on a game. It is much more dependent on preferences and compüatibility with engine architecture. Hence, I think we can already discuss the feature. Just as @afonso360 wrote, this is not about implementation, but about specification :) |
This comment has been minimized.
This comment has been minimized.
alteous
commented
Aug 7, 2017
•
Here I mean a subset of the Rust grammar that may be interpreted or compiled at the user's discretion. |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Aug 7, 2017
|
Just for some potential ideas that can be taken from this since it is not really a scripting language (although it could be used as such) but look at Terra. It is Luajit combined with LLVM. It itself is basically a set of enhancements on top of luajit that add specialized bindings to the code generator for LLVM including being able to add types to code and more. Basically it is a code generation library, you could, for example, make a scripting language 'compiler' in terra that compiles a scripting language to native fast and optimized code at run-time via LLVM, or you could even compile it out to a stand-alone dynamic link library (or static link) that you could then load 'instantly' next time. The main thing I'm bringing up with this is that it would be really nice to have the engine 'export' the necessary primitives to be able to bind whatever scripting language we want, and things like Terra would use those exports directly, or something like a 'lua' binding would be a dynamic-link (or static link depending on how compiled) library that just creates the lua scripting engine with the proper bindings to the exports. It opens the entire gamut for what is possible when this is done. /me uses terra, though not as a scripting language but rather as a generator for, say, noise generators to make user-generates noise functions, as one example |
This comment has been minimized.
This comment has been minimized.
|
I agree with @torkleyy. We need real example (a game) to better understand what data we want to access from scripts, how to link it, how to run scripts. |
This comment has been minimized.
This comment has been minimized.
I think we can still make some headway before we get to the point where we need something specific.
It sounds like a lot of work, unless there is already something that we can use. |
torkleyy
added
the
status: discussing
label
Nov 29, 2017
torkleyy
added
diff: hard
and removed
diff: normal
labels
Dec 9, 2017
This comment has been minimized.
This comment has been minimized.
|
I've changed this to
|
torkleyy
self-assigned this
Dec 15, 2017
This comment has been minimized.
This comment has been minimized.
naturallymitchell
commented
Dec 30, 2017
|
If Amethyst could reuse WayCooler's Lua module (rlua IPC), that'd probably make your work easier and several projects' common code bases better. (Aside: imho, to run code with speed, it should be a core engine function. To tell an engine how to glue together a bunch of those functions, any practical scripting/config language could make sense.) Lua's interpreter seems very practical since it's a well-proven interpreter with well-established semantics, and rlua seems like a good wrapper with its safety measures and active development. |
This comment has been minimized.
This comment has been minimized.
|
I'm working on this issue and I'm already using rlua. But I'll tell you more once I got some nice results. |
This comment has been minimized.
This comment has been minimized.
|
Shameless plug https://github.com/gluon-lang/gluon. Since gluon is a statically typed language already, and it has full APIs for enforcing types between itself and Rust should be possible to integrate into Types with lifetimes may be possible. I actually had that working way, way back but ended up removing it since it was so limited (any lifetime needed to strictly outlive the interpreter itself making it more trouble than its worth). Thanks to some changes done in the last year it could be worthwhile to try it again however as it is now possible to create short lived child interpreters which are already have the capability to restrict short lived values from escaping to longer lived interpreters. Piggybacking on this system it should be possible to create a interpreter for each script call (the interpreter could easily be recycled to avoid allocating a fresh one each time), pass it some reference values to the script and then destroy/recycle the interpreter before the references lifetimes ends. No promises though :) |
This comment has been minimized.
This comment has been minimized.
|
gluon defintely looks interesting :) I'll look into it, but the time I can use for OS is currently rather limited. |
This comment has been minimized.
This comment has been minimized.
|
A very interesting discussion is going on here, thanks for all your contributions. Gluon seems to get a lot of development and I can imagine that Mozilla is interested in it. To me, it looks a lot like a primarily functional language that I love: OCaml. It is also in pure save Rust, so no unsafe code. I love the clear syntax and like to remind us, that Amethyst is also meant for game designers. Plus, it is type inferred and capable to display domain driven design very well. Other benefits are the thread safety and of course its deep cooperation with Rust which made it look like an obvious choice. Imagine all the capabilities that you can give the users. You can basically create an interface to every single function in the engine. This can be one of the features who turn out to set the project unique. One more thing is that Amethyst aims to be a showcase for Rust and Gluon is written in it. |
This comment has been minimized.
This comment has been minimized.
|
I started working on a scripting framework ( |
This comment has been minimized.
This comment has been minimized.
|
About dynamic recompiling in/with Gluon: gluon-lang/gluon#454 |
This comment has been minimized.
This comment has been minimized.
norman784
commented
Aug 28, 2018
|
I don't know if this discussion still going here, but I think theres a point of using a scripting language, and its attract users or maybe make thinks easier to other users (like an entry barrier) and lastly modding :), saying that I think the best option is a wide used scripting language, could it be JS, Lua, etc, I don't know OCalm (just by name) but to me feels a niche language, is not so wide used. About something that read in the first post about config files for UI, I agree with that, maybe something like yaml like mentioned or some html-ish template (my preferred here is pug-lang/slim-lang subsets), I mean take that syntax and use with the corresponding tags for each component (i.e. UiText, UiButton, UiImage, etc and take as tag attributes the property of each ui element), and maybe add some sugar with a small subset of css for the styling or just a css like for styling using the corresponding name of the elements and their properties (then maybe will be more json like). Well I propose this because to me feels more natural because my background as webdeveloper. But theres also another think, and it is real needed a scripting language at all (I mean for coding, not for the UI), because it may take a lot of resources to develop and maintain it, just take a look what Unity do, they drop the support for UnityScript (JS) and Boo, and they have the resources to maintain it, but maybe was not practical because the code redundancy (maintain 3 frontend langs on top of their c++ backend), docs maintenance, etc. If this last one is the case I'm in with releasing binding tools and the community work on what they feel better for them (so amethyst core team itself doesn't need to deviate the resources to this and can focus on making this engine more awesome). |
This comment has been minimized.
This comment has been minimized.
I think that the competence, elegance and curtness of a language is also important. Plus, Gluon is a real scripting language, written in and for Rust.
Its also easier to integrate. |
This comment has been minimized.
This comment has been minimized.
|
There is no need for particular scripting language support to be part of the engine though. |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Aug 28, 2018
Exactly this. This is the pattern I took, and it is the pattern that engines like Godot and Urho3D and others take as well. Just expose a native interface that can be linked to and other libraries can implement the scripting language integrations. |
This comment has been minimized.
This comment has been minimized.
|
Taking into account all the insights in this issue, @kabergstrom and I have been working for a couple days now on a design for scripting support that would work with direct C bindings through language-specific drivers, and that would satisfy the following constraints:
This approach was built to be able to append any language to the engine. We will open a RFC describing the details later. But before we do that, did we forget anything in those constraints? |
This comment has been minimized.
This comment has been minimized.
|
Despite the fact that it is extremely rough and has some hilariously unsafe code I think I should still bring up the specs/shred-gluon integration I have been sketching out. Still, it does sort of work and I haven't found any unsolvable blockers yet. The main issue is that the support for dynamic systems in specs/shred is rather lackluster at the moment, part of it can be solved by exposing a few currently private function with regard to component extraction (which shouldn't affect the safety in any way). There might very well be possible to provide a better dynamic system abstraction in the crates themselves which could be another way of fixing it. On the gluon side the main issue is that I have to cast away the lifetimes to pass in borrowed resources to the virtual machine. I think gluon can be improved to support that however. https://github.com/Marwes/shred-example/blob/master/src/gluon_system.rs |
This comment has been minimized.
This comment has been minimized.
|
Is it not possible to support an "official" scripting language (like Gluon) and an extension API for adding support for other languages? Sounds like best of both worlds to me. Folks who just can't live without language X can add language X support (or leverage the efforts of others who have already done so) and folks who are willing to use any language so long as it achieves maximum performance get the tighter integration of Gluon(?). Forgive me if I'm missing something obvious. I'm not a game dev. Just a hacker who likes to say he contributed to a game engine, haha. |
This comment has been minimized.
This comment has been minimized.
|
Well if you can support all languages, no need to worry about implementation details for a specific language. The only debate is what language will serve as an example made by the core team and Amethyst contributors ;) |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Aug 30, 2018
|
If you wanted a sandboxed language as 'official', just use a webassembly JIT (V8 or Firefox's are both fantastic), it's safe and fast both with already a lot of languages able to target it and more coming all the time. I'd still just vote for a native interface then implement everything on that. |
This comment has been minimized.
This comment has been minimized.
|
Because I am not a game dev, can someone help me understand how a scripting language is typically implemented in the context of a game engine? An example of what I mean: in a web app, if I wanted a button to react to user input, I would register a callback on that button's "onClick" method (typically in the HTML). Within that callback, I have access to a suite of functions exposed by the web browser to, for example, manipulate the DOM. What I'm failing to wrap my head around in the game engine context is: when/where/how are the scripts executed? Every frame? Do you register callbacks like in the web example? If so, does the game dev expose the types of hooks they want available to the scripting engine? Seems like there's no "standard" set of hooks like in the web case. If I want to be able to fire off a registered callback when the player opens a door, for example, I would have to implement the "doorOpened" hook, right? Then register a callback to that hook in the script? Or am I way off? Thanks :) |
This comment has been minimized.
This comment has been minimized.
|
@scorbeil I think you are mostly correct. With specs you implement any of that as a With scripts it is probably better to not check for events manually but let the scripting system do that. |
This comment has been minimized.
This comment has been minimized.
Thats interesting. It would also include all languages, who are able to compile into JavaScript. |
This comment has been minimized.
This comment has been minimized.
|
It's not unreasonable to consider WebAssembly as a scripting language itself however. |
This comment has been minimized.
This comment has been minimized.
|
@ShalokShalom and any language that targets LLVM IR can be compiled to wasm with emscripten, yes? |
This comment has been minimized.
This comment has been minimized.
|
That's several intermediate steps, but it should work? |
This comment has been minimized.
This comment has been minimized.
|
Is there any language that can do so, which does not yet have a proper 'to-Javascript' compiler? |
This comment has been minimized.
This comment has been minimized.
|
Not that I can think of off the top of my head, but it's nice that it's there. I really like the idea of using wasm for the scripting API. Just about any language is an option, then. |
This comment has been minimized.
This comment has been minimized.
jonathandturner
commented
Dec 8, 2018
|
I have to admit that my project Rhai is "dead", or at least very, very stable That said, I think there are a lot of ideas in there and the related ChaiScript that Rhai was inspired by. The original motivation for ChaiScript was that it would near-effortless to register information to an engine, and that you could write your own scripting language against this engine. ChaiScript started off as one of the sample languages you could write, but as it progressed, it quickly became the default. To this day, though, there's a separation in the engine and the language. Rhai also has a similar distinction where the engine piece allows you to easily (hopefully) register functions and data types into the engine, and then a scripting language can dispatch off of these. While Rhai not be alive, I think the ideas there are still sound and something that are worth exploring. I wrote Rhai when I was still learning Rust, so the code in places might need some updating, but an updated version of the engine approach could be quite helpful. Some of the core ideas:
The end result is one that doesn't use any unsafe code and can support Rust in a fairly natural way. Not to try to hard sell you, but I'd love to see these ideas live on. |
This comment has been minimized.
This comment has been minimized.
|
Yeah I've looked into Rhai some more since I wrote that comment. I think it has promising ideas :) I would personally not use it as is though. It has the necessary features, but one thing in particular that I'm unsure about is the function overloading. The problem I see is that by checking the exact type ids, it's easy to get an error because you're using a primitve with a different size ( Let's see, maybe I'll look into it again in a few months. |
This comment has been minimized.
This comment has been minimized.
jonathandturner
commented
Dec 13, 2018
•
|
@torkleyy - for that kind of case, it's good to be specific about what you support in the scripting language, and why. Scripting languages are often more flexible than the static languages, naturally. One place they tend to be flexible is with numerics. They may not tell a difference between i32 and i64. Whatever amethyst ends up using may instead convert all integers to isize/usize or i64/u64, for example. Just to be clear, I'm not suggesting anyone use Rhai. Instead, I'm suggesting using the techniques Rhai uses to make a scripting engine that works closely with Rust. |
This comment has been minimized.
This comment has been minimized.
|
We have an opened rfc about scripting and which languages will be supported (all of them lol). amethyst/rfcs#1 |
This comment has been minimized.
This comment has been minimized.
|
Closing this as it is subsumed by the RFC linked above. |
afonso360 commentedAug 6, 2017
•
edited by torkleyy
This issue is meant to consolidate the discussion around the Scripting API.
It might be a bit early for an actual implementation to come out of this, however, starting a discussion around API design and goals should provide benefits when impl time comes.
On a discussion in gitter we threw around some ideas
@torkleyy mentioned he would like to have an alternative to the classic scripting approach. One of the ideas proposed was to have flexible scripting files that could be used as config files.
With an example
Or, as config:
@Xaeroxe and @lschmierer Discussed some ideas involving accesing components from a scripting language. Briefly mentioned is the feasablity of running the scripting system in parallel as an actual System.
However this seems impractial due to the way
specsenforcesSystemDatacorrectness on a type level.There are a lot of things that need to be addressed, however, I think we should start with: