[HN Gopher] Low-latency scripting for game engines
       ___________________________________________________________________
        
       Low-latency scripting for game engines
        
       Author : fwsgonzo
       Score  : 93 points
       Date   : 2024-05-26 05:42 UTC (1 days ago)
        
 (HTM) web link (fwsgonzo.medium.com)
 (TXT) w3m dump (fwsgonzo.medium.com)
        
       | shmerl wrote:
       | I must be missing some idea used there. Why does scripting need
       | emulation of hardware?
        
         | fp64 wrote:
         | I don't have an answer either, but I've seen people who want to
         | use bytecode/a VM using RISC-V just because it's well defined
         | and tooling is already there. This has less to do with RISC-V
         | hardware, or even really the fact that it's RISC-V, and more
         | with using a simple bytecode and VM - e.g. JVM could also work
         | there, but the Java ecosystem comes with what some people
         | consider considerable pain.
        
           | neonsunset wrote:
           | Many game developers have been successfully using XNA/FNA
           | with C# on all kinds of platforms (and, of course, Unity
           | existed for a long time, and now we have Godot and Stride
           | too). You get to access all the low-level bits when you need
           | to, and you don't have to sacrifice productivity or
           | performance for scripting otherwise.
        
         | boffinAudio wrote:
         | It doesn't need emulation of _hardware_ per se, but most
         | scripting environments are already _virtual machines_ of some
         | variety or another - and RISC-V just happens to be the latest
         | in a long line of virtual machine architectures available for
         | the purpose.
         | 
         | The author is cleverly using libriscv for this purpose - and it
         | is indeed a neat use of the library - but I fail to see the
         | 'scripting' part, personally - isn't it scripting when you can
         | just load a text file off the disk, containing program
         | instructions, have it interpreted into some (hopefully
         | optimized) interim representation, and then pushed through a
         | virtual machine? I don't see the "text files" part here - but
         | perhaps it gets more relevant in parts 2/3/4, which I haven't
         | read yet, either...
         | 
         | EDIT: I heard you like ABI, so I put a foreign ABI within your
         | ABI so you can ABI with your ABI .. actually, this started off
         | as a joke but its kind of painful to think about. This isn't
         | really "scripting" .. its more "embed a foreign ABI into your
         | application so you can throw a foreign binary at it, any time,
         | and modify program behaviour extensively "without needing to
         | recompile" .. maybe the author should rename the article "how
         | to embed a virtual machine into your app so you never have to
         | write (your app code) again .."
         | 
         | I can see why they call it "scripting" since, this is what you
         | usually do when embedding the Lua VM into an app - but the fact
         | that I have to use a compiler disqualifies the term 'scripting'
         | from being applicable here, imho ..
        
           | exDM69 wrote:
           | > but the fact that I have to use a compiler disqualifies the
           | term 'scripting' from being applicable here, imho ..
           | 
           | I'm not sure if this is a useful distinction to make.
           | 
           | Lua, perhaps the most used scripting language out there, runs
           | through a compiler too and then runs a bytecode interpreter
           | on the resulting code. Most scripting languages work this
           | way. The compiler is still there even if it gets invoked at
           | runtime. Most games ship the compiled bytecode files, not the
           | script source.
           | 
           | The key part here is loading the "script" bytecode at runtime
           | and then executing it in the host, allowing reloading and
           | restarting the script without restarting the "host" process
           | (often a game engine with long load times and lots of
           | resident assets like textures, shaders, models etc that don't
           | need reloading).
           | 
           | The host process _could_ also include a mechanism to invoke
           | the compiler at runtime, pass in the script as text, grab the
           | output and then run it as it does currently. This would be
           | identical to how Lua et al work, but quite a bit of work to
           | set up for limited benefit.
        
             | boffinAudio wrote:
             | Hey - the distinction _is important_ but I don 't think
             | you've got it right.
             | 
             | Out-of-the-box, Lua runs through an _interpreter_ - not a
             | _compiler_.
             | 
             | A compiler produces native machine code from a human-
             | readable programming language for the target platform -
             | whereas an interpreter (in some cases) produces an interim
             | representation (bytecode) for a virtual machine, not
             | necessarily native - and in other cases, simply executes
             | script code line-by-line, without the interim step.
             | 
             | In the case of Lua, this interim representation is in the
             | form of bytecode which is then further interpreted by a
             | virtual machine, pretending that it is a register-based
             | machine vastly different to the actual hardware it is
             | running on. This particular aspect is the _only_ feature
             | that the authors ' libriscv usage and the Lua VM have in
             | common - but that doesn't make it _scripting_.
             | 
             | And scripting means (to my jaded 40-years of development
             | brain) to load text files from a resource (disk or
             | otherwise), interpret it in some interim form, and then
             | push through a secondary mechanism for final execution in
             | the native environment.
             | 
             | >The key part here is loading the "script" bytecode at
             | runtime and then executing it in the host, allowing
             | reloading and restarting the script without restarting the
             | "host" process (often a game engine with long load times
             | and lots of resident assets like textures, shaders, models
             | etc that don't need reloading).
             | 
             | So this is where our definitions conflict and go awry,
             | because to me all you've described is runtime loading of a
             | binary resource. Is loading and parsing a .PNG resource
             | that appears in your executive bundle somewhere, also
             | considered "Scripting" in your opinion? Because I don't
             | think that is an accurate use of the term, personally. It
             | would be scripting if the file (or memory blob) was somehow
             | modifiable by the user, and then interpreted without
             | further interaction required on the part of the developer -
             | but in this case (the article) the developer (not the end
             | user) still has to compile a binary blob, integrate it into
             | their application, and then 'run it'.
             | 
             | This is more appropriately referred to as runtime resource
             | modification and execution - for which the action of
             | "scripting" is a superset - but the fact that there are
             | _two compilers_ involved in this project (native to build
             | the .exe, and risc-v cross-compiling to build the binary
             | blob resource for integration) means that we are far, far
             | away from the typical scripting mechanic.
             | 
             | Its important to make this distinction. This isn't about
             | scripting. It is about runtime resource modification and
             | processing - but the different paths taken to the same fork
             | in the road between scripting and compiling are vastly
             | different and should not be conflated.
             | 
             | This isn't to say that integrating libriscv as a virtual
             | machine in ones application execution environment is not a
             | brilliant idea with a great deal of merit - just that the
             | author is incorrectly using terms, and this must simply not
             | be allowed. There is no interpreting happening here until
             | runtime - when the binary risc-v blob is loaded and parsed
             | by a virtual machine. If there were some mechanism to load
             | code intended for the risc-v component _at runtime_ ,
             | compile it, and load it for execution/report errors in the
             | script/etc. - then I would say that the scripting workflow
             | has been completed for this project - and it would be
             | appropriate to use the term - but that has not happened
             | here. It still requires a separate compilation (risc-v
             | machine code) step, and there are still many, many aspects
             | of the scripting workflow that are not implemented in this
             | project ..
        
               | fwsgonzo wrote:
               | You're right! I actually did try to integrate a compiler,
               | but I quickly realized that it wasn't worth it for me,
               | personally. Iterating on the script is very quick right
               | now. It's mostly a matter of compiler flags and ccache,
               | believe it or not. And I can use mold for linking RISC-V!
        
               | boffinAudio wrote:
               | Its great work, and you've inspired me to put libriscv in
               | places where I usually put the LuaVM, but I wish you'd
               | update your article to s/Scripting/Dynamic modification
               | of resources at runtime/ .. or something.
               | 
               | We can see, already here in this thread, the dangers of
               | people mis-interpreting your technology.
               | 
               | Now, if you get the riscv compiler integrated into your
               | projects such that we can indeed just load a text file
               | containing C code, dynamically at runtime, (a la
               | shaders), I'll revisit all of this and go along with your
               | program. ;)
               | 
               | Anyway, thanks for the great series of articles - really
               | gave me an interesting read on the way to work this
               | morning, and I've put libriscv (as well as your sample
               | projects) in my stack of Lab Todo's for the week .. now
               | if someone produces LuaRISCV that targets the riscv VM
               | instead of Lua Bytecode, that's gonna break a few molds,
               | in and of itself .. ;) (In the context of your work so
               | far, this seems like a low-hanging fruit, actually..)
        
               | exDM69 wrote:
               | > Out-of-the-box, Lua runs through an interpreter - not a
               | compiler.
               | 
               | The first thing the "interpreter" does is run the Lua
               | code through `luac`, the Lua _compiler_ and then feed the
               | bytecode to the Lua VM. This may be transparent to the
               | user, but it 's still there.
               | 
               | Almost all interpreted languages have a compiler and a
               | bytecode interpreter as distinct steps.
               | 
               | > Is loading and parsing a .PNG resource that appears in
               | your executive bundle somewhere, also considered
               | "Scripting" in your opinion?
               | 
               | Of course it's not, an image file does not contain any
               | code that could be interpreted or executed in a host
               | environment.
               | 
               | There is a distinction here on how code is executed,
               | whether by compiling, interpreting, JITting or a
               | combination of the above. But if you draw the line for
               | "scripting" at consuming textual source code, that would
               | exclude most use of Lua in gaming engines, as it is
               | typically distributed as bytecode and may not even link
               | luac compiler to the host executable. Yet it's commonly
               | called "scripting" in the industry.
               | 
               | And conversely, if the code in this article included a
               | mechanism to compile the source to risc-v would it meet
               | your definition of "scripting"?
               | 
               | There isn't a clear definition of what's scripting and
               | what's not, but drawing the line at consuming textual
               | source code is not, in my opinion, a _useful_ distinction
               | (it 's certainly a distinction) because it hardly matches
               | what's the state of the art out there.
        
               | boffinAudio wrote:
               | For _decades_ , compiling has referred to the process of
               | turning human-readable language into native machine code.
               | _That is what is happening here._
               | 
               | Interpreting has, also for decades, referred to the run-
               | time interpretation of human-readable language into some
               | mechanism which either a) immediately results in native
               | execution at runtime, or b) produces errors reported to
               | the developer for fixing, _precluding_ the generation of
               | immutable machine code being executed natively by the CPU
               | (except of course with JIT, which _is a form of
               | compilation at runtime_ , since the interim bytecode is
               | translated into real machine code instructions...)
               | 
               | Scripting has, for decades - not just in the gaming
               | industry, which is a subset of computing enterprises -
               | meant "loading a human readable text file containing a
               | programming language and directly executing it if it
               | passes validation - reporting errors, otherwise,
               | preventing further execution. This is why we have BASH
               | scripts and Python scripts and Lua scripts - they are not
               | machine code, they are interpreted and either eventually
               | produce machine code, or run through a state device
               | pretending to be a non-native machine.
               | 
               |  _fwsgonzo is literally compiling C code into machine
               | code to be executed on a pretend CPU (in the form of an
               | embedded libriscv)._
               | 
               | The code is not interpreted (from one language to
               | another) - it is executed in a virtual machine
               | environment. Bytecode _is_ , on the other hand, always
               | interpreted from one form to another prior to execution
               | (except JIT, it is only interpreted once, compiled, and
               | then exists as machine code always)
               | 
               | fwsgonzo's binary blob is executed by a 'fake' CPU, it is
               | not interpreted.
               | 
               | If he had the execution environment set up, he could
               | literally run that very same machine code on real RISCV
               | hardware, unchanged, without translation or
               | interpretation.
               | 
               | It is not, therefore, interpreted in any sense other than
               | by his embedded RISCV emulator - and thus it is not
               | scripting!
               | 
               | This is the point where the distinction is important.
               | 
               | >The first thing the "interpreter" does is run the Lua
               | code through `luac`,
               | 
               | The first thing the Lua interpreter does is validate the
               | inbound, human-readable script to make sure the program
               | is correct, syntactically and otherwise - giving errors
               | to the developer if errors are encountered. Meaning, at
               | runtime, errors can be caught and fixed by the human
               | developer.
               | 
               | Only then, once it has been validated, is it processed
               | into an interim representation as bytecode. Sure, Lua can
               | be told to produce bytecode in order to speed up runtime
               | loading and execution, but its still an _interpreted
               | bytecode_. It hasn 't been compiled into a native form
               | for direct execution - it still requires a secondary
               | _native program_ (a VM host) in order to provide any
               | functionality.
               | 
               | From the Lua 5.1 manual, Section 2.4.1:
               | ...          Chunks can also be pre-compiled into binary
               | form; see program luac for details. Programs in source
               | and compiled forms are interchangeable; Lua automatically
               | detects the file type and acts accordingly.
               | 
               | Lua _does have a compiler_ for the case where you want to
               | create Lua bytecode (.luac), as a loadable-at-runtime
               | resource to be further interpreted and also, the
               | _bytecode is subsequently interpreted according to the
               | needs of the target (native) environment on which it is
               | being executed, whether through a JIT or otherwise_. That
               | same bytecode can be executed on vastly different native
               | CPU architectures - _through interpretation_.
               | 
               | The difference is, prior to Lua's internal compilation of
               | the script into bytecode, _validation of the programs
               | correctness is performed, preventing the developer from
               | producing incorrect bytecode if there are errors_ , and
               | this is the process of scripting - distinct from
               | compilation - because it is a more direct human/computer
               | interaction regarding the correctness of the script
               | language as it is being used by the developer.
               | 
               | >There isn't a clear definition of what's scripting and
               | what's not, but drawing the line at consuming textual
               | source code is not, in my opinion, a useful distinction
               | (it's certainly a distinction) because it hardly matches
               | what's the state of the art out there.
               | 
               | I disagree with you, there very definitely _IS_ a clear
               | definition of what is scripting and what is not - one
               | must not call it  'scripting' unless runtime loading,
               | validation (or not), interpreting, and subsequent
               | execution (whether on an interim bytecode or otherwise)
               | is happening - and that is not what is happening here in
               | fwsgonzo's project. He is compiling binary blobs, and his
               | eventual execution environment has _nothing to do with
               | the validation of the scripted code_. The C compiler he
               | uses in a prior step does, however.
               | 
               | Scripting is a development workflow where
               | compilation/linking/building is not required - results
               | are immediate, the program reports validity of the loaded
               | script, or otherwise, and executes directly upon command
               | by the developer.
               | 
               | Additionally, fwsgonzo has also, already confirmed that
               | this distinction is correct (see elsewhere in the thread)
               | - that in fact interpreting of a script is _NOT_
               | happening in any sense other than the RISCV VM is
               | interpreting pre-validated machine code (not bytecode!)
               | in the form of RISCV instructions.
               | 
               |  _That machine code is not a human-readable script, and
               | it is not bytecode! It is machine code, produced by a
               | compiler._
               | 
               | This distinction is important because that same machine
               | code could, theoretically, be executed directly,
               | unmodified, on a RISCV machine - _that is not the case
               | with Lua bytecode, ever, which always requires
               | interpretation by a VM._
               | 
               | fwsgonzo's project is _entirely based around pre-
               | compilation of native binary resources_ , not
               | interpretation. A human-readable language is not being
               | interpreted by his runtime.
               | 
               | There is no opportunity (at runtime) with his project to
               | have the runtime report on errors in the human-readable
               | script - this has all been done with a prior
               | _compilation_ step.
               | 
               | >but drawing the line at consuming textual source code is
               | not, in my opinion, a useful distinction (it's certainly
               | a distinction) because it hardly matches what's the state
               | of the art out there.
               | 
               | I disagree with you. I think you are taking an aberration
               | of the gaming industry, which is rife with such things,
               | and applying it to computing as a whole - and this is
               | where the protest over your position lays.
               | 
               | It is absolutely important to make this useful
               | distinction, because in case a) INTERPRETATION: an
               | interim representation is being generated after
               | validating program correctness/conformity to a language
               | spec, and in case b) COMPILATION: no such validation is
               | occurring once the compiler produces runnable machine
               | code.
               | 
               | > Yet it's commonly called "scripting" in the industry.
               | 
               | I have 40 years of experience with this subject,
               | including working on game engines and realtime
               | (scientific) use of Lua in high-performance environments,
               | and the phrase "scripting" has _always_ referred to the
               | process of writing code that is immediately interpreted
               | by some program before resulting in actual runtime
               | execution if it is found to be valid code.
               | 
               | The interpretation may not even work as desired, but the
               | host environment/program will still continue to be
               | executed in a runtime context.
               | 
               | The fact that compilers "interpret" code before producing
               | an interim representation that is then used to produce
               | static machine code, is entirely why the distinction must
               | be made: _because there is a point where code can be
               | incorrect and thus not runnable!_
               | 
               | In the game world, "scripting" means 'writing some human-
               | readable script and having it interpreted at runtime,
               | without involving a native
               | compilation/linking/building/packaging step" - and as
               | this is not what is happening (key word: without) in
               | fwsgonzos' project, it is incorrect use of the phrase.
               | 
               | He is compiling resources which can be loaded at runtime,
               | bypassing the native loading/linking phase, and it is
               | therefore more appropriate to refer to what he is doing
               | as "runtime resource management" which, incidentally,
               | feeds into a VM. This is not scripting, although
               | scripting often necessitates the same activity - errors
               | in the code are not reported at runtime, by the process
               | doing something with the resource.
               | 
               | Please just use the right term and stop trying to justify
               | an incorrect usage - don't re-define these terms based on
               | a misunderstanding of the mechanics involved. There are
               | literally _decades_ of examples which are entirely
               | counter to your misunderstanding out there, in the state
               | of the art.
               | 
               | (tl;dr - Is /bin/bash a compiler? Is /bin/python a
               | compiler? Why isn't gcc exclusively referred to as an
               | interpreter? Is clang an interpreter? Is ld a scripting
               | environment?)
        
               | indigoabstract wrote:
               | > This particular aspect is the only feature that the
               | authors' libriscv usage and the Lua VM have in common -
               | but that doesn't make it scripting.
               | 
               | Maybe I'm nitpicking, but to me scripting is just
               | programming/extending a certain fixed piece of software
               | to execute instructions not already programmed into it
               | without having to modify that software itself. Usually
               | using an API. Not unlike computer programming, which aims
               | to make a piece of hardware execute some instructions
               | without needing to alter the said hardware. The main
               | difference is conceptual (the platform targeted: hardware
               | or software). If the script happens to be run by a VM
               | emulating a real processor because your software includes
               | such a thing, I think the distinction becomes purely
               | conceptual.
               | 
               | Now, the technology is obviously super cool, but what I
               | don't quite understand yet is what is the best use case
               | for this? Is it really game scripting? Or compiling C++
               | on the fly?
               | 
               | It's not exactly a simple drop in replacement for a Lua
               | interpreter.
        
             | mistercow wrote:
             | I would argue that "scripting" has to do with what you, as
             | the programmer, do to deploy your code, and not what
             | happens under the hood. If you can deploy by shipping a
             | single source code file, that's a script. If there's a
             | build step, that's not a script. Whether the underlying
             | system compiles it, interprets it, sends it to MTurk for a
             | human to evaluate by hand, or whatever doesn't matter.
        
         | fsniper wrote:
         | Isn't it mentioned as "sandboxing"? If the script runs in a
         | controlled vm, it can not reach the game's internal state
         | unless it is exposed to the vm.
        
         | bawolff wrote:
         | I was kind of wondering that too. Perhaps for sandboxing, but
         | then i wonder why not something like webassembly or even eBPF.
         | I kind of wish the author went more into the why of it.
        
           | fwsgonzo wrote:
           | Nothing wrong with using WebAssembly, if you wish to. eBPF
           | I'm not so sure is a good fit. Most people are just fine with
           | Lua, LuaJIT or Luau though. This is really just for
           | especially interested, or if you really need low latency.
        
       | gudzpoz wrote:
       | > ... but Lua still creates issues now and then. Like if you
       | forget return, the return value is that of the last expression.
       | 
       | Is this true? Or was it true for some Lua 2.X versions? Because
       | it does not seem to be the case for Lua 3.0 and on: [1]
       | 
       | > If control reaches the end of a function without a return
       | instruction, then the function returns with no results.
       | 
       | As to the idea of using an emulator for scripting, it seems a bit
       | similar to approaches using WebAssembly. But looking into the
       | benchmarks [2] provided by libriscv, it is quite interesting to
       | see it outperforms luajit and wasm3 (in its "hand-picked" tests,
       | at the very least).
       | 
       | [1] https://www.lua.org/manual/3.0/manual.html [2]
       | https://github.com/fwsGonzo/libriscv?tab=readme-ov-file#benc...
        
         | sebstefan wrote:
         | I've forgotten `return` plenty of times and to the best of my
         | recollection it's always returned `nil` to the caller.
         | 
         | Maybe he's talking about something else than pure lua?
         | Something with the game's bindings?
        
           | fwsgonzo wrote:
           | Maybe I'm old now. I'll remove it from the article! Reading
           | back on it, it seems like I'm writing negatively about Lua,
           | despite using it for many years. I think highly of Lua, and
           | especially think it has made so many things easier for people
           | over the years. I actually chose Nelua as one of the examples
           | (Part 3) because of it!
        
         | fwsgonzo wrote:
         | I spent a lot of time on those benchmarks. I think my
         | conclusion is just that because WASM isn't a register-machine
         | architecture, you basically have to implement a register
         | allocator to be really fast. wasmtime uses a complex allocator
         | to great success. wasm3 has done it too, but it's just a basic
         | one and it won't be able to compete with GCC or Clang. I could
         | be wrong here, but what else is there? During my testing, it
         | was never in question if libriscv was faster.
         | 
         | I used my usual benchmarks: STREAM (memory) and CoreMark (CPU).
        
       | dazzawazza wrote:
       | This is seriously cool but I really think we are losing our way
       | in game development.
       | 
       | We used to create DSLs to make scripting of games simpler and
       | less error prone... so that coders/designers could write
       | Scripts/AI in a language better suited to the problems they face.
       | It was sort of a side issue that is was a sandbox although that
       | was really useful for lots of reasons.
       | 
       | Now we seem to be creating more and more complex toolchains while
       | complaining that game development is getting more and more
       | expensive. We're not solving the correct problems at all.
       | 
       | Oh well.
        
         | johnnyanmac wrote:
         | Even if it's c++ to c++, the goal of scripting at the end of
         | the day is quick iteration. What is "quick iteration" for
         | scripting will depend on the scriptor.
         | 
         | This article is clearly targeted at engineers rolling their own
         | engine, so that audience may find it beneficial keep everything
         | in one language if they are already comfortable with it. As
         | long as the core engine doesn't need to re-compile every little
         | change, it's a win.
        
           | fwsgonzo wrote:
           | Yeah, I can confirm that the iteration speed is fast. I
           | consider the scripting portion a solved problem right now,
           | having used it so long. Gamedev is so many other things
           | though, and practically every corner of the engine has to
           | have convenience functionality in order to reduce the overall
           | workload. It's rough for gamedevs right now, I feel like.
        
             | johnnyanmac wrote:
             | IMO the big tools are convinent enough to use. But the
             | rampup time to really understand how the engine ticks is
             | dreadful, because documentation drops off a cliff once you
             | want to do more than animate a few dozen actors in a level
             | (and tbf, sometimes that is indeed enough to ship).
             | 
             | The other half of the problem is asset production time. But
             | no game engine is really solving that problem. As you'll
             | discover in that domain, the art community is a lot more
             | protective of their techniques and pipelines than
             | programming. Even more so if looking for game ready asset
             | production. Same issue, different cause.
        
         | nxobject wrote:
         | There is one benefit to jumping through these hoops to use C++
         | as a scripting language (how much of a benefit it is, well,
         | that's your judgment): you get to reuse libraries, as the
         | author notes.
        
         | pjc50 wrote:
         | Modern AAA game development is suffering a chronic
         | mismanagement problem. Like fimmaking. Poor creative vision,
         | not communicated clearly to those executing it; endless
         | rewrites and rework; lack of originality; poor treatment of
         | staff leading to poor morale; and churning away in the
         | background, the culture war.
         | 
         | Technically the only interesting challenge is "how do we get
         | off Unity?"
        
           | chii wrote:
           | > a chronic mismanagement problem. Like fimmaking.
           | 
           | the mismanagement stems from the fact that it is costing too
           | much from the onset, and "management" wants to ensure that
           | the investment makes a good enough return to justify the high
           | cost.
           | 
           | Therefore, they dictate all of the risks have to be removed -
           | such as not going for a risky new brand, but make a sequel.
           | They want realistic graphics because it's more commercially
           | viable - going for a different or uncommon aesthetic means
           | taking risks.
           | 
           | I would argue all of the problems in AAA development stems
           | from this fact.
           | 
           | it is also why indie games can be so cheap yet so successful.
           | Not because indies are better (tho they are- at least more
           | passionate if nothing else), but because indies are capable
           | of taking risks to push the edge and make something new and
           | untested.
           | 
           | It's the same as films - creative endeavours cannot have
           | their risks managed away. It is inherent, and there's a large
           | chance of failure even if the team has done their best.
        
             | kevindamm wrote:
             | The risk aversion in product is not a new phenomenon,
             | though. Bigger producers have been following that track
             | since at least the 90s. Adherence to brand, and even more
             | so to basic game genres and mechanics, has been an issue
             | complained about by devs at any big enough studio for
             | decades.
             | 
             | What changed, I think, is all of the development studios
             | being bought up by large producers. But, then again, I see
             | steam as being a great counterforce on this, and the ease
             | of releasing on web or mobile has been a boon for indie
             | devs too. So maybe that hasn't changed that much.
             | 
             | The technology has advanced to where you can spend
             | blockbuster budgets and get nearly film-quality results
             | (not nearly possible in the cartridge and CD days).
             | Meanwhile the price per AAA title has stayed relatively
             | fixed at 50-60 USD for that same range of time, so
             | production houses have had to try being appealing to ever-
             | larger audiences. Fortunately, many people continue playing
             | these games into their 30s and 40s so the market grows on
             | its own too.
             | 
             | I'm trying to say you're right about the risk aversion
             | being a big part of the industry's problems but that's been
             | an issue for a while, it has gotten terribly enhanced with
             | the growth of the industry.
             | 
             | Now I wonder which is worse.. extracting money one quarter
             | a time with punishingly difficult timing tests, or
             | extracting money via cosmetics that have no actual game
             | impact but are marketed very compellingly.
        
             | the_snooze wrote:
             | >it is also why indie games can be so cheap yet so
             | successful. Not because indies are better (tho they are- at
             | least more passionate if nothing else), but because indies
             | are capable of taking risks to push the edge and make
             | something new and untested.
             | 
             | The cheapness also means indies simply get more "shots on
             | goal." The barrier to entry is relatively low, so failing
             | is lower-stakes. You have way more indies trying (and
             | mostly failing), which means you have a greater raw number
             | of hits. That's compared to a big company only having a
             | handful of big-budget games in development.
        
           | 587846 wrote:
           | This certainly seems to be true, at least for one modern
           | example, according to a recent post that linked to a YouTube
           | video whose creator evidently has insider information about
           | the 'failure' of Kerbal Space Program 2
           | (https://news.ycombinator.com/item?id=40485788).
        
           | chris37879 wrote:
           | As someone in an otherwise healthy position at my job, fuck
           | yes, I want to get away from Unity, but there's just no
           | better option for the platforms we're targeting and how
           | quickly we want to ship things. Something about the devil you
           | know, ya know?
        
         | kgabis wrote:
         | Shameless plug, but some time ago I've created a language where
         | the main design goal was for it to be easy to use and embed:
         | https://github.com/kgabis/ape.
        
         | nox101 wrote:
         | Something I want is a sandboxed place to run USER scripts in
         | game. I trust the game's creators to not hack my machine with
         | their DSL (else I wouldn't be running their game). I don't
         | trust random drive by game mod to the same level. I'd love not
         | to have to trust user additions, but currently I do have to
         | trust them or go without.
         | 
         | I run a few games that takes C# plugins. The games have a big
         | warning that they aren't doing anything to prevent my machine
         | getting hacked, personal files uploaded to random servers,
         | etc....
        
           | maccard wrote:
           | You want luau - https://luau-lang.org/
           | 
           | It's what Roblox uses
        
             | JonChesterfield wrote:
             | Or lua itself
        
       | sebstefan wrote:
       | > 2. Install a RISC-V compiler
       | 
       | > On Linux this is fairly straight-forward.
       | 
       | Well... Of course on Linux it would be straight forward
       | 
       | I'd love for games to start having any/all system languages as
       | the embedded scripting language.
       | 
       | But with Linux being around ~2% of the market share (with "~" in
       | a hand-wavey way), I was kinda looking for the Windows steps to
       | see if how much of a pain this would actually be if somebody
       | wanted to set it up.
        
         | fwsgonzo wrote:
         | Ah yeah, I have installed RISC-V with a oneliner in WSL. So
         | it's not too far off on Windows, but I mostly program on Linux
         | these days. You can also build on a Linux VM and share it to
         | Windows, but what kind of iteration loop is that?
         | 
         | I don't know. Perhaps clang-cl could be used on Windows? It
         | depends on how much of a run-time environment one wants.
        
       | nxobject wrote:
       | I just think it's neat that the canonical script package is an
       | Linux ELF binary.
        
         | pdpi wrote:
         | Is there anything Linux-specific about ELF? I was under the
         | impression it's a pretty common format for executables, used by
         | a whole bunch of systems. It certainly predates Linux, as it
         | was (according to Wikipedia) introduced in 1988 with SVR4.
        
           | gmueckl wrote:
           | The ELF format is shared between different platforms. There
           | are identifiers for the target OS and CPU in the ELF header.
        
       | lenkite wrote:
       | This is wonderful! No need for a second language for
       | plugins/extensions if your software is written in C++. Hell, it
       | is mind-blowing - using a RISC-V emulator to run _C++_ scripts.
       | Lol - this is not something that immediately strikes one 's
       | brain. Looking forward to fully digging into this next weekend.
        
       | highsea wrote:
       | Reminds me how Quake3 shipped with a VM to compile/run the C game
       | code.
        
       | ceronman wrote:
       | If I understand correctly, the idea here is to provide safe
       | scripting by running a RISC V emulator. The "scripts" would be
       | written in C/C++ compiled to RISC V. And then these compiled
       | scripts would be run inside the game engine's emulator. The
       | emulator's library then will allow to share some memory between
       | the emulated program and the host game engine by sharing some
       | memory.
       | 
       | All this sounds like a poor re-invention of Web Assembly 1.0.
       | 
       | I think Wasm is a better option for most cases because:
       | 
       | - There are more advanced Wasm runtimes that can do JIT
       | compilation and be very fast.
       | 
       | - There are probably more languages compiled to Wasm than to RISC
       | V. Especially for higher level languages, which is attractive for
       | scripting.
       | 
       | - There is better tooling for debugging Wasm.
       | 
       | - Interoperability is better specified in Wasm, it was designed
       | from the ground up for that. And with Wasm components it's even
       | better. This is specially important for different host
       | architectures.
        
         | fwsgonzo wrote:
         | This whole comment sounds dismissive towards both me and RISC-V
         | as an architecture people actually run their computers on.
         | 
         | I have a lot of blog posts that you can read to get up to
         | speed. Or maybe you already made up your mind.
        
           | JonChesterfield wrote:
           | Risc-v is a hardware ISA optimised for education. Wasm is a
           | sandboxed IR optimised for compilers. It would be
           | phenomenally unlikely for risc-v to be better than wasm in
           | the exact domain wasm was built to excel at.
        
             | thefaux wrote:
             | Both are targets for a general purpose programming
             | language. As OP commented below, wasm is a stack machine
             | while riscv is a register machine. It would surprise me if
             | there is any wasm program for which there is not a
             | semantically equivalent and faster riscv implementation.
        
               | JonChesterfield wrote:
               | Wasm has locals and block arguments, it's no more a stack
               | machine than risc-v is a stack machine.
        
           | ceronman wrote:
           | In no way I intended to be dismissive of you work or the
           | RISC-V architecture. I apologize if my words could be
           | interpreted in that way. I actually think that RISCV is a
           | really cool architecture, mostly because it is open. I would
           | love to see it getting more traction in the hardware world. I
           | also think that your work on libriscv is impressive!
           | 
           | My criticism was at the idea of using a RISC-V emulator as a
           | scripting platform. And I'm not saying that it doesn't work,
           | only that I personally think that Web assembly seems a better
           | option for that particular use case.
        
             | fwsgonzo wrote:
             | I've been at it for a few years now and my experience with
             | game engine scripting is that the functions are small, and
             | that it's helpful or pleasant to have the ability to make
             | many calls back into the game engine to ask for things,
             | even simple things. My measurements have shown time and
             | again that libriscv spends 3ns entering and leaving the
             | emulator dispatch, and 2ns to execute a system call or even
             | a more complex host function scheme (using custom
             | instructions).
             | 
             | So now it's a race. For example, wasmtime needs 48ns just
             | to enter and leave, and 24ns to make a call into the host.
             | That's around 100-150 instructions libriscv can execute
             | before wasmtime has even overcome the fixed call latencies.
             | And then add 50 each time we make a call back into the
             | engine.
             | 
             | Now combine this with my ~200 host functions in my game,
             | and I don't know how many in-game events. Which function
             | would wasmtime be faster at? I don't know, probably not a
             | single one. And that's really it. There's no fibonacci
             | computations in game engine scripting. It's just logic.
             | 
             | As far as using complex run-times for scripting: I've
             | already been doing this dance for years now. For example,
             | TinyKVM is a native performance KVM userspace emulator that
             | I among other things ran v8 inside. You can find my
             | research paper about it. So it's not like I couldn't throw
             | v8 in there and slideware some JS solution. But, I really
             | do prefer writing C++.
             | 
             | Also related is attack surface. libriscv is 10k LOC.
             | wasmtime is what, 350k LOC?
             | 
             | Here is a random function I benchmarked:
             | https://fwsgonzo.medium.com/a-sandboxed-rainbow-
             | function-b42...
             | 
             | wasmtime spent 107ns and libriscv 57ns. Those kinds of
             | functions is your average script function. And, even if we
             | were exactly matching in latency, I would still call that a
             | win!
             | 
             | EDIT: To add, you did make a good point about tooling,
             | components etc.
        
         | neonsunset wrote:
         | It's a classic fallacy of thinking "interpreter would be fast
         | enough". Except here it's worse by not even getting the
         | productivity advantage of automatic memory management!
         | 
         | No, use something actually good for gamescript, like C#, which
         | is industry proven and has no issues interpreted languages
         | suffer from.
         | 
         | I'm always baffled this even has to be said, yet enthusiast
         | circles keep sabotaging themselves in assuming they can do
         | better with techniques known to do worse.
        
         | bitwize wrote:
         | Or QuakeC. That's pretty much what QuakeC was like.
        
           | Narishma wrote:
           | I don't think so. QuakeC was its own language.
           | 
           | This is more like Quake 3 which used a general purpose VM
           | that you could compile regular C to.
        
         | senkora wrote:
         | > There are probably more languages compiled to Wasm than to
         | RISC V. Especially for higher level languages, which is
         | attractive for scripting.
         | 
         | To expand on this, this is especially useful for modding. The
         | original developers should probably standardize on a single
         | scripting language for practical reasons, but individual
         | modders or groups or modders may benefit from being able to
         | choose their scripting language independent of the original
         | developers'.
        
       ___________________________________________________________________
       (page generated 2024-05-27 23:01 UTC)