Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor persistent memory to use #[wasm_bindgen] struct #54

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions javascript/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use strict";
let wasm_module;
let bot;

// replace this with the name of your module
const MODULE_NAME = "screeps-starter-rust";
Expand Down Expand Up @@ -36,20 +36,22 @@ module.exports.loop = function () {
Game.cpu.halt();
} else {
try {
if (wasm_module) {
wasm_module.loop();
if (bot) {
bot.loop();
} else {
// attempt to load the wasm only if there's enough bucket to do a bunch of work this tick
if (Game.cpu.bucket < 750) {
console.log("we are running out of time, pausing compile!" + JSON.stringify(Game.cpu));
return;
}
// load the wasm module
wasm_module = require(MODULE_NAME);
const wasm_module = require(MODULE_NAME);
// load the wasm instance!
wasm_module.initialize_instance();
// Create the instance of our Bot class
bot = new wasm_module.Bot();
// go ahead and run the loop for its first tick
wasm_module.loop();
bot.loop();
}
} catch (error) {
console.error("caught exception:", error);
Expand Down
65 changes: 38 additions & 27 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use std::{
cell::RefCell,
collections::{hash_map::Entry, HashMap, HashSet},
};
use std::collections::{hash_map::Entry, HashMap, HashSet};

use js_sys::{JsString, Object, Reflect};
use log::*;
Expand All @@ -17,14 +14,6 @@ use wasm_bindgen::{prelude::*, JsCast};

mod logging;

// this is one way to persist data between ticks within Rust's memory, as opposed to
// keeping state in memory on game objects - but will be lost on global resets!
thread_local! {
static CREEP_TARGETS: RefCell<HashMap<String, CreepTarget>> = RefCell::new(HashMap::new());
}

static INIT_LOGGING: std::sync::Once = std::sync::Once::new();

// this enum will represent a creep's lock on a specific target object, storing a js reference
// to the object id so that we can grab a fresh reference to the object each successive tick,
// since screeps game objects become 'stale' and shouldn't be used beyond the tick they were fetched
Expand All @@ -34,27 +23,49 @@ enum CreepTarget {
Harvest(ObjectId<Source>),
}

// add wasm_bindgen to any function you would like to expose for call from js
// to use a reserved name as a function name, use `js_name`:
#[wasm_bindgen(js_name = loop)]
pub fn game_loop() {
INIT_LOGGING.call_once(|| {
// Annotating a struct with `#[wasm_bindgen]` will generate a JS class of the same name with all
// methods that are also annotated with `#[wasm_bindgen]`. The generated class is a simpler wrapper
// around an integer representing a pointer to the struct instance in the WASM heap.
// This is one way to persist data between ticks within Rust's memory, as opposed to
// keeping state in memory on game objects - but will be lost on global resets!
#[wasm_bindgen]
pub struct Bot {
creep_targets: HashMap<String, CreepTarget>,
}

#[wasm_bindgen]
impl Bot {
#[wasm_bindgen(constructor)]
pub fn initialize() -> Self {
// Put any code that only should happen once at startup here

// show all output of Info level, adjust as needed
logging::setup_logging(logging::Info);
});

debug!("loop starting! CPU: {}", game::cpu::get_used());
Self {
creep_targets: HashMap::new(),
}
}

// add wasm_bindgen to any function you would like to expose for call from js
// to use a reserved name as a function name, use `js_name`.
#[wasm_bindgen(js_name = loop)]
pub fn game_loop(&mut self) {
debug!("loop starting! CPU: {}", game::cpu::get_used());

// mutably borrow the creep_targets refcell, which is holding our creep target locks
// in the wasm heap
CREEP_TARGETS.with(|creep_targets_refcell| {
let mut creep_targets = creep_targets_refcell.borrow_mut();
debug!("running creeps");
for creep in game::creeps().values() {
run_creep(&creep, &mut creep_targets);
run_creep(&creep, &mut self.creep_targets);
}
});

run_spawns();
cleanup_memory();

info!("done! cpu: {}", game::cpu::get_used());
}
}

fn run_spawns() {
debug!("running spawns");
let mut additional = 0;
for spawn in game::spawns().values() {
Expand All @@ -71,7 +82,9 @@ pub fn game_loop() {
}
}
}
}

fn cleanup_memory() {
// memory cleanup; memory gets created for all creeps upon spawning, and any time move_to
// is used; this should be removed if you're using RawMemory/serde for persistence
if game::time() % 1000 == 0 {
Expand Down Expand Up @@ -99,8 +112,6 @@ pub fn game_loop() {
}
}
}

info!("done! cpu: {}", game::cpu::get_used())
}

fn run_creep(creep: &Creep, creep_targets: &mut HashMap<String, CreepTarget>) {
Expand Down