rpgx_wasm/map/
mod.rs

1pub mod effect;
2pub mod layer;
3pub mod mask;
4pub mod tile;
5
6use effect::WasmEffect;
7use layer::WasmLayer;
8use tile::WasmTile;
9
10use rpgx::prelude::Map;
11use wasm_bindgen::prelude::*;
12
13use crate::prelude::{WasmCoordinates, WasmDirection, WasmShape};
14
15#[wasm_bindgen(js_name = Map)]
16pub struct WasmMap {
17    inner: Map,
18}
19
20#[wasm_bindgen(js_class = Map)]
21impl WasmMap {
22    #[wasm_bindgen(constructor)]
23    pub fn new(name: String, layers: Vec<WasmLayer>, spawn: &WasmCoordinates) -> WasmMap {
24        let inner_layers = layers.into_iter().map(|l| l.into_inner()).collect();
25        WasmMap {
26            inner: Map::new(name, inner_layers, *spawn.inner()),
27        }
28    }
29
30    /* TODO #[wasm_bindgen(js_name = compose)]
31    pub fn compose(
32        name: String,
33        maps: Vec<JsValue>, // JS array of [WasmMap, WasmCoordinates]
34        layers: Vec<WasmLayer>,
35        spawn: WasmCoordinates,
36    ) -> Result<WasmMap, JsValue> {
37        let mut rust_maps: Vec<(Map, Coordinates)> = Vec::with_capacity(maps.len());
38
39        for js_val in maps {
40            // Convert JsValue into JS array (tuple expected)
41            let arr = js_val
42                .dyn_into::<Array>()
43                .map_err(|_| JsValue::from_str("Each map entry must be a tuple (array)"))?;
44
45            if arr.length() != 2 {
46                return Err(JsValue::from_str(
47                    "Each map entry must be a tuple of length 2",
48                ));
49            }
50
51            // Extract first element: WasmMap
52            let wasm_map = arr.get(0);
53
54            // Extract second element: WasmCoordinates
55            let wasm_coord = arr.get(1);
56
57            rust_maps.push((wasm_map, wasm_coord));
58        }
59
60        let inner_layers = layers.into_iter().map(|l| l.into_inner()).collect();
61
62        Ok(WasmMap {
63            inner: Map::compose(name, rust_maps, inner_layers, *spawn.inner()),
64        })
65    }*/
66
67    #[wasm_bindgen(getter)]
68    pub fn name(&self) -> String {
69        self.inner.name.clone()
70    }
71
72    #[wasm_bindgen(getter)]
73    pub fn spawn(&self) -> WasmCoordinates {
74        WasmCoordinates::from_inner(self.inner.spawn)
75    }
76
77    #[wasm_bindgen(getter)]
78    pub fn layers(&self) -> Vec<WasmLayer> {
79        self.inner
80            .layers
81            .iter()
82            .cloned()
83            .map(WasmLayer::from_inner)
84            .collect()
85    }
86
87    /// Load a new layer into the map.
88    #[wasm_bindgen(js_name = loadLayer)]
89    pub fn load_layer(&mut self, layer: WasmLayer) {
90        self.inner.load_layer(layer.into_inner());
91    }
92
93    /// Returns a JS object mapping layer names to WasmLayer instances.
94    #[wasm_bindgen(js_name = layersByName)]
95    pub fn layers_by_name(&self) -> js_sys::Object {
96        // Use the core Map method `layers_by_name` directly, which returns IndexMap<String, Layer>
97        let core_map = self.inner.layers_by_name();
98
99        let obj = js_sys::Object::new();
100        for (name, layer) in core_map.into_iter() {
101            let wasm_layer = WasmLayer::from_inner(layer);
102            js_sys::Reflect::set(&obj, &JsValue::from_str(&name), &JsValue::from(wasm_layer))
103                .unwrap_throw();
104        }
105        obj
106    }
107
108    /// Merge another map at a given offset; optionally update spawn.
109    #[wasm_bindgen(js_name = mergeAt)]
110    pub fn merge_at(
111        &mut self,
112        other: WasmMap,
113        top_left: WasmCoordinates,
114        spawn: Option<WasmCoordinates>,
115    ) {
116        let spawn_opt = spawn.map(|s| *s.inner());
117        self.inner
118            .merge_at(&other.inner, *top_left.inner(), spawn_opt);
119    }
120
121    /// Duplicate this map in a direction; optionally update spawn.
122    #[wasm_bindgen(js_name = duplicateToThe)]
123    pub fn duplicate_to_the(&mut self, direction: WasmDirection, spawn: Option<WasmCoordinates>) {
124        let spawn_opt = spawn.map(|s| *s.inner());
125        self.inner
126            .duplicate_to_the(direction.into_inner(), spawn_opt);
127    }
128
129    /// Returns true if movement is allowed at the given coordinate.
130    #[wasm_bindgen(js_name = moveAllowed)]
131    pub fn move_allowed(&self, target: &WasmCoordinates) -> bool {
132        self.inner.move_allowed(*target.inner())
133    }
134
135    /// Returns the bounding shape of the map.
136    #[wasm_bindgen(js_name = getShape)]
137    pub fn get_shape(&self) -> WasmShape {
138        WasmShape::from_inner(self.inner.get_shape())
139    }
140
141    /// Returns all tiles at a coordinate from all layers.
142    #[wasm_bindgen(js_name = getTilesAt)]
143    pub fn get_tiles_at(&self, pointer: &WasmCoordinates) -> Vec<WasmTile> {
144        self.inner
145            .get_tiles_at(*pointer.inner())
146            .into_iter()
147            .map(WasmTile::from_inner)
148            .collect()
149    }
150
151    /// Returns all effects at a coordinate from all layers.
152    #[wasm_bindgen(js_name = getEffectsAt)]
153    pub fn get_effects_at(&self, pointer: &WasmCoordinates) -> Vec<WasmEffect> {
154        self.inner
155            .get_effects_at(*pointer.inner())
156            .into_iter()
157            .map(WasmEffect::from_inner)
158            .collect()
159    }
160
161    /// Returns all action IDs at a coordinate from all layers.
162    #[wasm_bindgen(js_name = getActionsAt)]
163    pub fn get_actions_at(&self, pointer: &WasmCoordinates) -> Vec<u32> {
164        self.inner.get_actions_at(*pointer.inner())
165    }
166}
167
168impl WasmMap {
169    /// Consume and get the inner Map
170    pub fn into_inner(self) -> Map {
171        self.inner
172    }
173
174    /// Create from an inner Map directly
175    pub fn from_inner(inner: Map) -> WasmMap {
176        WasmMap { inner }
177    }
178}