use anyhow::Result; use arrayvec::ArrayVec; use libtw2_event_loop::{ Addr, Application, Chunk, ConnlessChunk, Loop, PeerId, SocketLoop, Timeout, }; use libtw2_gamenet_ddnet::{ enums::{Team, VERSION}, msg::{ self, Game, System, SystemOrGame, game::{ClSetTeam, ClStartInfo}, system::{EnterGame, Info, Ready}, }, }; use libtw2_packer::{Unpacker, with_packer}; use log::warn; use std::{ fmt::{self, Debug}, net::{IpAddr, Ipv4Addr}, }; pub struct Client {} impl Client { pub fn new() -> Result { let mut sloop = SocketLoop::client(); sloop.connect(Addr { ip: IpAddr::V4(Ipv4Addr::LOCALHOST), port: 8303, }); sloop.run(ClientNetwork {}); Ok(Self {}) } } pub struct ClientNetwork {} impl Application for ClientNetwork { fn needs_tick(&mut self) -> Timeout { Timeout::inactive() } fn on_tick(&mut self, loop_: &mut L) {} fn on_packet(&mut self, loop_: &mut L, chunk: Chunk) { let pid = chunk.pid; let msg; match msg::decode(&mut Warn(chunk.data), &mut Unpacker::new(chunk.data)) { Ok(m) => msg = m, Err(err) => { warn!("decode error {:?}:", err); return; } } eprintln!("{msg:?}"); match msg { SystemOrGame::System(System::MapChange(map)) => { loop_.sends(pid, Ready); } SystemOrGame::System(System::ConReady(..)) => { loop_.sendg(pid, ClStartInfo { name: b"testclient", clan: b"metamuffin", country: -1, skin: b"limekittygirl", use_custom_color: true, color_body: 0xFF00FF, color_feet: 0x550055, }); } SystemOrGame::Game(Game::SvReadyToEnter(..)) => { loop_.sends(pid, EnterGame); loop_.sendg(pid, ClSetTeam { team: Team::Red }); } _ => {} } } fn on_connless_packet(&mut self, loop_: &mut L, chunk: ConnlessChunk) {} fn on_connect(&mut self, loop_: &mut L, pid: PeerId) { todo!() } fn on_ready(&mut self, loop_: &mut L, pid: PeerId) { loop_.sends(pid, Info { version: VERSION.as_bytes(), password: Some(b""), }); loop_.flush(pid); } fn on_disconnect(&mut self, loop_: &mut L, pid: PeerId, remote: bool, reason: &[u8]) {} } // Copied straight from libtw2/downloader/src/main.rs by heinrich5991, MIT-or-Apache-2.0 trait LoopExt: Loop { fn sends<'a, S: Into>>(&mut self, pid: PeerId, msg: S) { fn inner(msg: System, pid: PeerId, loop_: &mut L) { let mut buf: ArrayVec<[u8; 2048]> = ArrayVec::new(); with_packer(&mut buf, |p| msg.encode(p).unwrap()); loop_.send(Chunk { pid, vital: true, data: &buf, }) } inner(msg.into(), pid, self) } fn sendg<'a, G: Into>>(&mut self, pid: PeerId, msg: G) { fn inner(msg: Game, pid: PeerId, loop_: &mut L) { let mut buf: ArrayVec<[u8; 2048]> = ArrayVec::new(); with_packer(&mut buf, |p| msg.encode(p).unwrap()); loop_.send(Chunk { pid, vital: true, data: &buf, }) } inner(msg.into(), pid, self) } } impl LoopExt for L {} struct Warn<'a>(&'a [u8]); impl<'a, W: Debug> warn::Warn for Warn<'a> { fn warn(&mut self, w: W) { warn!("{:?}", w); } }