# HG changeset patch # User sheepluva # Date 1624486170 -7200 # Node ID 61da40b657fa097fa0e12ca221cbf5efcd683c18 # Parent 7472781493936f51eb22e79ee0e8767508e9889c hedgewars-engine (rust): ugly+slow impl for returning lib's previews (QTfrontend "compatible") diff -r 747278149393 -r 61da40b657fa rust/hedgewars-engine/Cargo.toml --- 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" diff -r 747278149393 -r 61da40b657fa rust/hedgewars-engine/src/main.rs --- 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 = 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); } }