QuakeC

QuakeC is a QuakeC virtual machine in Elixir. It reads compiled QuakeC programs (progs.dat, csprogs.dat, menu.dat). It runs their functions against builtins that your host supplies.

Where it fits

quake_c knows nothing of worlds, drawing or networking. The host does that work. A 3D host reads the game's files and maps with cauldron_3d_formats. It answers the program's tracing and movement builtins with cauldron_3d's Cauldron3D.Hull and Cauldron3D.Move. It draws with cauldron_3d or cauldron_gpu.

Installation

Add the dependency to mix.exs:

def deps do
  [
    {:quake_c, "~> 0.3"}
  ]
end

Usage

defmodule MyGame.Builtins do
  def call(%{qc: qc} = host, 25, _argument_count) do
    IO.write(QuakeC.string(qc, QuakeC.slot(qc, 4)))
    host
  end
end

{:ok, progs} = QuakeC.Progs.parse(File.read!("progs.dat"))
host = %{qc: QuakeC.new(progs)}
host = QuakeC.Exec.call_named(host, "main", MyGame.Builtins)

The host is any map with the memory under :qc.

Write the builtins as a module with call(host, builtin, argument_count). It returns the host. builtin is the builtin's number. For a builtin the program binds by name (#0:name), it is the name.

A builtin's arguments are in global slots 4, 7, 10 and on, three slots each. Read them with QuakeC.slot/2 or QuakeC.slot_vector/2. Put the result in slots 1 to 3 with QuakeC.put_slot/3. A builtin may run QuakeC itself by calling QuakeC.Exec.call/4 again. It may stop every running function with QuakeC.Exec.abort/1.

What is here

The compile cache

A program is compiled the first time it runs on a node. Every later run loads it from the cache. The first run of a large program takes noticeable time.

The cache directory is the application setting :quake_c, :cache_dir. By default it is the user cache directory's quake_c. Each program's entry is named by its digest.

config :quake_c, cache_dir: "/var/cache/my_game/quake_c"

License

MIT. FTE's pr_comp.h and execloop.h define the extended instructions this machine runs.