1 extern crate libloading; |
1 extern crate libloading; |
2 |
2 |
3 use libloading::{Library, Symbol}; |
3 use libloading::{Library, Symbol}; |
4 use std::ops::Deref; |
4 use std::ops::Deref; |
|
5 use std::env; |
|
6 use getopts::Options; |
|
7 use std::io::prelude::*; |
|
8 use std::io::{self, Read}; |
|
9 use std::net::{Shutdown, TcpStream}; |
|
10 use image::{GrayImage, imageops}; |
5 |
11 |
6 struct EngineInstance {} |
12 struct EngineInstance {} |
7 |
13 |
8 struct Engine<'a> { |
14 struct Engine<'a> { |
9 protocol_version: Symbol<'a, unsafe fn() -> u32>, |
15 protocol_version: Symbol<'a, unsafe fn() -> u32>, |
10 start_engine: Symbol<'a, unsafe fn() -> *mut EngineInstance>, |
16 start_engine: Symbol<'a, unsafe fn() -> *mut EngineInstance>, |
|
17 generate_preview: Symbol<'a, unsafe fn(engine_state: &mut EngineInstance, preview: &mut PreviewInfo)>, |
|
18 dispose_preview: Symbol<'a, unsafe fn(engine_state: &mut EngineInstance, preview: &mut PreviewInfo)>, |
11 cleanup: Symbol<'a, unsafe fn(engine_state: *mut EngineInstance)>, |
19 cleanup: Symbol<'a, unsafe fn(engine_state: *mut EngineInstance)>, |
|
20 send_ipc: Symbol<'a, unsafe fn(engine_state: &mut EngineInstance, buf: *const u8, size: usize)>, |
|
21 read_ipc: Symbol<'a, unsafe fn(engine_state: &mut EngineInstance, buf: *mut u8, size: usize) -> usize>, |
|
22 } |
|
23 |
|
24 #[repr(C)] |
|
25 #[derive(Copy, Clone)] |
|
26 struct PreviewInfo { |
|
27 width: u32, |
|
28 height: u32, |
|
29 hedgehogs_number: u8, |
|
30 land: *const u8, |
12 } |
31 } |
13 |
32 |
14 fn main() { |
33 fn main() { |
15 let hwlib = Library::new("libhedgewars_engine.so").unwrap(); |
34 let hwlib = Library::new("libhedgewars_engine.so").unwrap(); |
16 |
35 |
17 unsafe { |
36 unsafe { |
18 let engine = Engine { |
37 let engine = Engine { |
19 protocol_version: hwlib.get(b"hedgewars_engine_protocol_version").unwrap(), |
38 protocol_version: hwlib.get(b"hedgewars_engine_protocol_version").unwrap(), |
20 start_engine: hwlib.get(b"start_engine").unwrap(), |
39 start_engine: hwlib.get(b"start_engine").unwrap(), |
|
40 generate_preview: hwlib.get(b"generate_preview").unwrap(), |
|
41 dispose_preview: hwlib.get(b"dispose_preview").unwrap(), |
21 cleanup: hwlib.get(b"cleanup").unwrap(), |
42 cleanup: hwlib.get(b"cleanup").unwrap(), |
|
43 send_ipc: hwlib.get(b"send_ipc").unwrap(), |
|
44 read_ipc: hwlib.get(b"read_ipc").unwrap(), |
22 }; |
45 }; |
23 |
46 |
24 println!("Hedgewars engine, protocol version {}", engine.protocol_version.deref()()); |
47 println!("Hedgewars engine, protocol version {}", engine.protocol_version.deref()()); |
|
48 |
|
49 let args: Vec<String> = env::args().collect(); |
|
50 |
|
51 let mut opts = getopts::Options::new(); |
|
52 opts.optflag("", "internal", "[internal]"); |
|
53 opts.optflag("", "landpreview", "[internal]"); |
|
54 opts.optflag("", "recorder", "[internal]"); |
|
55 opts.optopt("", "port", "[internal]", "PORT"); |
|
56 opts.optopt("", "user-prefix", "Set the path to the custom data folder to find game content", "PATH_TO_FOLDER"); |
|
57 opts.optopt("", "prefix", "Set the path to the system game data folder", "PATH_TO_FOLDER"); |
|
58 |
|
59 let matches = match opts.parse(&args[1..]) { |
|
60 Ok(m) => { m } |
|
61 Err(f) => { panic!(f.to_string()) } |
|
62 }; |
|
63 |
|
64 let engine_state = &mut *engine.start_engine.deref()(); |
|
65 |
|
66 let port: String = matches.opt_str("port").unwrap(); |
|
67 |
|
68 println!("PORT: {}", port); |
|
69 |
|
70 if matches.opt_present("landpreview") { |
|
71 |
|
72 let mut stream = TcpStream::connect(format!("127.0.0.1:{}", port)).expect("Failed to connect to IPC port. Feelsbadman."); |
|
73 |
|
74 //stream.write(b"\x01C").unwrap(); // config |
|
75 //stream.write(b"\x01?").unwrap(); // ping |
|
76 |
|
77 let mut buf = [0;1]; |
|
78 loop { |
|
79 let bytes_read = stream.read(&mut buf).unwrap(); |
|
80 if bytes_read == 0 { |
|
81 break; |
|
82 } |
|
83 engine.send_ipc.deref()(engine_state, &buf[0], buf.len()); |
|
84 // this looks like length 1 is being announced |
|
85 if buf[0] == 1 { |
|
86 let bytes_read = stream.read(&mut buf).unwrap(); |
|
87 if bytes_read == 0 { |
|
88 break; |
|
89 } |
|
90 if buf[0] == 33 { |
|
91 println!("Ping? Pong!"); |
|
92 break; |
|
93 } |
|
94 } |
|
95 }; |
|
96 |
|
97 let preview_info = &mut PreviewInfo { |
|
98 width: 0, |
|
99 height: 0, |
|
100 hedgehogs_number: 0, |
|
101 land: std::ptr::null(), |
|
102 }; |
|
103 |
|
104 engine.generate_preview.deref()(engine_state, preview_info); |
|
105 |
|
106 println!("Sending preview..."); |
|
107 |
|
108 //println!("Preview: w = {}, h = {}, n = {}", preview_info.width, preview_info.height, preview_info.hedgehogs_number); |
|
109 |
|
110 let land_size: usize = (preview_info.width * preview_info.height) as usize; |
|
111 |
|
112 let land_array: &[u8] = std::slice::from_raw_parts(preview_info.land, land_size); |
|
113 |
|
114 let raw_image = GrayImage::from_raw(preview_info.width, preview_info.height, land_array.to_vec()).unwrap(); |
|
115 |
|
116 const PREVIEW_WIDTH: u32 = 256; |
|
117 const PREVIEW_HEIGHT: u32 = 128; |
|
118 |
|
119 let preview_image = imageops::resize(&raw_image, PREVIEW_WIDTH, PREVIEW_HEIGHT, imageops::FilterType::Triangle); |
|
120 |
|
121 stream.write(preview_image.as_raw()).unwrap(); |
|
122 stream.flush().unwrap(); |
|
123 stream.write(&[preview_info.hedgehogs_number]).unwrap(); |
|
124 stream.flush().unwrap(); |
|
125 |
|
126 println!("Preview sent, disconnect"); |
|
127 |
|
128 stream.shutdown(Shutdown::Both).expect("IPC shutdown call failed"); |
|
129 |
|
130 engine.dispose_preview.deref()(engine_state, preview_info); |
|
131 } |
|
132 |
|
133 engine.cleanup.deref()(engine_state); |
25 } |
134 } |
26 } |
135 } |