client persistence

This commit is contained in:
core 2025-03-09 18:38:09 -04:00
parent 164eb4ba43
commit b011b13180
Signed by: core
GPG key ID: FDBF740DADDCEECF
10 changed files with 200 additions and 38 deletions

50
Cargo.lock generated
View file

@ -23,6 +23,10 @@ name = "accesskit"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3d3b8f9bae46a948369bc4a03e815d4ed6d616bd00de4051133a5019dc31c5a"
dependencies = [
"enumn",
"serde",
]
[[package]]
name = "accesskit_atspi_common"
@ -138,7 +142,7 @@ dependencies = [
"actix-service",
"actix-utils",
"ahash",
"base64",
"base64 0.22.1",
"bitflags 2.9.0",
"brotli",
"bytes",
@ -317,6 +321,7 @@ dependencies = [
"cfg-if",
"getrandom",
"once_cell",
"serde",
"version_check",
"zerocopy",
]
@ -708,6 +713,12 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.1"
@ -1221,6 +1232,7 @@ checksum = "bc4feb366740ded31a004a0e4452fbf84e80ef432ecf8314c485210229672fd1"
dependencies = [
"bytemuck",
"emath",
"serde",
]
[[package]]
@ -1239,6 +1251,7 @@ dependencies = [
"glow",
"glutin",
"glutin-winit",
"home",
"image",
"js-sys",
"log",
@ -1249,6 +1262,8 @@ dependencies = [
"percent-encoding",
"profiling",
"raw-window-handle",
"ron",
"serde",
"static_assertions",
"wasm-bindgen",
"wasm-bindgen-futures",
@ -1273,6 +1288,8 @@ dependencies = [
"log",
"nohash-hasher",
"profiling",
"ron",
"serde",
]
[[package]]
@ -1309,6 +1326,7 @@ dependencies = [
"log",
"profiling",
"raw-window-handle",
"serde",
"smithay-clipboard",
"web-time",
"webbrowser",
@ -1360,6 +1378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b"
dependencies = [
"bytemuck",
"serde",
]
[[package]]
@ -1404,6 +1423,17 @@ dependencies = [
"syn",
]
[[package]]
name = "enumn"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "epaint"
version = "0.31.1"
@ -1420,6 +1450,7 @@ dependencies = [
"nohash-hasher",
"parking_lot",
"profiling",
"serde",
]
[[package]]
@ -3404,7 +3435,7 @@ version = "0.12.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
dependencies = [
"base64",
"base64 0.22.1",
"bytes",
"encoding_rs",
"futures-core",
@ -3462,6 +3493,18 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "ron"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64 0.21.7",
"bitflags 2.9.0",
"serde",
"serde_derive",
]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@ -4382,7 +4425,7 @@ version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a"
dependencies = [
"base64",
"base64 0.22.1",
"flate2",
"log",
"once_cell",
@ -5200,6 +5243,7 @@ dependencies = [
"image",
"nalgebra-glm",
"poll-promise",
"serde",
"tracing",
"tracing-subscriber",
"tracing-web",

View file

@ -6,7 +6,7 @@ edition = "2021"
[dependencies]
tracing = "0.1"
tracing-subscriber = "0.3"
eframe = { version = "0.31" }
eframe = { version = "0.31", features = ["persistence"] }
glow = "*"
egui_glow = "0.31"
egui = "0.31"
@ -15,6 +15,7 @@ ehttp = "0.5"
image = "0.25"
bytemuck = "1.22"
nalgebra-glm = "0.19"
serde = { version = "1", features = ["derive"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
tracing-web = "0.1"

View file

@ -94,7 +94,7 @@
}
}
</style>
<link rel="modulepreload" href="/wxbox-client-80142735797f0966.js" crossorigin="anonymous" integrity="sha384-Vt83Dej0N3ylPemIHXzytyKIxG97APHZN9wiDVs0l/Ke7cJAIwuTt06P9cfxlScr"><link rel="preload" href="/wxbox-client-80142735797f0966_bg.wasm" crossorigin="anonymous" integrity="sha384-cgdrHf785ZWa2q7jeTewH7zPTO9blVxrrz8Om8M6boiYE0iolbNJAoWkNUNbIZoe" as="fetch" type="application/wasm"></head>
<link rel="modulepreload" href="/wxbox-client-4ab39f9996332d21.js" crossorigin="anonymous" integrity="sha384-RKP0HUDiGQfxWXl6hL/T+kQcdd+6hIRZz4x4PNzYIAWRzd1ftTPsFDz037h+Ro9x"><link rel="preload" href="/wxbox-client-4ab39f9996332d21_bg.wasm" crossorigin="anonymous" integrity="sha384-g4SnoQkXzKtsR/R3fR6ezczl6JgHv1+4YeAHafD3wGDFal64pg3O9U8GePtlnVXu" as="fetch" type="application/wasm"></head>
<body>
<!-- The WASM code will resize the canvas dynamically -->
@ -111,8 +111,8 @@
<script type="module">
import init, * as bindings from '/wxbox-client-80142735797f0966.js';
const wasm = await init({ module_or_path: '/wxbox-client-80142735797f0966_bg.wasm' });
import init, * as bindings from '/wxbox-client-4ab39f9996332d21.js';
const wasm = await init({ module_or_path: '/wxbox-client-4ab39f9996332d21_bg.wasm' });
window.wasmBindings = bindings;

View file

@ -212,7 +212,7 @@ function debugString(val) {
return className;
}
function __wbg_adapter_32(arg0, arg1, arg2) {
wasm.closure72_externref_shim(arg0, arg1, arg2);
wasm.closure1033_externref_shim(arg0, arg1, arg2);
}
function takeFromExternrefTable0(idx) {
@ -221,12 +221,16 @@ function takeFromExternrefTable0(idx) {
return value;
}
function __wbg_adapter_37(arg0, arg1) {
const ret = wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h0fb7ada914653eaa_multivalue_shim(arg0, arg1);
const ret = wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hf569355bc10ba4a3_multivalue_shim(arg0, arg1);
if (ret[1]) {
throw takeFromExternrefTable0(ret[0]);
}
}
function __wbg_adapter_40(arg0, arg1, arg2) {
wasm.closure1746_externref_shim(arg0, arg1, arg2);
}
/**
* Chroma subsampling format
* @enum {0 | 1 | 2 | 3}
@ -1166,10 +1170,34 @@ function __wbg_get_imports() {
const ret = new Function(getStringFromWasm0(arg0, arg1));
return ret;
};
imports.wbg.__wbg_newwithbyteoffsetandlength_4b01f207bed23fc0 = function(arg0, arg1, arg2) {
const ret = new Int8Array(arg0, arg1 >>> 0, arg2 >>> 0);
return ret;
};
imports.wbg.__wbg_newwithbyteoffsetandlength_5910bdf845a168eb = function(arg0, arg1, arg2) {
const ret = new Uint32Array(arg0, arg1 >>> 0, arg2 >>> 0);
return ret;
};
imports.wbg.__wbg_newwithbyteoffsetandlength_6991ab0478cc4a43 = function(arg0, arg1, arg2) {
const ret = new Int32Array(arg0, arg1 >>> 0, arg2 >>> 0);
return ret;
};
imports.wbg.__wbg_newwithbyteoffsetandlength_69ec77b20853ae02 = function(arg0, arg1, arg2) {
const ret = new Uint16Array(arg0, arg1 >>> 0, arg2 >>> 0);
return ret;
};
imports.wbg.__wbg_newwithbyteoffsetandlength_b0192e1adfca2df1 = function(arg0, arg1, arg2) {
const ret = new Int16Array(arg0, arg1 >>> 0, arg2 >>> 0);
return ret;
};
imports.wbg.__wbg_newwithbyteoffsetandlength_ba35896968751d91 = function(arg0, arg1, arg2) {
const ret = new Uint8Array(arg0, arg1 >>> 0, arg2 >>> 0);
return ret;
};
imports.wbg.__wbg_newwithbyteoffsetandlength_f113a96374814bb2 = function(arg0, arg1, arg2) {
const ret = new Float32Array(arg0, arg1 >>> 0, arg2 >>> 0);
return ret;
};
imports.wbg.__wbg_newwithrecordfromstrtoblobpromise_43dee664be2df4ab = function() { return handleError(function (arg0) {
const ret = new ClipboardItem(arg0);
return ret;
@ -1277,6 +1305,9 @@ function __wbg_get_imports() {
imports.wbg.__wbg_readPixels_33f7af7601585ec6 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) {
arg0.readPixels(arg1, arg2, arg3, arg4, arg5 >>> 0, arg6 >>> 0, arg7);
}, arguments) };
imports.wbg.__wbg_readPixels_bc526324b691316a = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) {
arg0.readPixels(arg1, arg2, arg3, arg4, arg5 >>> 0, arg6 >>> 0, arg7);
}, arguments) };
imports.wbg.__wbg_readPixels_ca434c18552fc5bc = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) {
arg0.readPixels(arg1, arg2, arg3, arg4, arg5 >>> 0, arg6 >>> 0, arg7);
}, arguments) };
@ -1466,6 +1497,9 @@ function __wbg_get_imports() {
imports.wbg.__wbg_texParameteri_d550886a76f21258 = function(arg0, arg1, arg2, arg3) {
arg0.texParameteri(arg1 >>> 0, arg2 >>> 0, arg3);
};
imports.wbg.__wbg_texSubImage2D_0eeb9856a37cc769 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) {
arg0.texSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9);
}, arguments) };
imports.wbg.__wbg_texSubImage2D_355ed8d7c2b07c22 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) {
arg0.texSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9);
}, arguments) };
@ -1599,20 +1633,20 @@ function __wbg_get_imports() {
const ret = false;
return ret;
};
imports.wbg.__wbindgen_closure_wrapper2730 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 73, __wbg_adapter_32);
imports.wbg.__wbindgen_closure_wrapper3798 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1034, __wbg_adapter_32);
return ret;
};
imports.wbg.__wbindgen_closure_wrapper633 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 73, __wbg_adapter_32);
imports.wbg.__wbindgen_closure_wrapper3800 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1034, __wbg_adapter_32);
return ret;
};
imports.wbg.__wbindgen_closure_wrapper635 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 73, __wbg_adapter_32);
imports.wbg.__wbindgen_closure_wrapper3802 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1034, __wbg_adapter_37);
return ret;
};
imports.wbg.__wbindgen_closure_wrapper841 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 73, __wbg_adapter_37);
imports.wbg.__wbindgen_closure_wrapper6521 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1747, __wbg_adapter_40);
return ret;
};
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {

Binary file not shown.

View file

@ -1,33 +1,61 @@
use std::sync::{Arc, Mutex};
use eframe::{Frame, Storage};
use egui::{Context, Event, MouseWheelUnit, Sense, Vec2};
use serde::{Deserialize, Serialize};
use tracing::debug;
use crate::map::{Map};
use crate::map::osm::OSMBaselayer;
use crate::map::tiles::{LayerManager, LayerSource};
#[derive(Serialize, Deserialize)]
pub struct App {
map: Map
}
impl App {
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
if let Some(storage) = cc.storage {
if let Some(stored) = eframe::get_value(storage, eframe::APP_KEY) {
let mut stored: Self = stored;
stored.map.init(cc);
return stored;
}
}
let mut layer_manager = LayerManager::default();
layer_manager.layers.insert(0, OSMBaselayer::SOURCE_ID);
let mut map = Map::new(cc).unwrap();
map.layer_manager = layer_manager;
Self {
map: Map::new(layer_manager, cc).unwrap(),
map,
}
}
}
impl eframe::App for App {
fn save(&mut self, storage: &mut dyn Storage) {
eframe::set_value(storage, eframe::APP_KEY, self);
}
fn update(&mut self, ctx: &Context, frame: &mut Frame) {
egui::SidePanel::left("sidebar")
.resizable(false)
.min_width(ctx.input(|i| i.screen_rect).width() / 6.0)
.show(ctx, |ui| {
ui.heading("wxbox");
ui.collapsing("Map internals", |ui| {
ui.label(format!("Position: {}, {} @ {}", &self.map.lat, &self.map.long, &self.map.zoom));
ui.label(format!("Inertia: {}, {}", &self.map.x_inertia, &self.map.y_inertia));
ui.checkbox(&mut self.map.allow_nonint_zoom, "Allow non-integer zoom (broken)?");
ui.label("Inertia falloff:");
ui.add(egui::DragValue::new(&mut self.map.inertia_falloff).speed(0.01).range(1.1_f64..=2.0));
ui.label("Inertia scale:");
ui.add(egui::DragValue::new(&mut self.map.inertia_scale).speed(0.01).range(0.1_f64..=1.9))
});
});
egui::CentralPanel::default()
@ -38,7 +66,7 @@ impl eframe::App for App {
fn on_exit(&mut self, gl: Option<&glow::Context>) {
if let Some(gl) = gl {
self.map.render.lock().unwrap().destroy(gl);
self.map.render.as_ref().unwrap().lock().unwrap().destroy(gl);
}
}
}

View file

@ -8,35 +8,58 @@ use std::sync::{Arc, Mutex};
use egui::{Event, MouseWheelUnit, Rect, Sense, Ui};
use image::{DynamicImage, ImageReader};
use poll_promise::Promise;
use serde::{Deserialize, Serialize};
use tracing::{debug, warn};
use crate::map::osm::OSMBaselayer;
use crate::map::render::{ExtraRenderOptions, MapRender};
use crate::map::tiles::{LayerId, LayerManager, LayerSource, Tile, XCoord, YCoord, ZoomLevel};
#[derive(Serialize, Deserialize)]
#[serde(default)]
pub struct Map {
pub layer_manager: LayerManager,
pub lat: f64,
pub long: f64,
pub zoom: f64,
pub render: Arc<Mutex<MapRender>>,
#[serde(skip)]
pub render: Option<Arc<Mutex<MapRender>>>,
pub options: ExtraRenderOptions,
pub allow_nonint_zoom: bool
pub allow_nonint_zoom: bool,
pub x_inertia: f64,
pub y_inertia: f64,
pub inertia_falloff: f64,
pub inertia_scale: f64
}
impl Map {
pub fn new<'a>(layer_manager: LayerManager, cc: &'a eframe::CreationContext<'a>) -> Option<Self> {
let gl = cc.gl.as_ref().unwrap();
Some(Self {
layer_manager: layer_manager,
impl Default for Map {
fn default() -> Self {
Self {
layer_manager: LayerManager::default(),
lat: 35.227085,
long: -80.843124,
zoom: 12.0,
render: Arc::new(Mutex::new(MapRender::new(gl)?)),
options: ExtraRenderOptions {
},
allow_nonint_zoom: false
})
render: None,
options: ExtraRenderOptions {},
allow_nonint_zoom: false,
x_inertia: 0.0,
y_inertia: 0.0,
inertia_falloff: 1.25,
inertia_scale: 0.16
}
}
}
impl Map {
pub fn new<'a>(cc: &'a eframe::CreationContext<'a>) -> Option<Self> {
let mut new = Self::default();
new.init(cc);
Some(new)
}
pub fn init<'a>(&mut self, cc: &'a eframe::CreationContext) {
let gl = cc.gl.as_ref().unwrap();
self.render = Some(Arc::new(Mutex::new(MapRender::new(gl).unwrap())));
}
pub fn process_input(&mut self, ctx: &egui::Context, ui: &mut Ui, rect: Rect, response: egui::Response) {
let xy_delta = response.drag_delta();
let z_delta = if ui.rect_contains_pointer(rect) {
@ -67,8 +90,36 @@ impl Map {
let mut x = x * n;
let mut y = y * n;
x -= xy_delta.x as f64 * 1.0 / 256.0;
y -= xy_delta.y as f64 * 1.0 / 256.0;
const MIN_INERTIA: f64 = 0.01;
let x_delta = xy_delta.x as f64 * 1.0 / 256.0;
x -= x_delta;
if self.x_inertia.abs() > MIN_INERTIA {
self.x_inertia /= self.inertia_falloff;
if !response.dragged() {
x -= self.x_inertia;
}
ctx.request_repaint();
}
self.x_inertia += x_delta * self.inertia_scale;
let y_delta = xy_delta.y as f64 * 1.0 / 256.0;
y -= y_delta;
if self.y_inertia.abs() > MIN_INERTIA {
if !response.dragged() {
y -= self.y_inertia;
ctx.request_repaint();
}
self.y_inertia /= self.inertia_falloff;
}
self.y_inertia += y_delta * self.inertia_scale;
let long_deg = x / n * 360.0 - 180.0;
let lat_rad = (std::f64::consts::PI * (1.0 - 2.0 * y / n)).sinh().atan();
@ -203,7 +254,7 @@ impl Map {
);
self.process_input(ctx, ui, rect, response);
let tileset = self.load_tiles(ctx, rect.width() as usize, rect.height() as usize);
let render = self.render.clone();
let render = self.render.as_ref().unwrap().clone();
let options = self.options;
let width = rect.width();
let height = rect.height();

View file

@ -4,6 +4,7 @@ use std::io::Cursor;
use std::mem;
use glow::{Buffer, HasContext, PixelUnpackData, Program, Texture, VertexArray};
use image::{DynamicImage, EncodableLayout, ImageReader};
use serde::{Deserialize, Serialize};
use tracing::{debug, error, warn};
use crate::map::tiles::{LayerId, XCoord, YCoord, ZoomLevel};
use crate::map::Tileset;
@ -224,6 +225,6 @@ impl MapRender {
}
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Serialize, Deserialize)]
pub struct ExtraRenderOptions {
}

View file

@ -1,6 +1,7 @@
use std::collections::{BTreeMap, HashMap};
use image::DynamicImage;
use poll_promise::Promise;
use serde::{Deserialize, Serialize};
// type aliases to make the tile map less hellish
pub type ZoomLevel = usize;
@ -8,9 +9,11 @@ pub type XCoord = usize;
pub type YCoord = usize;
pub type LayerId = u64;
#[derive(Default)]
#[derive(Default, Serialize, Deserialize)]
#[serde(default)]
pub struct LayerManager {
pub layers: Vec<LayerId>,
#[serde(skip)]
pub tiles: HashMap<(ZoomLevel, XCoord, YCoord, LayerId), Tile>,
}