Grocery Game

A grocery store simulation game

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.

Patreon PayPal Logo

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

WebAssembly is a binary instruction format for a stack-based virtual machine. WebAssembly is designed as a portable compilation target for programming languages, enabling deployment [anywhere] for client and server applications.

webassembly.org, emphasis added

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:

  1. Protect users from buggy or malicious modules, and
  2. Provide developers with useful primitives and mitigations for developing safe applications...
Security, webassembly.org, emphasis added

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:

Teraflop Engine's cube example.

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

Take the above scene, for example:

🌍️ World

  • 🗃️ Green Cube
    • 📊️ Mesh: Green
    • 📊️ Material: Sunlit
      • 📊️ Shader: Vertex
      • 📊️ Shader: Fragment
    • 📊️ Transform: $$ translate(\begin{bmatrix}x: 1.2, y: 1.50, z: 0\end{bmatrix}) * rotate(45.radians, up) $$
  • 🗃️ Fuchsia Box
    • 📊️ Mesh: Fuchsia
    • 📊️ Material: Sunlit
      • 📊️ Shader: Vertex
      • 📊️ Shader: Fragment
    • 📊️ Transform: $$ scale(\begin{bmatrix}x: 1.2, y: 0.45, z: 1.2\end{bmatrix}) $$
Figure 1: State of the World in the cube example.

Note an identical instance of the Sunlit material, Figure 2 below, is shared between both of the World’s entities.

  • 📊️ Material: Sunlit
    • 📊️ Shader: Vertex
    • 📊️ Shader: Fragment
Figure 2: Sunlit Material

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.

  • System: rotate

    Rotates the camera around the scene at 6 RPM

  • System: aspectRatio

    Preserves the camera's aspect ratio when the game window is resized

  • 🛠️ File Watcher
  • Systems Built Into the Engine:
    • 🛠️ Pipeline Preparer
    • 🛠️ Resource Initializer
    • 🛠️ Texture Uploader
Figure 3: Systems that operate on the World in the cube example.

Hot Reloading Shaders

Teraflop Engine hot reloading the fragment shader of the cube example.

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:

  1. Re-Integrate Ultralight
  2. Back port the existing store floor space system, i.e. walls, doors, shelves, and checkstands
  3. Get back to fleshing out more game systems, starting with agent-based shoppers and pathfinding

Citations

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.

Patreon PayPal Logo

Feedback

Let me know your thoughts and ideas for the game.

Written on January 8, 2021