Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
iiiii7d committed Jan 4, 2025
1 parent 3b9ef55 commit d2fd038
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ Cargo.lock
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/
17 changes: 17 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "mrt-flightradar2"
version = "0.1.0"
edition = "2024"

[dependencies]
air-traffic-simulator = { git="https://github.com/bitfielddev/air-traffic-simulator" }

color-eyre = "0.6.3"
serde_yaml = "0.9.34"
tokio = { version = "1.42.0", features = ["full"] }
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
itertools = "0.13.0"

surf = "2.3.2"
csv = "1.3.1"
glam = "0.29.2"
54 changes: 54 additions & 0 deletions src/airports.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use std::sync::Arc;
use air_traffic_simulator::engine::world_data::{AirportData, Runway};
use air_traffic_simulator::WorldData;
use color_eyre::Report;
use glam::Vec2;
use color_eyre::Result;

pub async fn airports(world_data: &mut WorldData) -> Result<()> {
let client = surf::client().with(surf::middleware::Redirect::new(5));
let string = client.send(surf::get("https://docs.google.com/spreadsheets/d/11E60uIBKs5cOSIRHLz0O0nLCefpj7HgndS1gIXY_1hw/export?format=csv&gid=0"))
.await.map_err(|a| Report::msg(a.to_string()))?
.body_string()
.await.map_err(|a| Report::msg(a.to_string()))?;
let mut reader = csv::Reader::from_reader(string.as_bytes());
fn parse_coords(c: &str) -> Vec2 {
let mut a = c.trim().split(' ');
Vec2::new(a.next().and_then(|a| a.parse().ok()).unwrap(), a.next().and_then(|a| a.parse().ok()).unwrap())
}
world_data.airports = reader.records().map(|res| {
let res = res?;
if !res.get(1).unwrap().contains("Airfield") && !res.get(1).unwrap().contains("Airport") {
return Ok(None)
}
let mut runways = vec![];
for i in [3, 7, 11, 15] {
if res.get(i).is_none_or(|a| a.is_empty()) {
if i == 3 {
return Ok(None)
}
break
}
runways.push(Arc::new(Runway {
name: res.get(i+2).unwrap().into(),
start: parse_coords(res.get(i).unwrap()),
end: parse_coords(res.get(i+1).unwrap()),
altitude: 0.0,
class: res.get(i+3).unwrap().chars().next().unwrap().to_string().into(),
}));
runways.push(Arc::new(Runway {
name: res.get(i+2).unwrap().into(),
start: parse_coords(res.get(i+1).unwrap()),
end: parse_coords(res.get(i).unwrap()),
altitude: 0.0,
class: res.get(i+3).unwrap().chars().next().unwrap().to_string().into(),
}));
}
Ok(Some(Arc::new(AirportData {
name: res.get(0).unwrap().into(),
code: res.get(0).unwrap().into(),
runways: runways.into(),
})))
}).collect::<Result<Vec<_>>>()?.into_iter().flatten().collect();
Ok(())
}
56 changes: 56 additions & 0 deletions src/client_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as L from "leaflet";


class CustomTileLayer extends L.TileLayer {
getTileUrl(coords) {
const Zcoord = 2 ** (8 - coords.z);
const Xcoord = coords.x * 1;
const Ycoord = coords.y * -1;
const group = {
x: Math.floor((Xcoord * Zcoord) / 32),
y: Math.floor((Ycoord * Zcoord) / 32),
};
const numberInGroup = {
x: Math.floor(Xcoord * Zcoord),
y: Math.floor(Ycoord * Zcoord),
};
let zzz = "";
for (let i = 8; i > coords.z; i--) {
zzz += "z";
}
if (zzz.length !== 0) zzz += "_";
return `https://dynmap.minecartrapidtransit.net/main/tiles/new/flat/${group.x}_${group.y}/${zzz}${numberInGroup.x}_${numberInGroup.y}.png`;
}
}

export const tileLayer = new CustomTileLayer("", {
maxZoom: 8,
id: "map",
tileSize: 128,
zoomOffset: 0,
noWrap: true,
bounds: [
[-900, -900],
[900, 900],
],
attribution: "Minecart Rapid Transit",
});

export const altitudeColours = [
[50, "#aaaaaa"],
[100, "#aaaa00"],
[150, "#00aa00"],
[250, "#00aaaa"],
[350, "#0000aa"],
[450, "#aa00aa"],
[550, "#aa0000"],
[650, "#000000"],
];

export function world2map([x, y]) {
return [y / -64 - 0.5, x / 64];
}

export function world2map3([x, y, z]) {
return [y / -64 - 0.5, x / 64, z];
}
4 changes: 4 additions & 0 deletions src/engine_config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
tick_duration: 1.0
plane_spawn_chance: 0.1
max_planes: 100
cruising_altitude: 500
29 changes: 29 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
mod airports;
mod waypoints;

use air_traffic_simulator::WorldData;
use color_eyre::Result;
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
use crate::airports::airports;
use crate::waypoints::waypoints;

#[tokio::main]
async fn main() -> Result<()> {
color_eyre::install()?;
tracing_subscriber::registry()
.with(EnvFilter::from_env("RUST_LOG"))
.with(fmt::layer())
.try_init()?;

let mut world_data: WorldData = serde_yaml::from_str(include_str!("wd.yml"))?;

airports(&mut world_data).await?;
waypoints(&mut world_data).await?;

let engine_config = serde_yaml::from_str(include_str!("engine_config.yml"))?;
let engine = air_traffic_simulator::Engine::new(world_data, engine_config);

air_traffic_simulator::run_server(engine, Some(include_str!("client_config.js"))).await?;

Ok(())
}
58 changes: 58 additions & 0 deletions src/waypoints.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use std::sync::Arc;
use air_traffic_simulator::engine::world_data::Waypoint;
use air_traffic_simulator::WorldData;
use color_eyre::Report;
use glam::Vec2;
use color_eyre::Result;
use itertools::Itertools;

fn nearest_waypoints(waypoints: &[(String, Vec2, Vec<&String>)], wp: Vec2) -> Vec<String> {
let mut radius = 0.0;
let mut nearest = vec![];
while nearest.len() < 3 {
radius += 1000.0;
nearest = waypoints
.iter()
.filter(|(_, w, _)| *w != wp)
.filter(|(_, w, _)| w.distance(wp) < radius)
.map(|(a, _, _)| a.to_owned())
.collect();
}
nearest
}

pub async fn waypoints(world_data: &mut WorldData) -> Result<()> {
let client = surf::client().with(surf::middleware::Redirect::new(5));
let string = client.send(surf::get("https://docs.google.com/spreadsheets/d/11E60uIBKs5cOSIRHLz0O0nLCefpj7HgndS1gIXY_1hw/export?format=csv&gid=707730663"))
.await.map_err(|a| Report::msg(a.to_string()))?
.body_string()
.await.map_err(|a| Report::msg(a.to_string()))?;
let mut reader = csv::Reader::from_reader(string.as_bytes());
fn parse_coords(c: &str) -> Vec2 {
let mut a = c.trim().split(' ');
Vec2::new(a.next().and_then(|a| a.parse().ok()).unwrap(), a.next().and_then(|a| a.parse().ok()).unwrap())
}

let mut waypoints = reader.records().map(|res| {
let res = res.unwrap();
(res.get(0).unwrap().into(), parse_coords(res.get(1).unwrap()), vec![])
}).collect::<Vec<_>>();

let mut airways = vec![];
for (name, coords, _) in &waypoints {
for nw in nearest_waypoints(&waypoints, *coords) {
airways.push((name.to_owned(), nw.to_owned()))
}
}
for (name, _, conns) in &mut waypoints {
*conns = airways.iter().filter_map(|(a, b)| {
if *a == *name {Some(b)} else if *b == *name {Some(a)} else { None }
}).sorted().dedup().collect()
}
world_data.waypoints = waypoints.into_iter().map(|(name, coords, conns)| Arc::new(Waypoint {
name: name.into(),
pos: coords,
connections: conns.into_iter().map(Into::into).collect()
})).collect();
Ok(())
}
14 changes: 14 additions & 0 deletions src/wd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
classes: [["XS", "S", "MS", "M", "ML", "L"], ["SP"]]
airports: []
flights: null
planes:
- id: "Airplane"
name: "Airplane"
manufacturer: "Me"
class: "XS"
motion:
max_v: [15.0, 5.0]
max_a: [1.0, 0.3]
turning_radius: 100.0
icon: null
waypoints: []

0 comments on commit d2fd038

Please sign in to comment.