Skip to content

Instantly share code, notes, and snippets.

@laverdet
Created June 28, 2021 04:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laverdet/b58d691cbd317d11f54324230fae49ea to your computer and use it in GitHub Desktop.
Save laverdet/b58d691cbd317d11f54324230fae49ea to your computer and use it in GitHub Desktop.
Screeps WebAssembly module demo
let i32;
let u8;
let creeps;
export function initialize(wasm) {
const { memory } = wasm.exports;
const reset = () => {
i32 = new Int32Array(memory.buffer);
u8 = new Uint8Array(memory.buffer);
};
reset();
wasm.exports.memory.addGrowCallback?.(reset);
}
export function evaluate(string) {
return eval(String.fromCharCode(...u8.subarray(string, u8.indexOf(0, string))));
}
export function getTime() {
return Game.time;
}
export function findCreeps(addr) {
creeps = Object.values(Game.creeps);
for (let ii = 0; ii < creeps.length; ++ii) {
i32[(addr >>> 2) + ii * 2] = creeps[ii].pos.x;
i32[(addr >>> 2) + ii * 2 + 1] = creeps[ii].pos.y;
}
return creeps.length;
}
export function dispatchMoveIntent(creep, direction) {
return creeps[creep].move(direction);
}
#include <ctime>
#include <iostream>
#include <random>
#define IMPORT(module, symbol) __attribute__((import_module(module), import_name(symbol)))
#define EXPORT extern "C" __attribute__((used))
struct Creep {
int x, y;
};
IMPORT("./binding.js", "evaluate") int evaluate(const char* source);
IMPORT("./binding.js", "getTime") int get_time();
IMPORT("./binding.js", "findCreeps") int find_creeps(Creep creeps[]);
IMPORT("./binding.js", "dispatchMoveIntent") int dispatch_move_intent(int creep, int direction);
EXPORT void loop() {
// Initialize random
std::random_device rd;
std::mt19937 gen{rd()};
std::uniform_int_distribution distrib(1, 8);
// Log current time, takes TZ environment into account
const auto time = std::time(nullptr);
char time_str[100];
if (std::strftime(time_str, sizeof(time_str), "%c", std::localtime(&time))) {
std::cout << "Starting tick[" << get_time() << "] @ " << time_str << '\n';
}
// Spawn creeps
evaluate("Game.spawns.Spawn1.createCreep([ MOVE ])");
// Move creeps in a random direction
Creep creeps[16];
const auto length = find_creeps(creeps);
for (int ii = 0; ii < length; ++ii) {
const auto move = distrib(gen);
std::cout << "Moving creep[" << creeps[ii].x << ", " << creeps[ii].y << "] -> " << move;
std::cout << " = " << dispatch_move_intent(ii, distrib(gen)) << '\n';
}
}
export { loop } from './loop.wasm?TZ=CST+6';
# emcc: `-fwasm-exceptions` and node: `--experimental-wasm-eh` are available but not super well
# supported right now, so C++ exceptions will exit the wasm runtime via a JS exception.
CXX = em++
LD = emcc
CXXFLAGS = -O3 -std=c++20
EMFLAGS = -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s ALLOW_MEMORY_GROWTH=1 --no-entry
loop.wasm: loop.o
%.wasm: %.o
$(LD) -o $@ $^ $(EMFLAGS)
.PHONY: clean
clean:
$(RM) *.o *.wasm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment