From e3aea1494d9585c8a45048b2edd8d2635f34c9a3 Mon Sep 17 00:00:00 2001 From: catvayor Date: Wed, 22 May 2024 15:54:49 +0200 Subject: [PATCH] vision implementation --- Cargo.lock | 1 + Cargo.toml | 3 + src/main.rs | 165 ++++++++++++++++++++++++++++++++---- static/utils.js | 114 +++++++++++++------------ templates/conscrit.html.hbs | 21 ++--- 5 files changed, 222 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2538a5..c8c50b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1566,6 +1566,7 @@ dependencies = [ name = "traque" version = "0.1.0" dependencies = [ + "rand", "rocket", "rocket_dyn_templates", ] diff --git a/Cargo.toml b/Cargo.toml index cbc8538..136c681 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies] +rand = "0.8.5" + [dependencies.rocket] version = "0.5.0" features = ["json"] diff --git a/src/main.rs b/src/main.rs index 5e80c2a..79175b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ #[macro_use] extern crate rocket; +use rand::Rng; use rocket::{ fs::{relative, FileServer}, response::stream::{Event, EventStream}, @@ -18,7 +19,7 @@ enum TrackedState { invisible: bool, blurred: bool, captured: bool, - malette: bool, + mallette: bool, invisibility_codes: u32, blur_codes: u32, }, @@ -28,29 +29,98 @@ enum TrackedState { }, } +use TrackedState::{Conscrit, Vieux}; + +const BLURRED_MOVE: (f32, f32) = (0.0005, 0.0005); + +impl TrackedState { + fn invisible(&self) -> bool { + match self { + Conscrit { invisible, .. } => *invisible, + Vieux { invisible, .. } => *invisible, + } + } + fn blurred(&self) -> bool { + match self { + Conscrit { blurred, .. } => *blurred, + Vieux { .. } => false, + } + } + fn global_viewed(&self) -> bool { + match self { + Conscrit { + captured, + mallette, + invisible, + .. + } => (*captured || *mallette) && !*invisible, + Vieux { invisible, .. } => !*invisible, + } + } + fn color(&self) -> u8 { + match self { + Vieux { color, .. } => *color, + Conscrit { captured, .. } => { + if *captured { + 1 + } else { + 0 + } + } + } + } + fn admin_color(&self) -> u8 { + match self { + Vieux { color, invisible } => { + if *invisible { + 2 + } else { + *color + } + } + Conscrit { + invisible, + captured, + .. + } => { + if *invisible { + 2 + } else if *captured { + 1 + } else { + 0 + } + } + } + } +} + struct Tracked { + id: String, name: String, pos: (f32, f32), state: TrackedState, } -fn build_conscrit(name: String) -> Tracked { +fn build_conscrit(id: String, name: String) -> Tracked { Tracked { + id: id, name: name, pos: (0.0, 0.0), state: TrackedState::Conscrit { invisible: false, blurred: false, captured: false, - malette: false, + mallette: false, invisibility_codes: 0, blur_codes: 0, }, } } -fn build_vieux(name: String) -> Tracked { +fn build_vieux(id: String, name: String) -> Tracked { Tracked { + id: id, name: name, pos: (0.0, 0.0), state: TrackedState::Vieux { @@ -67,6 +137,64 @@ type Tracking = RwLock>>; struct TrackedInfo { name: String, pos: (f32, f32), + me: bool, + color: u8, +} + +fn base_view(team: &Tracked) -> TrackedInfo { + TrackedInfo { + name: team.name.clone(), + pos: team.pos, + me: false, + color: team.state.color(), + } +} + +fn admin_view(team: &Tracked) -> TrackedInfo { + TrackedInfo { + name: team.name.clone(), + pos: team.pos, + me: false, + color: team.state.admin_color(), + } +} + +fn apparent_info(watcher: &Tracked, team: &Tracked) -> Option { + if watcher.id == team.id { + Some(TrackedInfo { + me: true, + ..admin_view(team) + }) + } else if let Conscrit { + captured, mallette, .. + } = watcher.state + { + if captured { + if team.state.invisible() { + None + } else if team.state.blurred() { + let mut rng = rand::thread_rng(); + let (lat, lon) = team.pos; + Some(TrackedInfo { + pos: ( + lat + BLURRED_MOVE.0 * (rng.gen::() * 2.0 - 1.0), + lon + BLURRED_MOVE.1 * (rng.gen::() * 2.0 - 1.0), + ), + ..base_view(team) + }) + } else { + Some(base_view(team)) + } + } else { + if mallette || team.state.global_viewed() { + Some(base_view(team)) + } else { + None + } + } + } else { + Some(admin_view(team)) + } } #[get("/track/?")] @@ -88,6 +216,18 @@ fn tracked_view(id: &str, gpslog: Option, tracking: &State) -> O } } +fn info_to_send(id: &String, tracking: &Tracking) -> Vec { + let tracking_lock = tracking.read().unwrap(); + let watcher = tracking_lock.get(id).unwrap().read().unwrap(); + let mut infos: Vec = Vec::new(); + for (_, tracked) in tracking_lock.iter() { + if let Some(info) = apparent_info(&watcher, &tracked.read().unwrap()) { + infos.push(info); + } + } + infos +} + #[get("/track//events")] fn tracked_events<'a>( id: &'a str, @@ -99,13 +239,8 @@ fn tracked_events<'a>( let mut interval = time::interval(Duration::from_secs(5)); loop { select!{ - _ = interval.tick() => { - let info = TrackedInfo { - name: id.to_string(), - pos: tracking.read().unwrap().get(&id.to_string()).unwrap().read().unwrap().pos - }; - yield Event::json(&info).event("coords") - }, + _ = interval.tick() => + yield Event::json(&info_to_send(&id.to_string(), &tracking)).event("coords"), _ = &mut shutdown => break } } @@ -132,19 +267,19 @@ fn rocket() -> _ { let tracking = HashMap::>::from([ ( "team00".to_string(), - RwLock::new(build_conscrit("Équipe 0".to_string())), + RwLock::new(build_conscrit("team00".to_string(), "Équipe 0".to_string())), ), ( "team01".to_string(), - RwLock::new(build_conscrit("Équipe 1".to_string())), + RwLock::new(build_conscrit("team01".to_string(), "Équipe 1".to_string())), ), ( "npc0".to_string(), - RwLock::new(build_vieux("PNJ 0".to_string())), + RwLock::new(build_vieux("npc0".to_string(), "PNJ 0".to_string())), ), ( "npc1".to_string(), - RwLock::new(build_vieux("PNJ 1".to_string())), + RwLock::new(build_vieux("npc1".to_string(), "PNJ 1".to_string())), ), ]); rocket::build() diff --git a/static/utils.js b/static/utils.js index c5ccd3b..54d93b7 100644 --- a/static/utils.js +++ b/static/utils.js @@ -1,9 +1,5 @@ -var protocol = location.protocol; -var server = location.hostname; -var port = location.port; -var socket; -var id; -var markers = {}; +var evtsource; +var markers = []; var CircleIcon = L.Icon.extend({ options: { @@ -67,70 +63,80 @@ var map_border = [ var map; function setup_map(){ - map = L.map('map').setView([48.8448, 2.3550], 13); + map = L.map('map').setView([48.8448, 2.3550], 13); - L.tileLayer('https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png', { - maxZoom: 19, - attribution: '© OpenStreetMap' - }).addTo(map); + L.tileLayer('https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.{ext}', { + maxZoom: 20, + minZoom: 0, + attribution: '© Stadia Maps © Stamen Design © OpenMapTiles © OpenStreetMap contributors', + ext: 'png' + }).addTo(map); - L.polyline(map_border, {color: 'red'}).addTo(map); + L.polyline(map_border, {color: 'red'}).addTo(map); } ////////////////////////////////////////////////////////////////////////////// -// SOCKET +// EVENT LISTENNING -function setup_socket_common(){ - socket.on("moving", function(data){ - console.log("moving", data); - if(!(data.id in markers)){ - if(data.id == id){ - markers[data.id] = L.marker(data.position, {"icon": self_icons[data.color]}).addTo(map); - markers[data.id].setZIndexOffset(10000); - } - else - markers[data.id] = L.marker(data.position, {"icon": icons[data.color]}).addTo(map); - markers[data.id].bindPopup(data.id); - } else{ - markers[data.id].setLatLng(data.position); - if(data.id == id) - markers[data.id].setIcon(self_icons[data.color]); - else - markers[data.id].setIcon(icons[data.color]); - } - }); +function setup_evtlisten_common(){ + evtSource.addEventListener("coords", (event) => { + const data = JSON.parse(event.data); + console.log(data); + var i = 0; + for (tracked of data) { + if (i == markers.length) { + markers.push(L.marker([0,0], {"icon": icons[0] }).addTo(map)); + markers[i].bindPopup(""); + } + markers[i].setLatLng(tracked.pos); + markers[i].setPopupContent(tracked.name); + if (tracked.me) { + markers[i].setIcon(self_icons[tracked.color]); + markers[i].setZIndexOffset(1000); + } else { + markers[i].setIcon(icons[tracked.color]); + markers[i].setZIndexOffset(0); + } + ++i; + } + for (; i < markers.length; ++i) { + markers[i].setLatLng([0,0]); + } + }); - socket.on("popup", function(data){ - alert(data.content); - }); + //socket.on("popup", function(data){ + // alert(data.content); + //}); - socket.on("remove", function(data){ - if(data.id in markers) - markers[data.id].remove(); - }); + //socket.on("remove", function(data){ + // if(data.id in markers) + // markers[data.id].remove(); + //}); - socket.on("newTracker", function(data){ - L.marker(data.position, {"icon": icons[1]}).addTo(map); - }); + //socket.on("newTracker", function(data){ + // L.marker(data.position, {"icon": icons[1]}).addTo(map); + //}); } ////////////////////////////////////////////////////////////////////////////// // GEOLOCALISATION function setup_geoLoc(){ - function geoLoc_success(pos) { - fetch("/log?id="+id+"&lat="+pos.coords.latitude+"&lon="+pos.coords.longitude); - } + const requestOptions = { method: 'PUT' }; - function geoLoc_error(err) { - console.error(`ERROR(${err.code}): ${err.message}`); - } + function geoLoc_success(pos) { + fetch("/log/"+id+"?lat="+pos.coords.latitude+"&long="+pos.coords.longitude, requestOptions); + } - var options = { - enableHighAccuracy: false, - timeout: 5000, - maximumAge: 0 - }; + function geoLoc_error(err) { + console.error(`ERROR(${err.code}): ${err.message}`); + } - navigator.geolocation.watchPosition(geoLoc_success, geoLoc_error, options); + var options = { + enableHighAccuracy: false, + timeout: 5000, + maximumAge: 0 + }; + + navigator.geolocation.watchPosition(geoLoc_success, geoLoc_error, options); } diff --git a/templates/conscrit.html.hbs b/templates/conscrit.html.hbs index c9371a9..785be2a 100644 --- a/templates/conscrit.html.hbs +++ b/templates/conscrit.html.hbs @@ -24,7 +24,7 @@ } - +

@@ -36,21 +36,16 @@