mcpi_api/
lib.rs

1//! # MCPI API
2//! `mcpi_api` is a wrapper for the Minecraft Pi Edition API handling parsing and other aspects for you.
3use std::io::prelude::*;
4use std::net::TcpStream;
5use std::io::BufReader;
6use std::cmp::{min, max};
7
8#[cfg(test)]
9mod tests {
10
11    #[test]
12    fn development_test() {
13    }
14}
15
16///Struct containing functions and a Connection struct.
17pub struct Minecraft {
18    conn:Connection
19}
20
21struct Connection {
22    stream:TcpStream
23}
24
25///Struct containing functions and a Connection struct.
26pub struct Player<'a> {
27    conn:&'a mut Connection
28}
29
30pub struct Entity<'a> {
31    conn:&'a mut Connection
32}
33
34///Struct used to specify tile positions.
35#[derive(Debug)]
36pub struct TileVec3 {
37    pub x:i32,
38    pub y:i32,
39    pub z:i32
40}
41
42///Struct used to specify entity positions.
43#[derive(Debug)]
44pub struct Vec3 {
45    pub x:f32,
46    pub y:f32,
47    pub z:f32
48}
49
50impl TileVec3 {
51    /// Function to generate a TileVec3 from 3 i32's
52    pub fn from(x:i32, y:i32, z:i32) -> TileVec3 {
53        TileVec3 {
54            x,
55            y,
56            z
57        }
58    }
59    ///Function to generate a TileVec3 from a Vec<i32>
60    /// # Panics
61    /// This function panics if the vector contains less then 3 elements
62    pub fn from_vector(vec:&Vec<i32>) -> TileVec3 {
63        TileVec3 {
64            x: vec[0],
65            y: vec[1],
66            z: vec[2]
67        }
68    }
69}
70
71impl Vec3 {
72    ///Function to generate a Vec3 from 3 f32's
73    pub fn from(x:f32, y:f32, z:f32) -> Vec3 {
74        Vec3 {
75            x,
76            y,
77            z
78        }
79    }
80    ///Function to generate a Vec3 from a Vec<f32>
81    /// # Panics
82    /// This function panics if the vector contains less then 3 elements
83    pub fn from_vector(vec:&Vec<f32>) -> Vec3 {
84        Vec3{
85            x: vec[0],
86            y: vec[1],
87            z: vec[2]
88        }
89    }
90}
91
92impl Connection {
93    pub fn send(&mut self, msg:&str) {
94        self.stream.write(&format!("{}\n", msg).as_bytes()).expect("Failed to send! Is MCPI still running?");
95    }
96
97    pub fn receive(&mut self) -> String {
98        let mut reader = BufReader::new(&self.stream);
99        let mut line = String::new();
100        reader.read_line(&mut line).expect("Failed to receive! Is MCPI still running?");
101        line.replace('\n',"")
102    }
103
104    pub fn send_receive(&mut self, msg:&str) -> String {
105        self.send(msg);
106        self.receive()
107    }
108}
109///# Panics
110/// All functions implemented on the Minecraft struct might panic if the API is not running anymore or packages fail to send.
111/// This might change in a 0.2.0 version of this crate
112impl Minecraft {
113    ///Post a message to the chat
114    pub fn post_to_chat(&mut self, msg:&str) {
115        self.conn.send(&format!("chat.post({})", msg));
116    }
117    ///Get the block at a specific position
118    pub fn get_block(&mut self, pos:&TileVec3) -> u8 {
119        self.conn.send_receive(&format!("world.getBlock({},{},{})", pos.x, pos.y, pos.z)).parse::<u8>().unwrap()
120    }
121    ///Get the block with data at a specific position
122    pub fn get_block_with_data(&mut self, pos:&TileVec3) -> Vec<u8> {
123        self.conn.send_receive(&format!("world.getBlockWithData({},{},{})", pos.x, pos.y, pos.z)).split(',').map(|s| s.parse()).collect::<Result<Vec<u8>, _>>().unwrap()
124    }
125    ///Get a array of blocks contained in the specified area
126    pub fn get_blocks(&mut self, pos1:&TileVec3, pos2:&TileVec3) -> Vec<u8> {
127        let mut results:Vec<u8> = vec![];
128        for y in min(pos1.y, pos2.y)..max(pos1.y, pos2.y)+1 {
129            for x in min(pos1.x, pos2.x)..max(pos1.x, pos2.x)+1 {
130                for z in min(pos1.z, pos2.z)..max(pos1.z, pos2.z) + 1 {
131                    results.push(self.conn.send_receive(&format!("world.getBlock({},{},{})", x,y,z)).parse::<u8>().unwrap());
132                }
133            }
134        }
135        results
136    }
137    ///Get a array of blocks with their data contained in the specified area
138    pub fn get_blocks_with_data(&mut self, pos1:&TileVec3, pos2:&TileVec3) -> Vec<Vec<u8>> {
139        let mut results:Vec<Vec<u8>> = vec![];
140        for y in min(pos1.y, pos2.y)..max(pos1.y, pos2.y)+1 {
141            for x in min(pos1.x, pos2.x)..max(pos1.x, pos2.x)+1 {
142                for z in min(pos1.z, pos2.z)..max(pos1.z, pos2.z) + 1 {
143                    results.push(self.conn.send_receive(&format!("world.getBlockWithData({},{},{})", x,y,z)).split(',').map(|s| s.parse()).collect::<Result<Vec<u8>, _>>().unwrap());
144                }
145            }
146        }
147        results
148    }
149    ///Set a block at a specific position
150    pub fn set_block(&mut self, pos:&TileVec3, blocktype:u8, blockdata:u8) {
151        self.conn.send(&format!("world.setBlock({},{},{},{},{})", pos.x, pos.y, pos.z, blocktype, blockdata));
152    }
153    ///Fill the specified area with the a block
154    pub fn set_blocks(&mut self, pos1:&TileVec3, pos2:&TileVec3, blocktype:u8, blockdata:u8) {
155        self.conn.send(&format!("world.setBlocks({},{},{},{},{},{},{},{})", pos1.x,pos1.y,pos1.z,pos2.x,pos2.y,pos2.z,blocktype,blockdata));
156    }
157    ///Get the highest point at the specified position
158    pub fn get_height(&mut self, pos:&TileVec3) -> i8 {
159        self.conn.send_receive(&format!("world.getHeight({},{})", pos.x,pos.z)).parse::<i8>().unwrap()
160    }
161    ///Save the current world state as a checkpoint
162    pub fn save_checkpoint(&mut self) {
163        self.conn.send("world.checkpoint.save()");
164    }
165    ///Restore a previously saved world state
166    pub fn restore_checkpoint(&mut self) {
167        self.conn.send("world.checkpoint.restore()");
168    }
169    ///Set a world setting to true or false.
170    /// Available settings: "world_immutable", "nametags_visible"
171    pub fn setting(&mut self, setting:&str, status:bool) {
172        self.conn.send(&format!("world.setting({},{})",setting,if status == true {1} else {0}));
173    }
174    ///Get a list of entity ids for all online players
175    pub fn get_player_entity_ids(&mut self) -> Vec<u16> {
176        self.conn.send_receive(&format!("world.getPlayerIds()")).split("|").map(|s| s.parse()).collect::<Result<Vec<u16>, _>>().unwrap()
177    }
178    ///Get a instance of the Player struct containing player related functions
179    pub fn player(&mut self) -> Player {
180        Player {
181            conn: &mut self.conn
182        }
183    }
184
185    pub fn entity(&mut self) -> Entity {
186        Entity {
187            conn: &mut self.conn
188        }
189    }
190}
191///# Panics
192/// All functions implemented on the Player struct might panic if the API is not running anymore or packages fail to send.
193/// This might change in a 0.2.0 version of this crate
194impl Player<'_> {
195    ///Get the position of the main player
196     pub fn get_pos(&mut self) -> Vec3 {
197        Vec3::from_vector(&self.conn.send_receive(&format!("player.getPos()")).split(',').map(|s| s.parse()).collect::<Result<Vec<f32>, _>>().unwrap())
198    }
199    ///Set the position of the main player
200    pub fn set_pos(&mut self, pos:&Vec3) {
201        self.conn.send(&format!("player.setPos({},{},{})", pos.x, pos.y, pos.z));
202    }
203    ///Get the tile position of the main player
204    pub fn get_tile_pos(&mut self) -> TileVec3 {
205        let vec:Vec<i32> = self.conn.send_receive(&format!("player.getTile()")).split(',').map(|s| s.parse()).collect::<Result<Vec<i32>, _>>().unwrap();
206        TileVec3::from_vector(&vec)
207    }
208    ///Set the tile position of the main player
209    pub fn set_tile_pos(&mut self, pos:&TileVec3) {
210        self.conn.send(&format!("player.setTile({},{},{})", pos.x, pos.y, pos.z))
211    }
212    ///Set a setting for the main player
213    /// Available settings: "autojump"
214    pub fn setting(&mut self, setting:&str, status:bool) {
215        self.conn.send(&format!("player.setting({},{})",setting,if status {1} else {0}));
216    }
217}
218
219impl Entity<'_> {
220    ///Get the position of a player entity
221    pub fn get_pos(&mut self, id:u16) -> Vec3 {
222        Vec3::from_vector(&self.conn.send_receive(&format!("entity.getPos({})", id)).split(',').map(|s| s.parse()).collect::<Result<Vec<f32>, _>>().unwrap())
223    }
224    ///Set the position of a player entity
225    pub fn set_pos(&mut self, id:u16, pos:&Vec3) {
226        self.conn.send(&format!("entity.setPos({},{},{},{})", id, pos.x, pos.y, pos.z));
227    }
228    ///Get the tile position of a player entity
229    pub fn get_tile_pos(&mut self, id:u16) -> TileVec3 {
230        let vec:Vec<i32> = self.conn.send_receive(&format!("entity.getTile({})", id)).split(',').map(|s| s.parse()).collect::<Result<Vec<i32>, _>>().unwrap();
231        TileVec3::from_vector(&vec)
232    }
233    ///Set the tile position of a player entity
234    pub fn set_tile_pos(&mut self, id:u16, pos:&TileVec3) {
235        self.conn.send(&format!("entity.setTile({},{},{},{})",id, pos.x, pos.y, pos.z))
236    }
237}
238
239///Function to create a Minecraft struct.
240/// Takes a IP adress and a port as arguments.
241/// # Examples
242/// ```
243/// use mcpi_api::create;
244/// let mut  mc = create("localhost:4711");
245/// mc.post_to_chat("Hello World!")
246/// ```
247/// # Panics
248/// This function panics if binding to the adress fails.
249pub fn create(adress:&str) -> Minecraft {
250    let stream = TcpStream::connect(adress);
251    match stream {
252        Ok(_) => {}
253        Err(_) => {
254            panic!("Failed to connect to the API! Is Minecraft running?")
255        }
256    }
257    Minecraft {
258        conn: Connection {
259            stream: stream.unwrap()
260        }
261    }
262}