hedgewars-engine (rust): ugly+slow impl for returning lib's previews (QTfrontend "compatible")
authorsheepluva
Thu, 24 Jun 2021 00:09:30 +0200
changeset 15827 61da40b657fa
parent 15826 747278149393
child 15828 36816af30583
hedgewars-engine (rust): ugly+slow impl for returning lib's previews (QTfrontend "compatible")
rust/hedgewars-engine/Cargo.toml
rust/hedgewars-engine/src/main.rs
--- a/rust/hedgewars-engine/Cargo.toml	Wed Jun 23 23:41:51 2021 +0200
+++ b/rust/hedgewars-engine/Cargo.toml	Thu Jun 24 00:09:30 2021 +0200
@@ -7,4 +7,5 @@
 [dependencies]
 lib-hedgewars-engine = { path = "../lib-hedgewars-engine" }
 libloading = "0.5.0"
-
+getopts = "0.2"
+image = "0.23"
--- a/rust/hedgewars-engine/src/main.rs	Wed Jun 23 23:41:51 2021 +0200
+++ b/rust/hedgewars-engine/src/main.rs	Thu Jun 24 00:09:30 2021 +0200
@@ -2,13 +2,32 @@
 
 use libloading::{Library, Symbol};
 use std::ops::Deref;
+use std::env;
+use getopts::Options;
+use std::io::prelude::*;
+use std::io::{self, Read};
+use std::net::{Shutdown, TcpStream};
+use image::{GrayImage, imageops};
 
 struct EngineInstance {}
 
 struct Engine<'a> {
     protocol_version: Symbol<'a, unsafe fn() -> u32>,
     start_engine: Symbol<'a, unsafe fn() -> *mut EngineInstance>,
+    generate_preview: Symbol<'a, unsafe fn(engine_state: &mut EngineInstance, preview: &mut PreviewInfo)>,
+    dispose_preview: Symbol<'a, unsafe fn(engine_state: &mut EngineInstance, preview: &mut PreviewInfo)>,
     cleanup: Symbol<'a, unsafe fn(engine_state: *mut EngineInstance)>,
+    send_ipc: Symbol<'a, unsafe fn(engine_state: &mut EngineInstance, buf: *const u8, size: usize)>,
+    read_ipc: Symbol<'a, unsafe fn(engine_state: &mut EngineInstance, buf: *mut u8, size: usize) -> usize>,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct PreviewInfo {
+  width: u32,
+  height: u32,
+  hedgehogs_number: u8,
+  land: *const u8,
 }
 
 fn main() {
@@ -18,9 +37,99 @@
         let engine = Engine {
             protocol_version: hwlib.get(b"hedgewars_engine_protocol_version").unwrap(),
             start_engine: hwlib.get(b"start_engine").unwrap(),
+            generate_preview: hwlib.get(b"generate_preview").unwrap(),
+            dispose_preview: hwlib.get(b"dispose_preview").unwrap(),
             cleanup: hwlib.get(b"cleanup").unwrap(),
+            send_ipc: hwlib.get(b"send_ipc").unwrap(),
+            read_ipc: hwlib.get(b"read_ipc").unwrap(),
         };
 
         println!("Hedgewars engine, protocol version {}", engine.protocol_version.deref()());
+
+        let args: Vec<String> = env::args().collect();
+
+        let mut opts = getopts::Options::new();
+        opts.optflag("", "internal", "[internal]");
+        opts.optflag("", "landpreview", "[internal]");
+        opts.optflag("", "recorder", "[internal]");
+        opts.optopt("", "port", "[internal]", "PORT");
+        opts.optopt("", "user-prefix", "Set the path to the custom data folder to find game content", "PATH_TO_FOLDER");
+        opts.optopt("", "prefix", "Set the path to the system game data folder", "PATH_TO_FOLDER");
+
+        let matches = match opts.parse(&args[1..]) {
+            Ok(m) => { m }
+            Err(f) => { panic!(f.to_string()) }
+        };
+
+        let engine_state = &mut *engine.start_engine.deref()();
+
+        let port: String = matches.opt_str("port").unwrap();
+
+        println!("PORT: {}", port);
+
+        if matches.opt_present("landpreview") {
+
+            let mut stream = TcpStream::connect(format!("127.0.0.1:{}", port)).expect("Failed to connect to IPC port. Feelsbadman.");
+
+            //stream.write(b"\x01C").unwrap(); // config
+            //stream.write(b"\x01?").unwrap(); // ping
+
+            let mut buf = [0;1];
+            loop {
+                let bytes_read = stream.read(&mut buf).unwrap();
+                if bytes_read == 0 {
+                    break;
+                }
+                engine.send_ipc.deref()(engine_state, &buf[0], buf.len());
+                // this looks like length 1 is being announced
+                if buf[0] == 1 {
+                    let bytes_read = stream.read(&mut buf).unwrap();
+                    if bytes_read == 0 {
+                        break;
+                    }
+                    if buf[0] == 33 {
+                        println!("Ping? Pong!");
+                        break;
+                    }
+                }
+            };
+
+            let preview_info = &mut PreviewInfo {
+                width: 0,
+                height: 0,
+                hedgehogs_number: 0,
+                land: std::ptr::null(),
+            };
+
+            engine.generate_preview.deref()(engine_state, preview_info);
+
+            println!("Sending preview...");
+
+            //println!("Preview: w = {}, h = {}, n = {}", preview_info.width, preview_info.height, preview_info.hedgehogs_number);
+
+            let land_size: usize = (preview_info.width * preview_info.height) as usize;
+
+            let land_array: &[u8] = std::slice::from_raw_parts(preview_info.land, land_size);
+
+            let raw_image = GrayImage::from_raw(preview_info.width, preview_info.height, land_array.to_vec()).unwrap();
+
+            const PREVIEW_WIDTH: u32 = 256;
+            const PREVIEW_HEIGHT: u32 = 128;
+
+            let preview_image = imageops::resize(&raw_image, PREVIEW_WIDTH, PREVIEW_HEIGHT, imageops::FilterType::Triangle);
+
+            stream.write(preview_image.as_raw()).unwrap();
+            stream.flush().unwrap();
+            stream.write(&[preview_info.hedgehogs_number]).unwrap();
+            stream.flush().unwrap();
+
+            println!("Preview sent, disconnect");
+
+            stream.shutdown(Shutdown::Both).expect("IPC shutdown call failed");
+
+            engine.dispose_preview.deref()(engine_state, preview_info);
+        }
+
+        engine.cleanup.deref()(engine_state);
     }
 }