~starkingdoms/starkingdoms

ref: 011a026fb2c7d43d688798bdeb8ea70a6315b7b3 starkingdoms/crates/unified/src/shared/net.rs -rw-r--r-- 3.3 KiB
011a026f — core netcode: rd3 6 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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::<Transform>()
        .replicate::<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)
}