use avian2d::prelude::{AngularInertia, AngularVelocity, Collider, LinearVelocity, Mass, Position, Rotation};
use bevy::ecs::entity::MapEntities;
use bevy::prelude::*;
use crate::prelude::{App, Message};
use bevy_replicon::prelude::*;
use serde::{Deserialize, Serialize};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use url::{Host, Url};
use crate::shared::attachment::{Joint, JointOf, PartInShip, Peer, Ship, SnapOf, SnapOfJoint};
use crate::shared::config::planet::{Planet, PlanetSpring, PlanetSpringJoint};
use crate::shared::ecs::{CanCraft, Drill, Part, Player, PlayerStorage, SingleStorage, Temperature};
use crate::shared::ecs::thruster::{Thruster, ThrusterOfPart};
pub const STARKINGDOMS_PROTOCOL_MAGIC: u64 = 0x5a5a_e37e_4aaa;
pub fn register_replication(app: &mut App) {
app
.add_mapped_server_message::<Hi>(Channel::Ordered)
.replicate_once::<Transform>()
.replicate_once::<GlobalTransform>()
.replicate::<Position>()
.replicate::<Rotation>()
.replicate::<LinearVelocity>()
.replicate::<AngularVelocity>()
.replicate::<AngularInertia>()
.replicate::<Mass>()
.replicate::<Collider>()
.replicate::<Part>()
.replicate::<Planet>()
.replicate::<Player>()
.replicate::<ChildOf>()
.replicate::<Ship>()
.replicate::<PartInShip>()
.replicate::<Joint>()
.replicate::<Peer>()
.replicate::<JointOf>()
.replicate::<SnapOfJoint>()
.replicate::<SnapOf>()
.replicate::<PlayerStorage>()
.replicate::<Thruster>()
.replicate::<ThrusterOfPart>()
.replicate::<CanCraft>()
.replicate::<Temperature>()
.replicate::<Drill>()
.replicate::<SingleStorage>()
.replicate::<PlanetSpring>()
.replicate::<PlanetSpringJoint>();
}
#[derive(Message, Deserialize, Serialize, MapEntities)]
pub struct Hi {
#[entities]
pub you_are: Entity,
pub time_offset: f64,
}
#[derive(Serialize, Deserialize)]
pub struct ManagementInfo {
pub native_port: u16,
pub wt_port: u16,
pub cert_hash: String,
}
/// wasm is hard
pub fn parse_management_address(s: &str) -> Result<SocketAddr, String> {
let url = Url::parse(s).map_err(|err| format!("invalid server URL: {err}"))?;
let ip = match url.host() {
Some(Host::Ipv4(ip)) => IpAddr::V4(ip),
Some(Host::Ipv6(ip)) => IpAddr::V6(ip),
Some(Host::Domain(domain)) => domain.parse::<IpAddr>()
.map_err(|_| format!("server host must be an IP address, got `{domain}`"))?,
None => return Err("server URL is missing a host".to_string()),
};
let port = url.port().ok_or("server URL is missing a port")?;
Ok(SocketAddr::new(ip, port))
}
pub fn encode_cert_hash(hash: &[u8; 32]) -> String {
hash.iter().map(|byte| format!("{byte:02x}")).collect()
}
pub fn decode_cert_hash(s: &str) -> Result<[u8; 32], String> {
if s.len() != 64 {
return Err(format!("cert_hash must be 64 hex chars, got {}", s.len()));
}
let mut hash = [0u8; 32];
for (byte, chunk) in hash.iter_mut().zip(s.as_bytes().chunks_exact(2)) {
let chunk = std::str::from_utf8(chunk).unwrap();
*byte = u8::from_str_radix(chunk, 16).map_err(|err| format!("invalid cert_hash: {err}"))?;
}
Ok(hash)
}