diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..387ab4e --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Compiled source # +################### +target + +# Packages # +############ +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# OS generated files # +###################### +.DS_Store +ehthumbs.db +Icon? +Thumbs.db + +# Project files # +################# +.classpath +.externalToolBuilders +.idea +.project +.settings +nbproject +*.iml +*.ipr +*.iws +*.sublime-project +*.sublime-workspace +screeps.toml diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..bc16adf --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,388 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "crustacean" +version = "0.0.0" +dependencies = [ + "fern", + "js-sys", + "log", + "screeps-game-api", + "serde", + "serde_json", + "structstruck", + "wasm-bindgen", + "wasm-bindgen-test", + "web-sys", +] + +[[package]] +name = "enum-iterator" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7add3873b5dd076766ee79c8e406ad1a472c385476b9e38849f8eec24f1be689" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "enum_dispatch" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fern" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee" +dependencies = [ + "log", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "num-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "screeps-game-api" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d0b5f3ad2c817d344c7794eafcc5d6a4becff5ddf7fbb15091e799cf083e49b" +dependencies = [ + "arrayvec", + "enum-iterator", + "enum_dispatch", + "js-sys", + "num-derive", + "num-traits", + "serde", + "serde-wasm-bindgen", + "serde_json", + "serde_repr", + "wasm-bindgen", +] + +[[package]] +name = "serde" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "structstruck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a052ec87a2d9bdd3a35f85ec6a07a5ac0816e4190b1cbede9d67cccb47ea66d" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "venial", +] + +[[package]] +name = "syn" +version = "2.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "venial" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61584a325b16f97b5b25fcc852eb9550843a251057a5e3e5992d2376f3df4bb2" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f55e1cb --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "crustacean" +version = "0.0.0" +authors = [] +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +js-sys = "0.3" +log = "0.4" +fern = "0.6" +screeps-game-api = "0.15" +wasm-bindgen = "0.2" +web-sys = { version = "0.3", features = ["console"] } +structstruck = "0.4.1" +serde_json = "1.0.104" +serde = { version = "1.0.183", features = ["derive"] } + +[dev-dependencies] +wasm-bindgen-test = "0.3" + +[profile.release] +panic = "abort" +opt-level = 3 +lto = true + +[package.metadata.wasm-pack.profile.release] +# Replace the following to enable wasm-opt optimization +# wasm-pack will try to install wasm-opt automatically, but it must be installed by hand on some +# operating systems. +wasm-opt = false +# See wasm-opt for full available options; handy examples: +# -O4 - optimize aggressively for performance +# -Oz - optimize aggressively for code size +# -g - leave debug info in place, allowing for more descriptive stack traces on panic +# --disable-sign-ext - prevents opcodes that the screeps servers can't load (see +# https://github.com/rustyscreeps/screeps-game-api/issues/391) +#wasm-opt = ["-O4", "--disable-sign-ext"] + +[features] +default = [] + +sim = ["screeps-game-api/sim"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bae16f1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 David Ross + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..481023e --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# screeps-starter-rust + +Starter Rust AI for [Screeps: World][screeps], the JavaScript-based MMO game. + +This uses the [`screeps-game-api`] bindings from the [rustyscreeps] organization. + +While it's possible to compile using [`wasm-pack`] directly using the Node.js target, +some modifications are needed to load the output within the Screep environment, so it's +recommended to use [`cargo-screeps`] for building and deploying your code. + +The documentation is currently a bit sparse. API docs which list functions one +can use are located at https://docs.rs/screeps-game-api/. + +Almost all crates on https://crates.io/ are usable (only things which interact with OS +apis are broken). + +Quickstart: + +```sh +# Install CLI dependency: +cargo install cargo-screeps + +# Clone the starter +git clone https://github.com/rustyscreeps/screeps-starter-rust.git +cd screeps-starter-rust + +# Copy the example config, and set up at least one deployment mode +cp example-screeps.toml screeps.toml +nano screeps.toml +# configure credentials (API key) if you'd like to upload directly, +# or a directory to copy to if you'd prepfer to use the game client to deploy + +# build tool: +cargo screeps --help +# compile the module without deploying anywhere +cargo screeps build +# compile plus deploy to the configured 'upload' mode; any section name you +# set up in your screeps.toml for different environments and servers can be used +cargo screeps deploy -m upload +# or if you've set a default mode in your configuration, simply use: +cargo screeps deploy +``` + +[screeps]: https://screeps.com/ +[`wasm-pack`]: https://rustwasm.github.io/wasm-pack/ +[`cargo-screeps`]: https://github.com/rustyscreeps/cargo-screeps/ +[`screeps-game-api`]: https://github.com/rustyscreeps/screeps-game-api/ +[rustyscreeps]: https://github.com/rustyscreeps/ diff --git a/javascript/main.js b/javascript/main.js new file mode 100644 index 0000000..aae2b0f --- /dev/null +++ b/javascript/main.js @@ -0,0 +1,59 @@ +"use strict"; +let wasm_module; + +// replace this with the name of your module +const MODULE_NAME = "screeps"; + +function console_error(...args) { + console.log(...args); + Game.notify(args.join(' ')); +} + +module.exports.loop = function () { + // Replace the Memory object (which gets populated into our global each tick) with an empty + // object, so that accesses to it from within the driver that we can't prevent (such as + // when a creep is spawned) won't trigger an attempt to parse RawMemory. Replace the object + // with one unattached to memory magic - game functions will access the `Memory` object and + // can throw data in here, and it'll go away at the end of tick. + + // Because it's in place, RawMemory's string won't be thrown to JSON.parse to deserialize - + // and because that didn't happen, RawMemory._parsed isn't set and won't trigger a + // post-tick serialize. + //delete global.Memory; + //global.Memory = {}; + try { + if (wasm_module) { + wasm_module.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 < 500) { + console.log("Not enough in the CPU bucket, not going to compile - CPU: " + JSON.stringify(Game.cpu)); + return; + } + + // delect the module from the cache, so we can reload it + if (MODULE_NAME in require.cache) { + delete require.cache[MODULE_NAME]; + } + // load the wasm module + wasm_module = require(MODULE_NAME); + if (wasm_module != undefined) { + // load the wasm instance! + wasm_module.initialize_instance(); + // run the setup function, which configures logging + wasm_module.setup(); + // go ahead and run the loop for its first tick + wasm_module.loop(); + } else { + console.log("Wasm module is undefined, is the name correct?") + } + } + } catch (error) { + console_error("Found error: ", error); + if (error.stack) { + console_error("Stack trace: ", error.stack); + } + console_error("Reloading wasm module"); + wasm_module = null; + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..69ee430 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,158 @@ +use log::*; +use screeps::ConstructionSite; +use screeps::{ + constants::{ErrorCode, Part, ResourceType}, + enums::StructureObject, + find, game, + local::ObjectId, + objects::{Creep, Source, StructureController}, + prelude::*, +}; +use serde::{Deserialize, Serialize}; +use wasm_bindgen::prelude::*; + +use crate::memory::{CreepMemory, Memory}; + +mod logging; +mod memory; + +// add wasm_bindgen to any function you would like to expose for call from js +#[wasm_bindgen(js_name = setup)] +pub fn setup() { + logging::setup_logging(logging::Info); +} + +// 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 +#[derive(Clone, Serialize, Deserialize, Debug)] +pub enum CreepTarget { + Upgrade(ObjectId), + Harvest(ObjectId), + Build(ObjectId), +} + +// to use a reserved name as a function name, use `js_name`: +#[wasm_bindgen(js_name = loop)] +pub fn game_loop() { + debug!("Loop starting! CPU: {}", game::cpu::get_used()); + debug!("Getting memory"); + let mut memory = crate::Memory::init_memory(); + debug!("Running creeps"); + for (name, _) in memory.creeps.clone() { + let creep = game::creeps().get(name.clone()); + if creep.is_none() { + info!("Found non-existent creep, removing..."); + memory.creeps.remove(&name); + memory.write_memory(); + } else { + run_creep(&creep.unwrap(), &mut memory.creeps.get_mut(&name).unwrap()); + } + } + + debug!("Running spawns"); + let mut additional = 0; + for spawn in game::spawns().values() { + debug!("Running spawn {}", String::from(spawn.name())); + + let body = [Part::Move, Part::Move, Part::Carry, Part::Work]; + if spawn.room().unwrap().energy_available() >= body.iter().map(|p| p.cost()).sum() { + // create a unique name, spawn. + let name_base = game::time(); + let name = format!("{}-{}", name_base, additional); + // note that this bot has a fatal flaw; spawning a creep + // creates Memory.creeps[creep_name] which will build up forever; + // these memory entries should be prevented (todo doc link on how) or cleaned up + match spawn.spawn_creep(&body, &name) { + Ok(()) => additional += 1, + Err(e) => warn!("Couldn't spawn: {:?}", e), + } + } + } + + memory.write_memory(); + info!("Done! cpu: {}", game::cpu::get_used()); +} + +fn run_creep(creep: &Creep, creepmem: &mut CreepMemory) { + if creep.spawning() { + return; + } + let name = creep.name(); + debug!("Running creep {}", name); + + let target = &creepmem.work; + match target { + Some(target) => { + let creep_target = target; + match creep_target { + CreepTarget::Upgrade(controller_id) + if creep.store().get_used_capacity(Some(ResourceType::Energy)) > 0 => + { + if let Some(controller) = controller_id.resolve() { + creep + .upgrade_controller(&controller) + .unwrap_or_else(|e| match e { + ErrorCode::NotInRange => { + let _ = creep.move_to(&controller); + } + _ => { + warn!("Couldn't upgrade: {:?}", e); + creepmem.work = None; + } + }); + } else { + creepmem.work = None; + } + } + CreepTarget::Harvest(source_id) + if creep.store().get_free_capacity(Some(ResourceType::Energy)) > 0 => + { + if let Some(source) = source_id.resolve() { + if creep.pos().is_near_to(source.pos()) { + creep.harvest(&source).unwrap_or_else(|e| { + warn!("couldn't harvest: {:?}", e); + creepmem.work = None; + }); + } else { + let _ = creep.move_to(&source); + } + } else { + creepmem.work = None; + } + } + CreepTarget::Build(site_id) => { + if let Some(site) = site_id.resolve() { + if creep.pos().is_near_to(site.pos()) { + creep.build(&site).unwrap_or_else(|e| { + warn!("couldn't build: {:?}", e); + creepmem.work = None; + }); + } else { + let _ = creep.move_to(&site); + } + } else { + creepmem.work = None; + } + } + _ => { + creepmem.work = None; + } + }; + } + None => { + // no target, let's find one depending on if we have energy + let room = creep.room().expect("couldn't resolve creep room"); + if creep.store().get_used_capacity(Some(ResourceType::Energy)) > 0 { + for structure in room.find(find::STRUCTURES, None).iter() { + if let StructureObject::StructureController(controller) = structure { + creepmem.work = Some(CreepTarget::Upgrade(controller.id())); + break; + } + } + } else if let Some(source) = room.find(find::SOURCES_ACTIVE, None).get(0) { + creepmem.work = Some(CreepTarget::Harvest(source.id())); + } + } + } +} diff --git a/src/logging.rs b/src/logging.rs new file mode 100644 index 0000000..3554dad --- /dev/null +++ b/src/logging.rs @@ -0,0 +1,52 @@ +use js_sys::JsString; +use screeps::game; +use web_sys::console; + +pub use log::LevelFilter::*; + +struct JsLog; +struct JsNotify; + +impl log::Log for JsLog { + fn enabled(&self, _: &log::Metadata<'_>) -> bool { + true + } + fn log(&self, record: &log::Record<'_>) { + console::log_1(&JsString::from(format!("{}", record.args()))); + } + fn flush(&self) {} +} +impl log::Log for JsNotify { + fn enabled(&self, _: &log::Metadata<'_>) -> bool { + true + } + fn log(&self, record: &log::Record<'_>) { + game::notify(&format!("{}", record.args()), None); + } + fn flush(&self) {} +} + +pub fn setup_logging(verbosity: log::LevelFilter) { + fern::Dispatch::new() + .level(verbosity) + .format(|out, message, record| { + out.finish(format_args!( + "({}) {}: {}", + record.level(), + record.target(), + message + )) + }) + .chain(Box::new(JsLog) as Box) + .chain( + fern::Dispatch::new() + .level(log::LevelFilter::Warn) + .format(|out, message, _record| { + let time = game::time(); + out.finish(format_args!("[{}] {}", time, message)) + }) + .chain(Box::new(JsNotify) as Box), + ) + .apply() + .expect("expected setup_logging to only ever be called once per instance"); +} diff --git a/src/memory.rs b/src/memory.rs new file mode 100644 index 0000000..443eb20 --- /dev/null +++ b/src/memory.rs @@ -0,0 +1,45 @@ +#![allow(dead_code)] + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use js_sys::JsString; + + + +structstruck::strike! { + #[strikethrough[derive(Serialize, Deserialize, Debug, Clone)]] +pub struct CreepMemory{ + pub _move: Option, + pub work: Option, +} +} + +structstruck::strike! { + #[strikethrough[derive(Serialize, Deserialize, Debug, Clone)]] + pub struct Memory { + pub creeps: HashMap +} +} + +impl Memory { + pub fn init_memory() -> Self { + let memory_jsstring = screeps::raw_memory::get(); + let memory: Memory = serde_json::from_str(&memory_jsstring.as_string().unwrap()).unwrap(); + return memory; + } + + pub fn write_memory(&self) { + screeps::raw_memory::set(&JsString::from(serde_json::to_string(&self).unwrap())); + } +}