Skip to content

Commit

Permalink
make_unique, better Tile indexing errors, coalescing dupe tiles
Browse files Browse the repository at this point in the history
  • Loading branch information
warriorstar-orion committed Nov 29, 2024
1 parent 7370d34 commit ef82409
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 13 deletions.
66 changes: 62 additions & 4 deletions src/dmm.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
extern crate dmm_tools;

use std::collections::btree_map;
use std::io;
use std::borrow::BorrowMut;
use std::collections::{btree_map, HashMap, HashSet};
use std::collections::btree_map::Keys as BTreeMapKeysIter;
use std::path::{Path, PathBuf};

use dmm_tools::dmm::{Key, Prefab};
use itertools::iproduct;
use pyo3::exceptions::{PyOSError, PyRuntimeError, PyValueError};
use pyo3::types::{PyAnyMethods, PyList, PyString, PyTuple};
Expand Down Expand Up @@ -113,6 +116,61 @@ impl CoordIterator {
}
}

impl Dmm {
pub fn generate_new_key(&mut self) -> Key {
let mut key: Key = Default::default();
while self.map.dictionary.contains_key(&key) {
key = key.next();
}

self.map.dictionary.insert(key, vec![]);
self.map.adjust_key_length();
key
}

pub fn coalesce_duplicate_tiles(&mut self) {
let mut coords_using_keys: HashMap<Key, Vec<dmm_tools::dmm::Coord3>> = HashMap::default();
let map = &mut self.map;

// First collect all known keys
map.iter_levels().for_each(|(z, zlvl)| {
zlvl.iter_top_down().for_each(|(coord, key)| {
coords_using_keys.entry(key).or_default().push(coord.z(z));
});
});

// Then find our prefab collisions, moving the collided keys over to the first one we found
// Then update the coords we know of and move them to the first key
let mut unused_keys: HashSet<Key> = HashSet::default();
let mut prefab_collisions: HashMap<&Vec<Prefab>, &Key> = HashMap::default();
for (key, prefabs) in &map.dictionary {
if prefab_collisions.contains_key(prefabs) {
unused_keys.insert(*key);
if let Some(coords) = coords_using_keys.get(key) {
for coord in coords {
let dim = map.grid.dim();
let raw = (coord.z as usize - 1, dim.1 - coord.y as usize, coord.x as usize - 1);
map.grid[raw] = *prefab_collisions[prefabs];
}
}
} else {
prefab_collisions.insert(prefabs, key);
}
}

for key in unused_keys {
map.dictionary.borrow_mut().remove_entry(&key);
}

map.adjust_key_length();
}

fn to_file(&mut self, path: &Path) -> io::Result<()> {
self.coalesce_duplicate_tiles();
self.map.to_file(path)
}
}

#[pymethods]
impl Dmm {
#[staticmethod]
Expand Down Expand Up @@ -147,13 +205,13 @@ impl Dmm {
})
}

fn save_to(&self, filename: &Bound<PyAny>) -> PyResult<()> {
fn save_to(&mut self, filename: &Bound<PyAny>) -> PyResult<()> {
if let Ok(path) = filename.extract::<std::path::PathBuf>() {
if let Ok(()) = self.map.to_file(&path) {
if let Ok(()) = self.to_file(&path) {
return Ok(());
}
} else if let Ok(pystr) = filename.downcast::<PyString>() {
if let Ok(()) = self.map.to_file(Path::new(&pystr.to_string())) {
if let Ok(()) = self.to_file(Path::new(&pystr.to_string())) {
return Ok(());
}
}
Expand Down
52 changes: 43 additions & 9 deletions src/tile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ extern crate dmm_tools;

use dmm_tools::dmm::Prefab;
use pyo3::conversion::ToPyObject;
use pyo3::exceptions::{PyRuntimeError, PyValueError};
use pyo3::exceptions::{PyIndexError, PyKeyError, PyRuntimeError, PyValueError};
use pyo3::types::{PyAnyMethods, PyDict, PyList, PyString};
use pyo3::{
pyclass, pymethods, Bound, IntoPy, Py, PyAny, PyErr, PyObject, PyResult, Python,
Expand Down Expand Up @@ -195,21 +195,31 @@ impl Tile {
Address::Coords(c) => map[c],
};
let prefabs = &map.dictionary[&key];
if index as usize >= prefabs.len() {
return Err(PyIndexError::new_err("list index out of range"));
}

let binding = prefabs[index as usize].path.clone();
let s = binding.as_str();
path::Path::new(s)
}

pub fn prefab_var(&self, index: i32, name: String, py: Python<'_>) -> PyObject {
pub fn prefab_var(&self, index: i32, name: String, py: Python<'_>) -> PyResult<PyObject> {
let map = &self.dmm.downcast_bound::<Dmm>(py).unwrap().borrow().map;
let key = match self.addr {
Address::Key(k) => k,
Address::Coords(c) => map[c],
};
let prefabs = &map.dictionary[&key];
if index as usize >= prefabs.len() {
return Err(PyIndexError::new_err("list index out of range"));
}
let prefab = &prefabs[index as usize];
if !prefab.vars.contains_key(&name) {
return Err(PyKeyError::new_err(format!("no varedit {}", name)));
}

constant_to_python_value(prefabs[index as usize].vars.get(&name).unwrap())
Ok(constant_to_python_value(prefab.vars.get(&name).unwrap()))
}

#[pyo3(signature = (index, name, default=None))]
Expand All @@ -219,39 +229,46 @@ impl Tile {
name: String,
default: Option<&Bound<PyAny>>,
py: Python<'_>,
) -> PyObject {
) -> PyResult<PyObject> {
let map = &self.dmm.downcast_bound::<Dmm>(py).unwrap().borrow().map;
let key = match self.addr {
Address::Key(k) => k,
Address::Coords(c) => map[c],
};
let prefabs = &map.dictionary[&key];
if index as usize >= prefabs.len() {
return Err(PyIndexError::new_err("list index out of range"));
}

let vars = &prefabs[index as usize].vars;
if vars.contains_key(&name) {
return constant_to_python_value(vars.get(&name).unwrap());
return Ok(constant_to_python_value(vars.get(&name).unwrap()));
}

if let Some(t) = default {
return t.into_py(py);
return Ok(t.into_py(py));
}

py.None()
Ok(py.None())
}

pub fn prefab_vars(&self, index: i32, py: Python<'_>) -> Vec<String> {
pub fn prefab_vars(&self, index: i32, py: Python<'_>) -> PyResult<Vec<String>> {
let map = &self.dmm.downcast_bound::<Dmm>(py).unwrap().borrow().map;
let mut vec = Vec::new();
let key = match self.addr {
Address::Key(k) => k,
Address::Coords(c) => map[c],
};
let prefabs = &map.dictionary[&key];
if index as usize >= prefabs.len() {
return Err(PyIndexError::new_err("list index out of range"));
}

prefabs[index as usize].vars.iter().for_each(|(name, _)| {
vec.push(name.clone());
});

vec
Ok(vec)
}

pub fn set_prefab_var(
Expand Down Expand Up @@ -321,6 +338,23 @@ impl Tile {
)))
}

fn make_unique(&mut self, py: Python<'_>) -> PyResult<()> {
let map = &mut self.dmm.downcast_bound::<Dmm>(py).unwrap().borrow_mut().map;
let dmm = self.dmm.downcast_bound::<Dmm>(py).unwrap();
match self.addr {
Address::Key(_) => {
return Err(PyErr::new::<PyRuntimeError, &str>("can only make Tiles from DMM#tiledef(x, y, z) unique"));
},
Address::Coords(c) => {
let new_key = dmm.borrow_mut().generate_new_key();
let dim = map.grid.dim();
map.dictionary.insert(new_key, map.dictionary[&map[c]].clone());
map.grid[(c.z as usize - 1, dim.1 - c.y as usize, c.x as usize - 1)] = new_key;
},
}
Ok(())
}

fn __repr__(&self, py: Python<'_>) -> PyResult<String> {
let map = &self.dmm.downcast_bound::<Dmm>(py).unwrap().borrow().map;
Ok(format!(
Expand Down

0 comments on commit ef82409

Please sign in to comment.