[MIRROR] Add Verdigris, an in-tree rust module to cover our random performance-code needs. (#9246)

Co-authored-by: ShadowLarkens <shadowlarkens@gmail.com>
Co-authored-by: CHOMPStation2 <chompsation2@gmail.com>
This commit is contained in:
CHOMPStation2
2024-10-17 02:07:35 -07:00
committed by GitHub
parent e2819e7bed
commit 796265e126
16 changed files with 185 additions and 51 deletions

View File

@@ -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

View File

@@ -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()
..()

View File

@@ -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)

View File

@@ -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

BIN
libverdigris.so Normal file

Binary file not shown.

BIN
verdigris.dll Normal file

Binary file not shown.

14
verdigris/.gitignore vendored Normal file
View File

@@ -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

25
verdigris/Cargo.toml Normal file
View File

@@ -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"

5
verdigris/README.md Normal file
View File

@@ -0,0 +1,5 @@
# Verdigris
## An in-tree rust module for [VOREStation](https://github.com/VOREStation/VOREStation)
Currently implemented:
- Random map cellular automata

6
verdigris/build-linux.sh Normal file
View File

@@ -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"

View File

@@ -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"

3
verdigris/build.rs Normal file
View File

@@ -0,0 +1,3 @@
fn main() {
bosion::gather_to_env();
}

5
verdigris/src/lib.rs Normal file
View File

@@ -0,0 +1,5 @@
#[macro_use]
extern crate meowtonin;
pub mod random_map;
pub mod verdigris;

View File

@@ -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<Vec<ByondValue>> {
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<ByondValue> = 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<Vec<bool>> {
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)
}

View File

@@ -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() {}

View File

@@ -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"