mod random_level_worker;
mod random;
use rusqlite::{Connection, Result};
use serde::{Deserialize, Serialize};
use serde_json;
use snap;
use snap::raw::{Decoder, Encoder};
use std::collections::HashMap;
use std::fs;
#[derive(Serialize, Deserialize)]
pub struct JSLevel {
worldSeed: i64,
changedBlocks: HashMap<String,ChangedBlocks>,
worldSize: i32,
version: u8
}
impl JSLevel {
pub fn new (worldSeed: i64, changedBlocks: HashMap<String,ChangedBlocks>, worldSize: i32, version: u8) -> Self {
JSLevel { worldSeed, changedBlocks, worldSize, version }
}
}
#[derive(Serialize, Deserialize)]
pub struct ChangedBlocks {a: u8, bt: u8}
impl ChangedBlocks { pub fn new (a: u8, bt: u8) -> Self {ChangedBlocks { a, bt }}}
pub struct LocalStorage {
key: String,
utf16_length: i32,
conversion_type: i32,
compression_type: i32,
last_access_time: i32,
value: Vec<u8>
}
pub fn get_tile_map (world_size: i32, seed: i64) -> Vec<u8> {
let y: i32 = 64;
let level: HashMap<usize, u8> = random_level_worker::start_generation(world_size, seed); let mut tile_map: Vec<u8> = Vec::new();
for i in 0..world_size * y * world_size {
tile_map.push(level.get(&(i as usize)).copied().unwrap_or(0)); }
return tile_map
}
pub fn deserialize_saved_game (json_string: String) -> JSLevel {
let level: JSLevel = serde_json::from_str(&json_string).unwrap();
return level;
}
pub fn serialize_saved_game (level: JSLevel, tile_map: Vec<u8>, opt: u8) -> String {
let x: i32 = level.worldSize;
let y: i32 = 64;
let z: i32 = level.worldSize;
let tile_map1 = get_tile_map(level.worldSize, level.worldSeed);
let mut output: String = String::from("{");
output += &format!(r#""worldSeed":{},"#,level.worldSeed.to_string());
output += r#""changedBlocks":"#; output += "{";
let mut t: u8;
let mut t1: u8;
let mut a: u8;
let mut flag: bool = false;
for i in 0..y {
for j in 0..z {
for k in 0..x {
let mut flag1 = false;
let key: String = String::from(format!(r#""p{}_{}_{}":"#,k,i,j));
let bt: u8 = level.changedBlocks.get(&key).unwrap_or(&ChangedBlocks::new(1,255)).bt;
t = tile_map[((i*z*x) + (j*x) + k) as usize];
t1 = tile_map1[((i*z*x) + (j*x) + k) as usize];
if bt != 255 { t = bt }
if t == t1 { a = 0 } else { a = 1 }
if (opt == 2 && a == 1) || (opt == 1 && (bt != 255 || a == 1)) || opt == 0 { flag1 = true }
if flag1 {
output += &key;
output += "{";
output += &format!(r#""a":{},"bt":{}"#,a,t);
output += "},";
flag = true;
}
}
}
}
if flag {output.pop();} output += "},";
output += &format!{r#""worldSize":{},"#,level.worldSize}; output += &format!{r#""version":{}"#,level.version};
output += "}"; return output;
}
pub fn serialize_saved_game_from_seed (seed: i64, tile_map: Vec<u8>) -> String {
let world_size: i32 = ((tile_map.len()/64) as f64).sqrt() as i32;
let changed_blocks: HashMap<String, ChangedBlocks> = HashMap::new();
let level = JSLevel::new(seed, changed_blocks, world_size, 1);
return serialize_saved_game(level, tile_map, 2);
}
pub fn read_saved_game (file_path: String) -> Result<String> {
let conn: Connection = Connection::open(file_path)?;
let mut stmt = conn.prepare(
"SELECT * FROM data where key=?1;"
)?;
let entries = stmt.query_map(["savedGame"], |row| Ok(
LocalStorage {
key: row.get(0)?,
utf16_length: row.get(1)?,
conversion_type: row.get(2)?,
compression_type: row.get(3)?,
last_access_time: row.get(4)?,
value: row.get(5)?,
}
))?;
let mut compressed_saved_game: Vec<u8> = Vec::new();
let mut decompressed_length: i32 = 0;
for entry in entries {
let local: LocalStorage = entry.unwrap();
if local.key == "savedGame" {
compressed_saved_game = local.value;
decompressed_length = local.utf16_length;
break;
}
}
let mut decompressed: Vec<u8> = Vec::new();
for _ in 0..decompressed_length {
decompressed.push(0);
}
Decoder::decompress(&mut Decoder::new(), &compressed_saved_game, &mut decompressed).unwrap();
let mut characters: Vec<char> = Vec::new();
for ch in decompressed {
characters.push(ch as char)
}
Ok(characters.iter().collect())
}
pub fn write_saved_game (file_path: String, json_string: String) -> Result<()> {
let characters: Vec<char> = json_string.chars().collect();
let utf16_length: i32 = characters.len() as i32;
let mut decompressed: Vec<u8> = Vec::new();
for ch in characters {
decompressed.push(ch as u8);
}
let max_comp_length = snap::raw::max_compress_len(decompressed.len());
let mut compressed: Vec<u8> = Vec::new();
for _ in 0..max_comp_length {
compressed.push(0);
}
Encoder::compress(&mut Encoder::new(), &decompressed, & mut compressed).unwrap();
let mut b: u8 = 0;
while b == 0 {
b = compressed.pop().unwrap();
}
compressed.push(b);
let conn: Connection = Connection::open(file_path)?;
conn.execute(
"CREATE TABLE if not exists data (
key TEXT PRIMARY KEY,
utf16_length INTEGER NOT NULL,
conversion_type INTEGER NOT NULL,
compression_type INTEGER NOT NULL,
last_access_time INTEGER NOT NULL DEFAULT 0,
value BLOB NOT NULL)",
[]
)?;
let mut stmt = conn.prepare("INSERT OR REPLACE INTO data (key, utf16_length, conversion_type, compression_type, value) values (?1, ?2, ?3, ?4, ?5)" )?;
stmt.execute(("savedGame", utf16_length, 1, 1, compressed));
Ok(())
}
pub fn write_saved_game_command (file: String, json_string: String) -> String {
let open: String = String::from(r#"localStorage.setItem("savedGame", `"#); let close: String = String::from(r#"`)"#);
let output: String = String::from(format!{r"{open}{json_string}{close}"});
if file != "" {fs::write(file, output.clone()).expect("Error when writing to file")}
return output;
}