diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 65391bbbfa..23bbeab67e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,6 +105,7 @@ jobs: sudo apt install gcc-multilib sudo apt install zlib1g-dev:i386 libssl-dev:i386 ldd librust_g.so + ldd libverdigris.so - name: Unit Tests run: | tools/ci/install_byond.sh diff --git a/code/__defines/verdigris/_verdigris.dm b/code/__defines/verdigris/_verdigris.dm new file mode 100644 index 0000000000..021506ac46 --- /dev/null +++ b/code/__defines/verdigris/_verdigris.dm @@ -0,0 +1,18 @@ +/* This comment bypasses grep checks */ /var/__verdigris + +/proc/__detect_verdigris() + if (world.system_type == UNIX) + return __verdigris = (fexists("./libverdigris.so") ? "./libverdigris.so" : "libverdigris") + else + return __verdigris = "verdigris" + +#define VERDIGRIS (__verdigris || __detect_verdigris()) +#define VERDIGRIS_CALL(name, args...) call_ext(VERDIGRIS, "byond:" + name)(args) + +/proc/verdigris_version() return VERDIGRIS_CALL("verdigris_version") +/proc/verdigris_features() return VERDIGRIS_CALL("verdigris_features") +/proc/verdigris_cleanup() return VERDIGRIS_CALL("cleanup") + +/world/New() + verdigris_cleanup() + ..() diff --git a/code/__defines/verdigris/random_map.dm b/code/__defines/verdigris/random_map.dm new file mode 100644 index 0000000000..5f8a237267 --- /dev/null +++ b/code/__defines/verdigris/random_map.dm @@ -0,0 +1,3 @@ +/proc/verdigris_generate_automata(limit_x, limit_y, iterations, initial_wall_cell) as /list + RETURN_TYPE(/list) + return VERDIGRIS_CALL("generate_automata", limit_x, limit_y, iterations, initial_wall_cell) diff --git a/code/modules/random_map/automata/automata.dm b/code/modules/random_map/automata/automata.dm index 50b53577c5..f10b9ad45d 100644 --- a/code/modules/random_map/automata/automata.dm +++ b/code/modules/random_map/automata/automata.dm @@ -10,58 +10,11 @@ var/cell_threshold = 5 // Cell becomes alive with this many live neighbors. // Automata-specific procs and processing. +/datum/random_map/automata/seed_map() + return // Do not seed, we use Verdigris for this now + /datum/random_map/automata/generate_map() - for(var/iter = 1 to iterations) - var/list/next_map[limit_x*limit_y] - var/count - var/is_not_border_left - var/is_not_border_right - var/ilim_u - var/ilim_d - var/bottom_lim = ((limit_y - 1) * limit_x) - - if (!islist(map)) - set_map_size() - - for (var/i in 1 to (limit_x * limit_y)) - count = 0 - - is_not_border_left = i != 1 && ((i - 1) % limit_x) - is_not_border_right = i % limit_x - - if (CELL_ALIVE(map[i])) // Center row. - ++count - if (is_not_border_left && CELL_ALIVE(map[i - 1])) - ++count - if (is_not_border_right && CELL_ALIVE(map[i + 1])) - ++count - - if (i > limit_x) // top row - ilim_u = i - limit_x - if (CELL_ALIVE(map[ilim_u])) - ++count - if (is_not_border_left && CELL_ALIVE(map[ilim_u - 1])) - ++count - if (is_not_border_right && CELL_ALIVE(map[ilim_u + 1])) - ++count - - if (i <= bottom_lim) // bottom row - ilim_d = i + limit_x - if (CELL_ALIVE(map[ilim_d])) - ++count - if (is_not_border_left && CELL_ALIVE(map[ilim_d - 1])) - ++count - if (is_not_border_right && CELL_ALIVE(map[ilim_d + 1])) - ++count - - if(count >= cell_threshold) - REVIVE_CELL(i, next_map) - else // Nope. Can't be alive. Kill it. - KILL_CELL(i, next_map) - - CHECK_TICK - - map = next_map + map = verdigris_generate_automata(limit_x, limit_y, iterations, initial_wall_cell) /datum/random_map/automata/get_additional_spawns(value, turf/T) return diff --git a/libverdigris.so b/libverdigris.so new file mode 100644 index 0000000000..4ca0f436aa Binary files /dev/null and b/libverdigris.so differ diff --git a/verdigris.dll b/verdigris.dll new file mode 100644 index 0000000000..2483bab46c Binary files /dev/null and b/verdigris.dll differ diff --git a/verdigris/.gitignore b/verdigris/.gitignore new file mode 100644 index 0000000000..6985cf1bd0 --- /dev/null +++ b/verdigris/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/verdigris/Cargo.toml b/verdigris/Cargo.toml new file mode 100644 index 0000000000..29fd9e041c --- /dev/null +++ b/verdigris/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "verdigris" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[profile.release] +debug = "full" +lto = "thin" +split-debuginfo = "packed" + +[profile.dev] +debug = "full" +opt-level = 0 + +[dependencies] +const_format = "0.2.33" +eyre = "0.6.12" +meowtonin = { git = "https://github.com/Absolucy/meowtonin.git" } +rand = "0.8.5" + +[build-dependencies] +bosion = "1.1.1" diff --git a/verdigris/README.md b/verdigris/README.md new file mode 100644 index 0000000000..202dc34001 --- /dev/null +++ b/verdigris/README.md @@ -0,0 +1,5 @@ +# Verdigris +## An in-tree rust module for [VOREStation](https://github.com/VOREStation/VOREStation) + +Currently implemented: + - Random map cellular automata diff --git a/verdigris/build-linux.sh b/verdigris/build-linux.sh new file mode 100644 index 0000000000..2003e433ed --- /dev/null +++ b/verdigris/build-linux.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +DIR="$(dirname "$0")" + +cargo build --release --target i686-unknown-linux-gnu +cp "target/i686-unknown-linux-gnu/release/libverdigris.so" "$DIR/../libverdigris.so" diff --git a/verdigris/build-windows.sh b/verdigris/build-windows.sh new file mode 100644 index 0000000000..f8daaa0ac6 --- /dev/null +++ b/verdigris/build-windows.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +DIR="$(dirname "$0")" + +cargo build --release --target i686-pc-windows-msvc +cp "target/i686-pc-windows-msvc/release/verdigris.dll" "$DIR/../verdigris.dll" diff --git a/verdigris/build.rs b/verdigris/build.rs new file mode 100644 index 0000000000..8c8770904b --- /dev/null +++ b/verdigris/build.rs @@ -0,0 +1,3 @@ +fn main() { + bosion::gather_to_env(); +} diff --git a/verdigris/src/lib.rs b/verdigris/src/lib.rs new file mode 100644 index 0000000000..7731e09554 --- /dev/null +++ b/verdigris/src/lib.rs @@ -0,0 +1,5 @@ +#[macro_use] +extern crate meowtonin; + +pub mod random_map; +pub mod verdigris; diff --git a/verdigris/src/random_map.rs b/verdigris/src/random_map.rs new file mode 100644 index 0000000000..0dc6451c80 --- /dev/null +++ b/verdigris/src/random_map.rs @@ -0,0 +1,72 @@ +use meowtonin::{value::ByondValue, ByondError, ByondResult}; +use rand::{distributions::Bernoulli, prelude::Distribution}; + +const CELL_THRESHOLD: usize = 5; + +#[byond_fn] +pub fn generate_automata( + limit_x: ByondValue, + limit_y: ByondValue, + iterations: ByondValue, + initial_wall_cell: ByondValue, +) -> ByondResult> { + let limit_x = limit_x.get_number()? as usize; + let limit_y = limit_y.get_number()? as usize; + let iterations = iterations.get_number()? as usize; + let initial_wall_cell = initial_wall_cell.get_number()? as usize; + + let mut map = seed_map(limit_x, limit_y, initial_wall_cell)?; + for _ in 1..iterations { + map = map + .iter() + .enumerate() + .map(|(i, _)| { + let mut count = 0; + + for x in [-1, 0, 1] { + for y in [-1, 0, 1] { + let idx = ((i as i32) + x + (y * (limit_y as i32))) as usize; + + if let Some(&value) = map.get(idx) { + let is_border_left = idx % limit_x == 0; + let is_border_right = (idx + 1) % limit_x == 0; + + if is_border_left && x == -1 { + continue; + } + if is_border_right && x == 1 { + continue; + } + + if value { + count += 1; + } + } + } + } + + count >= CELL_THRESHOLD + }) + .collect() + } + + let byond_list: Vec = map + .iter() + .map(|&b| ByondValue::new_num(if b { 1. } else { 0. })) + .collect(); + + Ok(byond_list) +} + +fn seed_map(limit_x: usize, limit_y: usize, percent_chance: usize) -> ByondResult> { + let mut map = vec![false; limit_x * limit_y]; + + let d = Bernoulli::new(percent_chance as f64 / 100.0).map_err(ByondError::boxed)?; + + map = map + .iter() + .map(|_| d.sample(&mut rand::thread_rng())) + .collect(); + + Ok(map) +} diff --git a/verdigris/src/verdigris.rs b/verdigris/src/verdigris.rs new file mode 100644 index 0000000000..f0dd35ba61 --- /dev/null +++ b/verdigris/src/verdigris.rs @@ -0,0 +1,21 @@ +//! Metadata functions +use const_format::formatcp as const_format; + +#[byond_fn] +pub fn verdigris_version() -> &'static str { + const_format!( + "{name} v{version} ({git_hash})", + name = env!("CARGO_PKG_NAME"), + version = env!("CARGO_PKG_VERSION"), + git_hash = env!("BOSION_GIT_COMMIT_SHORTHASH") + ) +} + +#[byond_fn] +pub fn verdigris_features() -> &'static str { + env!("BOSION_CRATE_FEATURES") +} + +/// Cleans up any resources used by Verdigris. +#[byond_fn] +pub fn cleanup() {} diff --git a/vorestation.dme b/vorestation.dme index 2f443abddd..fa0eb96b91 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -180,6 +180,8 @@ #include "code\__defines\traits\_traits.dm" #include "code\__defines\traits\declarations.dm" #include "code\__defines\traits\sources.dm" +#include "code\__defines\verdigris\_verdigris.dm" +#include "code\__defines\verdigris\random_map.dm" #include "code\_global_vars\_regexes.dm" #include "code\_global_vars\bitfields.dm" #include "code\_global_vars\configuration_ch.dm"