Modding Grocery Game
Happy New Year! 🎉️
Mods give old games new life. What’s more, extensible software can be engineered faster. Grocery Game welcomes mods with open arms!
Additional work has begun to increase the game’s customizability. Meanwhile, work continues integrating the gfx D library into Grocery Game’s underlying engine.[1]
If you’d like to play the game:
Subscribers of $5 or more on Patreon and other donors will also receive access to an Alpha version of the game.
Choosing a Scripting Language
The game’s UI is built with web technologies enabling quick iteration on the game’s UX. Keeping with JavaScript, already used in the GUI, seemed a logical choice especially given its massive ubiquity.[2]
Then came the daunting task of choosing from the many JS engines. V8 (of Node.js and Deno fame), duktape, and QuickJS were evaluated. I’ve had some experience integrating duktape into an application, but its ES6+ support is lacking.[3]
Prototyping an implemention of the moddable SDK’s XS JS engine was fruitful, but its API is cumbersome.
WebAssembly
Portability and Security
“WebAssembly’s binary format is designed to be executable efficiently on a variety of operating systems and instruction set architectures, [on and off the Web]”
[4] and is being designed to work in non-web, embedded environments. The standards body behind it is even developing it’s own C API.
“WebAssembly describes a [secure] and sandboxed execution environment …”
[5] with two important goals:
See the WebAssembly FAQ for more information.
What this means for Grocery Game
Any programming language can be used to mod the game.
Wasmer
The game’s engine is choosing Wasmer as its WebAssembly runtime.
Thanks to Wasmer’s smaller surface area (~80 functions), it was easy to embed, taking only a couple days to fashion D bindings to Wasmer. The resulting library is now included in Wasmer’s official list of Language Integrations.
Modding Grocery Game
Mods in a game engine require an interface to the game in order to change the game’s state. Officially called Plugins, mods in Grocery Game are bootstrapped from WebAssembly modules that export specific functions:
export function main(): boolean
In an effort to support JS as a source language, the Teraflop Scripting SDK initially supports AssemblyScript, a strict subset of TypeScript, as a source language, but many other languages have WebAssembly targets.
Modding API
namespace Plugin {
interface Plugin {
name: string,
version: Version
}
/** A `Plugin`'s [Semantic Version](https://semver.org). */
interface Version {
major: number,
minor: number,
patch: number,
meta: VersionMeta | number
}
/**
* Register a plugin with the game's registrar.
* @param version The plugin's [Semantic Version](https://semver.org) packed into a 32-bit bitfield.
* @see {@link makeVersion}
*/
declare function register(name: string, version: i32): bool
// `declare` denotes a Host-defined member, i.e. exposed as a module import from the Host game
/**
* Pack a [Semantic Version](https://semver.org) into a 32-bit bitfield.
* @param major Incompatible API changes
* @param minor Added functionality in a backwards compatible manner.
* @param patch Backwards compatible bug fixes.
* @param meta Additional label for pre-release and build metadata, defaulting to {@link VersionMeta.Release}
*
* @returns A 32-bit bitfield:
*
* | major | minor | patch | meta |
* | ----------- | ----------- | ----------- | ----------- |
* | `0000 0000` | `0000 0000` | `0000 0000` | `0000 0000` |
*/
function makeVersion(major: u8, minor: u8, patch: u8, meta: i32 = VersionMeta.Release): i32
enum VersionMeta {
Release = 0,
ReleaseCandidate = 1,
PreRelease = 2,
Beta = 3,
Alpha = 4,
PreAlpha = 5,
MAX = u8.MAX_VALUE
}
/** Unpack a [Semantic Version](https://semver.org) from a 32-bit bitfield. */
function unpackVersion(version: number): Version & { raw: number }
}
Teraflop Engine Musings
The game’s engine has received a lot of love in the last month. Of note:
- Continued integration of the gfx D library
- The successful integration of the ambient Sunlit shader teased last October
- Addition of a
Transform
component - Hot Reloading Shaders, and
- A new cube example scene:
Components All the Way Down
Much like turtles, Components run all the way down in the Teraflop ECS. A game’s scene is composed of:
- 🌍️ World
- 🗃️ Entities, e.g. people, vehicles, walls, doors, checkstands, etc.
- 📊️ Components, i.e. data or state important to render an Entity
- 🗃️ Entities, e.g. people, vehicles, walls, doors, checkstands, etc.
Take the above scene, for example:
Note an identical instance of the Sunlit material, Figure 2 below, is shared between both of the World’s entities.
Systems
The game logic in a Teraflop application is a collection of Systems that performs actions on and mutates the state of the World’s Entities. Figure 3 outlines the systems in play in the cube example scene, some of which are built into the engine’s core and run in every game application.
Hot Reloading Shaders
The infrastructure setup to support reloading shaders at runtime, e.g. the File Watcher in Figure 3, will also come in handy for hot reloading other aspects of the game, including templated shelf archetypes, agent scripts, and the GUI. 😀️
What’s Next
While waiting for PRs to gfx to get merged, Teraflop’s scripting interface will see some enhancements and further integration with the Wasmer runtime.
After that:
- Re-Integrate Ultralight
- Back port the existing store floor space system, i.e. walls, doors, shelves, and checkstands
- Get back to fleshing out more game systems, starting with agent-based shoppers and pathfinding
Citations
- 1: See my pull requests to the gfx D library.
- 2: Search interest for JavaScript, Lua, and Python, common choices for application scripting, Google Trends.
- 3: Post-ES5 features, Duktape Wiki.
- 4: Portability, webassembly.org.
- 5: WebAssembly, webassembly.org.
Alpha Access
Subscribers of $5 or more on Patreon and other donors will receive access to an Alpha version of the game for play testing.
Feedback
Let me know your thoughts and ideas for the game.