diff --git a/Cargo.lock b/Cargo.lock index 55d9d32..c3de89f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -605,7 +605,7 @@ dependencies = [ [[package]] name = "rsbuf" -version = "225.1.7" +version = "225.1.8" dependencies = [ "criterion", "getrandom", diff --git a/Cargo.toml b/Cargo.toml index bcf625f..7a3748f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rsbuf" -version = "225.1.7" +version = "225.1.8" edition = "2021" authors = ["2004Scape"] description = "A RuneScape update info computer." diff --git a/package.json b/package.json index 874cc7c..108c9e5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@2004scape/rsbuf", - "version": "225.1.7", + "version": "225.1.8", "description": "A RuneScape update info computer", "main": "dist/rsbuf.js", "types": "dist/rsbuf.d.ts", diff --git a/src/build.rs b/src/build.rs index 4725be8..d2f4c38 100644 --- a/src/build.rs +++ b/src/build.rs @@ -305,10 +305,10 @@ impl BuildArea { y: u8, z: u16 ) -> bool { - if let Some(other) = unsafe { &*players.as_ptr().add(player as usize) } { - return !(self.players.contains(player) || !CoordGrid::within_distance_sw(&other.coord, &CoordGrid::from(x, y, z), self.view_distance) || other.pid == -1 || other.pid == pid || other.coord.y() != y); - } - return false; + return match unsafe { &*players.as_ptr().add(player as usize) } { + None => false, + Some(other) => !(self.players.contains(player) || !CoordGrid::within_distance_sw(&other.coord, &CoordGrid::from(x, y, z), self.view_distance) || other.pid == -1 || other.pid == pid || other.coord.y() != y), + }; } #[inline] @@ -320,9 +320,9 @@ impl BuildArea { y: u8, z: u16 ) -> bool { - if let Some(other) = unsafe { &*npcs.as_ptr().add(npc as usize) } { - return !(self.npcs.contains(npc) || !CoordGrid::within_distance_sw(&other.coord, &CoordGrid::from(x, y, z), BuildArea::PREFERRED_VIEW_DISTANCE) || other.nid == -1 || other.coord.y() != y || !other.active); - } - return false; + return match unsafe { &*npcs.as_ptr().add(npc as usize) } { + None => false, + Some(other) => !(self.npcs.contains(npc) || !CoordGrid::within_distance_sw(&other.coord, &CoordGrid::from(x, y, z), BuildArea::PREFERRED_VIEW_DISTANCE) || other.nid == -1 || other.coord.y() != y || !other.active), + }; } } \ No newline at end of file diff --git a/src/category.rs b/src/category.rs new file mode 100644 index 0000000..8ac0cdb --- /dev/null +++ b/src/category.rs @@ -0,0 +1,23 @@ +#![allow(non_camel_case_types)] + +use wasm_bindgen::prelude::wasm_bindgen; + +#[repr(u8)] +#[wasm_bindgen] +// todo: measure how many events we should expect to receive from the client +// osrs has this as 50/10 but we know that's not true in rs2 +// todo: determine which packets belong in which category for this era +pub enum ClientProtCategory { + CLIENT_EVENT = 0, + USER_EVENT = 1, + RESTRICTED_EVENT = 2, // flood restricted events +} + +#[repr(u8)] +#[wasm_bindgen] +// packet decoding limit per tick, exceeding this ends decoding and picks up where it left off on the next tick +pub enum ClientProtCategoryLimit { + CLIENT_EVENT = 20, + USER_EVENT = 5, + RESTRICTED_EVENT = 2, +} \ No newline at end of file diff --git a/src/coord.rs b/src/coord.rs index 823d476..4980c6d 100644 --- a/src/coord.rs +++ b/src/coord.rs @@ -47,4 +47,14 @@ impl CoordGrid { pub const fn zone(pos: u16) -> u16 { return pos >> 3; } + + #[inline] + pub const fn origin(pos: u16) -> u16 { + return ((pos >> 3) - 6) << 3; + } + + #[inline] + pub const fn pack_zone_coord(x: u16, z: u16) -> u8 { + return (((x & 0x7) as u8) << 4) | (z & 0x7) as u8; + } } \ No newline at end of file diff --git a/src/in/anticheat.rs b/src/in/anticheat.rs new file mode 100644 index 0000000..5e96f6b --- /dev/null +++ b/src/in/anticheat.rs @@ -0,0 +1,392 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct AnticheatOp1 {} + +impl AnticheatOp1 { + const DEFAULT: AnticheatOp1 = AnticheatOp1::new(); + + #[inline] + pub const fn new() -> AnticheatOp1 { + return AnticheatOp1 {}; + } +} + +impl MessageDecoder for AnticheatOp1 { + #[inline] + fn length() -> i32 { + return 4; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatOp1 { + return AnticheatOp1::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatOp2 {} + +impl AnticheatOp2 { + const DEFAULT: AnticheatOp2 = AnticheatOp2::new(); + + #[inline] + pub const fn new() -> AnticheatOp2 { + return AnticheatOp2 {}; + } +} + +impl MessageDecoder for AnticheatOp2 { + #[inline] + fn length() -> i32 { + return 4; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatOp2 { + return AnticheatOp2::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatOp3 {} + +impl AnticheatOp3 { + const DEFAULT: AnticheatOp3 = AnticheatOp3::new(); + + #[inline] + pub const fn new() -> AnticheatOp3 { + return AnticheatOp3 {}; + } +} + +impl MessageDecoder for AnticheatOp3 { + #[inline] + fn length() -> i32 { + return 3; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatOp3 { + return AnticheatOp3::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatOp4 {} + +impl AnticheatOp4 { + const DEFAULT: AnticheatOp4 = AnticheatOp4::new(); + + #[inline] + pub const fn new() -> AnticheatOp4 { + return AnticheatOp4 {}; + } +} + +impl MessageDecoder for AnticheatOp4 { + #[inline] + fn length() -> i32 { + return 2; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatOp4 { + return AnticheatOp4::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatOp5 {} + +impl AnticheatOp5 { + const DEFAULT: AnticheatOp5 = AnticheatOp5::new(); + + #[inline] + pub const fn new() -> AnticheatOp5 { + return AnticheatOp5 {}; + } +} + +impl MessageDecoder for AnticheatOp5 { + #[inline] + fn length() -> i32 { + return 0; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatOp5 { + return AnticheatOp5::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatOp6 {} + +impl AnticheatOp6 { + const DEFAULT: AnticheatOp6 = AnticheatOp6::new(); + + #[inline] + pub const fn new() -> AnticheatOp6 { + return AnticheatOp6 {}; + } +} + +impl MessageDecoder for AnticheatOp6 { + #[inline] + fn length() -> i32 { + return 4; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatOp6 { + return AnticheatOp6::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatOp7 {} + +impl AnticheatOp7 { + const DEFAULT: AnticheatOp7 = AnticheatOp7::new(); + + #[inline] + pub const fn new() -> AnticheatOp7 { + return AnticheatOp7 {}; + } +} + +impl MessageDecoder for AnticheatOp7 { + #[inline] + fn length() -> i32 { + return 4; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatOp7 { + return AnticheatOp7::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatOp8 {} + +impl AnticheatOp8 { + const DEFAULT: AnticheatOp8 = AnticheatOp8::new(); + + #[inline] + pub const fn new() -> AnticheatOp8 { + return AnticheatOp8 {}; + } +} + +impl MessageDecoder for AnticheatOp8 { + #[inline] + fn length() -> i32 { + return 2; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatOp8 { + return AnticheatOp8::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatOp9 {} + +impl AnticheatOp9 { + const DEFAULT: AnticheatOp9 = AnticheatOp9::new(); + + #[inline] + pub const fn new() -> AnticheatOp9 { + return AnticheatOp9 {}; + } +} + +impl MessageDecoder for AnticheatOp9 { + #[inline] + fn length() -> i32 { + return 1; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatOp9 { + return AnticheatOp9::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatCycle1 {} + +impl AnticheatCycle1 { + const DEFAULT: AnticheatCycle1 = AnticheatCycle1::new(); + + #[inline] + pub const fn new() -> AnticheatCycle1 { + return AnticheatCycle1 {}; + } +} + +impl MessageDecoder for AnticheatCycle1 { + #[inline] + fn length() -> i32 { + return 1; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatCycle1 { + return AnticheatCycle1::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatCycle2 {} + +impl AnticheatCycle2 { + const DEFAULT: AnticheatCycle2 = AnticheatCycle2::new(); + + #[inline] + pub const fn new() -> AnticheatCycle2 { + return AnticheatCycle2 {}; + } +} + +impl MessageDecoder for AnticheatCycle2 { + #[inline] + fn length() -> i32 { + return -1; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatCycle2 { + return AnticheatCycle2::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatCycle3 {} + +impl AnticheatCycle3 { + const DEFAULT: AnticheatCycle3 = AnticheatCycle3::new(); + + #[inline] + pub const fn new() -> AnticheatCycle3 { + return AnticheatCycle3 {}; + } +} + +impl MessageDecoder for AnticheatCycle3 { + #[inline] + fn length() -> i32 { + return 3; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatCycle3 { + return AnticheatCycle3::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatCycle4 {} + +impl AnticheatCycle4 { + const DEFAULT: AnticheatCycle4 = AnticheatCycle4::new(); + + #[inline] + pub const fn new() -> AnticheatCycle4 { + return AnticheatCycle4 {}; + } +} + +impl MessageDecoder for AnticheatCycle4 { + #[inline] + fn length() -> i32 { + return 4; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatCycle4 { + return AnticheatCycle4::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatCycle5 {} + +impl AnticheatCycle5 { + const DEFAULT: AnticheatCycle5 = AnticheatCycle5::new(); + + #[inline] + pub const fn new() -> AnticheatCycle5 { + return AnticheatCycle5 {}; + } +} + +impl MessageDecoder for AnticheatCycle5 { + #[inline] + fn length() -> i32 { + return 0; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatCycle5 { + return AnticheatCycle5::DEFAULT; + } +} + +// ---- + +#[wasm_bindgen] +pub struct AnticheatCycle6 {} + +impl AnticheatCycle6 { + const DEFAULT: AnticheatCycle6 = AnticheatCycle6::new(); + + #[inline] + pub const fn new() -> AnticheatCycle6 { + return AnticheatCycle6 {}; + } +} + +impl MessageDecoder for AnticheatCycle6 { + #[inline] + fn length() -> i32 { + return -1; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> AnticheatCycle6 { + return AnticheatCycle6::DEFAULT; + } +} \ No newline at end of file diff --git a/src/in/chat_setmode.rs b/src/in/chat_setmode.rs new file mode 100644 index 0000000..027a6dd --- /dev/null +++ b/src/in/chat_setmode.rs @@ -0,0 +1,45 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct ChatSetMode { + #[wasm_bindgen(readonly)] + pub public: u8, + #[wasm_bindgen(readonly)] + pub private: u8, + #[wasm_bindgen(readonly)] + pub trade: u8, +} + +impl ChatSetMode { + #[inline] + pub fn new( + public: u8, + private: u8, + trade: u8, + ) -> ChatSetMode { + return ChatSetMode { + public, + private, + trade, + } + } +} + +impl MessageDecoder for ChatSetMode { + #[inline] + fn length() -> i32 { + return 3; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> ChatSetMode { + return ChatSetMode::new( + buf.g1(), + buf.g1(), + buf.g1(), + ); + } +} \ No newline at end of file diff --git a/src/in/client_cheat.rs b/src/in/client_cheat.rs new file mode 100644 index 0000000..974f2ee --- /dev/null +++ b/src/in/client_cheat.rs @@ -0,0 +1,31 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct ClientCheat { + #[wasm_bindgen(getter_with_clone, readonly)] + pub input: String, +} + +impl ClientCheat { + #[inline] + pub fn new(input: String) -> ClientCheat { + return ClientCheat { + input, + } + } +} + +impl MessageDecoder for ClientCheat { + #[inline] + fn length() -> i32 { + return -1; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> ClientCheat { + return ClientCheat::new(buf.gjstr(10)); + } +} \ No newline at end of file diff --git a/src/in/close_modal.rs b/src/in/close_modal.rs new file mode 100644 index 0000000..9e6bc87 --- /dev/null +++ b/src/in/close_modal.rs @@ -0,0 +1,28 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct CloseModal {} + +impl CloseModal { + const DEFAULT: CloseModal = CloseModal::new(); + + #[inline] + pub const fn new() -> CloseModal { + return CloseModal {} + } +} + +impl MessageDecoder for CloseModal { + #[inline] + fn length() -> i32 { + return 0; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> CloseModal { + return CloseModal::DEFAULT; + } +} \ No newline at end of file diff --git a/src/in/event.rs b/src/in/event.rs new file mode 100644 index 0000000..a6d2837 --- /dev/null +++ b/src/in/event.rs @@ -0,0 +1,79 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct EventTracking { + #[wasm_bindgen(getter_with_clone, readonly)] + pub bytes: Vec, +} + +impl EventTracking { + #[inline] + pub fn new(bytes: Vec) -> EventTracking { + return EventTracking { + bytes, + } + } +} + +impl MessageDecoder for EventTracking { + #[inline] + fn length() -> i32 { + return -2; + } + + #[inline] + fn decode(_: ClientProt, buf: Packet) -> EventTracking { + return EventTracking::new(buf.data.clone()); + } +} + +// ---- + +#[wasm_bindgen] +pub struct EventCameraPosition { + #[wasm_bindgen(readonly)] + pub pitch: i32, + #[wasm_bindgen(readonly)] + pub yaw: i32, + #[wasm_bindgen(readonly)] + pub angle: i32, + #[wasm_bindgen(readonly)] + pub zoom: i32, +} + +impl EventCameraPosition { + #[inline] + pub fn new( + pitch: i32, + yaw: i32, + angle: i32, + zoom: i32, + ) -> EventCameraPosition { + return EventCameraPosition { + pitch, + yaw, + angle, + zoom, + } + } +} + +impl MessageDecoder for EventCameraPosition { + #[inline] + fn length() -> i32 { + return 6; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> EventCameraPosition { + return EventCameraPosition::new( + buf.g2() as i32, + buf.g2() as i32, + buf.g1() as i32, + buf.g1() as i32, + ); + } +} \ No newline at end of file diff --git a/src/in/friend.rs b/src/in/friend.rs new file mode 100644 index 0000000..7143182 --- /dev/null +++ b/src/in/friend.rs @@ -0,0 +1,60 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct FriendListAdd { + #[wasm_bindgen(readonly)] + pub username: i64, +} + +impl FriendListAdd { + #[inline] + pub fn new(username: i64) -> FriendListAdd { + return FriendListAdd { + username, + } + } +} + +impl MessageDecoder for FriendListAdd { + #[inline] + fn length() -> i32 { + return 8; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> FriendListAdd { + return FriendListAdd::new(buf.g8s()); + } +} + +// ---- + +#[wasm_bindgen] +pub struct FriendListDel { + #[wasm_bindgen(readonly)] + pub username: i64, +} + +impl FriendListDel { + #[inline] + pub fn new(username: i64) -> FriendListDel { + return FriendListDel { + username, + } + } +} + +impl MessageDecoder for FriendListDel { + #[inline] + fn length() -> i32 { + return 8; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> FriendListDel { + return FriendListDel::new(buf.g8s()); + } +} \ No newline at end of file diff --git a/src/in/idle_timer.rs b/src/in/idle_timer.rs new file mode 100644 index 0000000..495089d --- /dev/null +++ b/src/in/idle_timer.rs @@ -0,0 +1,28 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct IdleTimer {} + +impl IdleTimer { + const DEFAULT: IdleTimer = IdleTimer::new(); + + #[inline] + pub const fn new() -> IdleTimer { + return IdleTimer {} + } +} + +impl MessageDecoder for IdleTimer { + #[inline] + fn length() -> i32 { + return 0; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> IdleTimer { + return IdleTimer::DEFAULT; + } +} \ No newline at end of file diff --git a/src/in/if_button.rs b/src/in/if_button.rs new file mode 100644 index 0000000..810fe74 --- /dev/null +++ b/src/in/if_button.rs @@ -0,0 +1,31 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct IfButton { + #[wasm_bindgen(readonly)] + pub component: u16, +} + +impl IfButton { + #[inline] + pub fn new(component: u16) -> IfButton { + return IfButton { + component, + } + } +} + +impl MessageDecoder for IfButton { + #[inline] + fn length() -> i32 { + return 2; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> IfButton { + return IfButton::new(buf.g2()); + } +} \ No newline at end of file diff --git a/src/in/if_playerdesign.rs b/src/in/if_playerdesign.rs new file mode 100644 index 0000000..a3f4149 --- /dev/null +++ b/src/in/if_playerdesign.rs @@ -0,0 +1,57 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct IfPlayerDesign { + #[wasm_bindgen(readonly)] + pub gender: u8, + #[wasm_bindgen(getter_with_clone, readonly)] + pub idkit: Vec, + #[wasm_bindgen(getter_with_clone, readonly)] + pub color: Vec, +} + +impl IfPlayerDesign { + #[inline] + pub fn new( + gender: u8, + idkit: Vec, + color: Vec + ) -> IfPlayerDesign { + return IfPlayerDesign { + gender, + idkit, + color, + } + } +} + +impl MessageDecoder for IfPlayerDesign { + #[inline] + fn length() -> i32 { + return 13; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> IfPlayerDesign { + let gender: u8 = buf.g1(); + + let mut idkit: [i32; 7] = [0; 7]; + for i in 0..7 { + let mut v = buf.g1() as i32; + if v == 0xff { + v = -1; + } + unsafe { *idkit.as_mut_ptr().add(i as usize) = v }; + } + + let mut color: [i32; 5] = [0; 5]; + for i in 0..5 { + unsafe { *color.as_mut_ptr().add(i as usize) = buf.g1() as i32 }; + } + + return IfPlayerDesign::new(gender, idkit.to_vec(), color.to_vec()); + } +} \ No newline at end of file diff --git a/src/in/ignore.rs b/src/in/ignore.rs new file mode 100644 index 0000000..17c40c2 --- /dev/null +++ b/src/in/ignore.rs @@ -0,0 +1,60 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct IgnoreListAdd { + #[wasm_bindgen(readonly)] + pub username: i64, +} + +impl IgnoreListAdd { + #[inline] + pub fn new(username: i64) -> IgnoreListAdd { + return IgnoreListAdd { + username, + } + } +} + +impl MessageDecoder for IgnoreListAdd { + #[inline] + fn length() -> i32 { + return 8; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> IgnoreListAdd { + return IgnoreListAdd::new(buf.g8s()); + } +} + +// ---- + +#[wasm_bindgen] +pub struct IgnoreListDel { + #[wasm_bindgen(readonly)] + pub username: i64, +} + +impl IgnoreListDel { + #[inline] + pub fn new(username: i64) -> IgnoreListDel { + return IgnoreListDel { + username, + } + } +} + +impl MessageDecoder for IgnoreListDel { + #[inline] + fn length() -> i32 { + return 8; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> IgnoreListDel { + return IgnoreListDel::new(buf.g8s()); + } +} \ No newline at end of file diff --git a/src/in/inv_button.rs b/src/in/inv_button.rs new file mode 100644 index 0000000..d560d15 --- /dev/null +++ b/src/in/inv_button.rs @@ -0,0 +1,101 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct InvButton { + #[wasm_bindgen(readonly)] + pub op: u8, + #[wasm_bindgen(readonly)] + pub obj: u16, + #[wasm_bindgen(readonly)] + pub slot: u16, + #[wasm_bindgen(readonly)] + pub component: u16, +} + +impl InvButton { + #[inline] + pub fn new( + op: u8, + obj: u16, + slot: u16, + component: u16, + ) -> InvButton { + return InvButton { + op, + obj, + slot, + component, + } + } +} + +impl MessageDecoder for InvButton { + #[inline] + fn length() -> i32 { + return 6; + } + + #[inline] + fn decode(prot: ClientProt, mut buf: Packet) -> InvButton { + let op: u8 = match prot { + ClientProt::INV_BUTTON1 => 1, + ClientProt::INV_BUTTON2 => 2, + ClientProt::INV_BUTTON3 => 3, + ClientProt::INV_BUTTON4 => 4, + ClientProt::INV_BUTTON5 => 5, + _ => 0, + }; + return InvButton::new( + op, + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} + +// ---- + +#[wasm_bindgen] +pub struct InvButtonD { + #[wasm_bindgen(readonly)] + pub component: u16, + #[wasm_bindgen(readonly)] + pub slot: u16, + #[wasm_bindgen(readonly)] + pub target: u16, +} + +impl InvButtonD { + #[inline] + pub fn new( + component: u16, + slot: u16, + target: u16, + ) -> InvButtonD { + return InvButtonD { + component, + slot, + target, + } + } +} + +impl MessageDecoder for InvButtonD { + #[inline] + fn length() -> i32 { + return 6; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> InvButtonD { + return InvButtonD::new( + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} \ No newline at end of file diff --git a/src/in/message_private.rs b/src/in/message_private.rs new file mode 100644 index 0000000..1e83f66 --- /dev/null +++ b/src/in/message_private.rs @@ -0,0 +1,40 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct MessagePrivate { + #[wasm_bindgen(readonly)] + pub username: i64, + #[wasm_bindgen(getter_with_clone, readonly)] + pub input: Vec, +} + +impl MessagePrivate { + #[inline] + pub fn new( + username: i64, + input: Vec, + ) -> MessagePrivate { + return MessagePrivate { + username, + input, + } + } +} + +impl MessageDecoder for MessagePrivate { + #[inline] + fn length() -> i32 { + return -1; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> MessagePrivate { + return MessagePrivate::new( + buf.g8s(), + unsafe { buf.data.get_unchecked(buf.pos..buf.pos + buf.data.len() - 8).to_vec() } + ); + } +} \ No newline at end of file diff --git a/src/in/message_public.rs b/src/in/message_public.rs new file mode 100644 index 0000000..8abe363 --- /dev/null +++ b/src/in/message_public.rs @@ -0,0 +1,45 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct MessagePublic { + #[wasm_bindgen(readonly)] + pub color: u8, + #[wasm_bindgen(readonly)] + pub effect: u8, + #[wasm_bindgen(getter_with_clone, readonly)] + pub input: Vec, +} + +impl MessagePublic { + #[inline] + pub fn new( + color: u8, + effect: u8, + input: Vec, + ) -> MessagePublic { + return MessagePublic { + color, + effect, + input, + } + } +} + +impl MessageDecoder for MessagePublic { + #[inline] + fn length() -> i32 { + return -1; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> MessagePublic { + return MessagePublic::new( + buf.g1(), + buf.g1(), + unsafe { buf.data.get_unchecked(buf.pos..buf.pos + buf.data.len() - 2).to_vec() } + ); + } +} \ No newline at end of file diff --git a/src/in/mod.rs b/src/in/mod.rs new file mode 100644 index 0000000..6ae4a5d --- /dev/null +++ b/src/in/mod.rs @@ -0,0 +1,25 @@ +pub mod client_cheat; +pub mod close_modal; +pub mod friend; +pub mod idle_timer; +pub mod if_button; +pub mod if_playerdesign; +pub mod ignore; +pub mod inv_button; +pub mod message_private; +pub mod message_public; +pub mod move_click; +pub mod no_timeout; +pub mod opheld; +pub mod oploc; +pub mod opnpc; +pub mod opobj; +pub mod opplayer; +pub mod rebuild_getmaps; +pub mod resume_pausebutton; +pub mod resume_countdialog; +pub mod tutorial_clickside; +pub mod chat_setmode; +pub mod reportabuse; +pub mod event; +pub mod anticheat; \ No newline at end of file diff --git a/src/in/move_click.rs b/src/in/move_click.rs new file mode 100644 index 0000000..ecab521 --- /dev/null +++ b/src/in/move_click.rs @@ -0,0 +1,63 @@ +use crate::coord::CoordGrid; +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct MoveClick { + #[wasm_bindgen(readonly)] + pub ctrl: bool, + #[wasm_bindgen(readonly)] + pub op: bool, + #[wasm_bindgen(getter_with_clone, readonly)] + pub path: Vec, +} + +impl MoveClick { + #[inline] + pub fn new( + ctrl: bool, + op: bool, + path: Vec, + ) -> MoveClick { + return MoveClick { + ctrl, + op, + path, + } + } +} + +impl MessageDecoder for MoveClick { + #[inline] + fn length() -> i32 { + return -1; + } + + #[inline] + fn decode(prot: ClientProt, mut buf: Packet) -> MoveClick { + let ctrl: bool = buf.g1() == 1; + let x: u16 = buf.g2(); + let z: u16 = buf.g2(); + + let offset: usize = if prot == ClientProt::MOVE_MINIMAPCLICK { 14 } else { 0 }; + let waypoints: usize = ((buf.data.len() - buf.pos - offset) / 2) + 1; + + let mut path: Vec = vec![0; waypoints]; + path[0] = CoordGrid::from(x, 0, z).packed; + + for index in 1..waypoints { + if index >= 25 { + break; + } + unsafe { *path.as_mut_ptr().add(index) = CoordGrid::from(x + buf.g1s() as u16, 0, z + buf.g1s() as u16).packed }; + } + + return MoveClick::new( + ctrl, + prot == ClientProt::MOVE_OPCLICK, + path, + ); + } +} \ No newline at end of file diff --git a/src/in/no_timeout.rs b/src/in/no_timeout.rs new file mode 100644 index 0000000..a2c581d --- /dev/null +++ b/src/in/no_timeout.rs @@ -0,0 +1,28 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct NoTimeout {} + +impl NoTimeout { + const DEFAULT: NoTimeout = NoTimeout::new(); + + #[inline] + pub const fn new() -> NoTimeout { + return NoTimeout {}; + } +} + +impl MessageDecoder for NoTimeout { + #[inline] + fn length() -> i32 { + return 0; + } + + #[inline] + fn decode(_: ClientProt, _: Packet) -> NoTimeout { + return NoTimeout::DEFAULT; + } +} \ No newline at end of file diff --git a/src/in/opheld.rs b/src/in/opheld.rs new file mode 100644 index 0000000..44829dd --- /dev/null +++ b/src/in/opheld.rs @@ -0,0 +1,164 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct OpHeld { + #[wasm_bindgen(readonly)] + pub op: u8, + #[wasm_bindgen(readonly)] + pub obj: u16, + #[wasm_bindgen(readonly)] + pub slot: u16, + #[wasm_bindgen(readonly)] + pub component: u16, +} + +impl OpHeld { + #[inline] + pub fn new( + op: u8, + obj: u16, + slot: u16, + component: u16, + ) -> OpHeld { + return OpHeld { + op, + obj, + slot, + component, + } + } +} + +impl MessageDecoder for OpHeld { + #[inline] + fn length() -> i32 { + return 6; + } + + #[inline] + fn decode(prot: ClientProt, mut buf: Packet) -> OpHeld { + let op: u8 = match prot { + ClientProt::OPHELD1 => 1, + ClientProt::OPHELD2 => 2, + ClientProt::OPHELD3 => 3, + ClientProt::OPHELD4 => 4, + ClientProt::OPHELD5 => 5, + _ => 0, + }; + return OpHeld::new( + op, + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} + +// ---- + +#[wasm_bindgen] +pub struct OpHeldT { + #[wasm_bindgen(readonly)] + pub obj: u16, + #[wasm_bindgen(readonly)] + pub slot: u16, + #[wasm_bindgen(readonly)] + pub component: u16, + #[wasm_bindgen(readonly)] + pub spell: u16, +} + +impl OpHeldT { + #[inline] + pub fn new( + obj: u16, + slot: u16, + component: u16, + spell: u16, + ) -> OpHeldT { + return OpHeldT { + obj, + slot, + component, + spell, + } + } +} + +impl MessageDecoder for OpHeldT { + #[inline] + fn length() -> i32 { + return 8; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> OpHeldT { + return OpHeldT::new( + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} + +// ---- + +#[wasm_bindgen] +pub struct OpHeldU { + #[wasm_bindgen(readonly)] + pub obj: u16, + #[wasm_bindgen(readonly)] + pub slot: u16, + #[wasm_bindgen(readonly)] + pub component: u16, + #[wasm_bindgen(readonly, js_name = useObj)] + pub use_obj: u16, + #[wasm_bindgen(readonly, js_name = useSlot)] + pub use_slot: u16, + #[wasm_bindgen(readonly, js_name = useComponent)] + pub use_component: u16, +} + +impl OpHeldU { + #[inline] + pub fn new( + obj: u16, + slot: u16, + component: u16, + use_obj: u16, + use_slot: u16, + use_component: u16, + ) -> OpHeldU { + return OpHeldU { + obj, + slot, + component, + use_obj, + use_slot, + use_component, + } + } +} + +impl MessageDecoder for OpHeldU { + #[inline] + fn length() -> i32 { + return 12; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> OpHeldU { + return OpHeldU::new( + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} \ No newline at end of file diff --git a/src/in/oploc.rs b/src/in/oploc.rs new file mode 100644 index 0000000..d055c45 --- /dev/null +++ b/src/in/oploc.rs @@ -0,0 +1,164 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct OpLoc { + #[wasm_bindgen(readonly)] + pub op: u8, + #[wasm_bindgen(readonly)] + pub x: u16, + #[wasm_bindgen(readonly)] + pub z: u16, + #[wasm_bindgen(readonly)] + pub loc: u16, +} + +impl OpLoc { + #[inline] + pub fn new( + op: u8, + x: u16, + z: u16, + loc: u16, + ) -> OpLoc { + return OpLoc { + op, + x, + z, + loc, + } + } +} + +impl MessageDecoder for OpLoc { + #[inline] + fn length() -> i32 { + return 6; + } + + #[inline] + fn decode(prot: ClientProt, mut buf: Packet) -> OpLoc { + let op: u8 = match prot { + ClientProt::OPLOC1 => 1, + ClientProt::OPLOC2 => 2, + ClientProt::OPLOC3 => 3, + ClientProt::OPLOC4 => 4, + ClientProt::OPLOC5 => 5, + _ => 0, + }; + return OpLoc::new( + op, + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} + +// ---- + +#[wasm_bindgen] +pub struct OpLocT { + #[wasm_bindgen(readonly)] + pub x: u16, + #[wasm_bindgen(readonly)] + pub z: u16, + #[wasm_bindgen(readonly)] + pub loc: u16, + #[wasm_bindgen(readonly)] + pub spell: u16, +} + +impl OpLocT { + #[inline] + pub fn new( + x: u16, + z: u16, + loc: u16, + spell: u16, + ) -> OpLocT { + return OpLocT { + x, + z, + loc, + spell, + } + } +} + +impl MessageDecoder for OpLocT { + #[inline] + fn length() -> i32 { + return 8; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> OpLocT { + return OpLocT::new( + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} + +// ---- + +#[wasm_bindgen] +pub struct OpLocU { + #[wasm_bindgen(readonly)] + pub x: u16, + #[wasm_bindgen(readonly)] + pub z: u16, + #[wasm_bindgen(readonly)] + pub loc: u16, + #[wasm_bindgen(readonly, js_name = useObj)] + pub use_obj: u16, + #[wasm_bindgen(readonly, js_name = useSlot)] + pub use_slot: u16, + #[wasm_bindgen(readonly, js_name = useComponent)] + pub use_component: u16, +} + +impl OpLocU { + #[inline] + pub fn new( + x: u16, + z: u16, + loc: u16, + use_obj: u16, + use_slot: u16, + use_component: u16, + ) -> OpLocU { + return OpLocU { + x, + z, + loc, + use_obj, + use_slot, + use_component, + } + } +} + +impl MessageDecoder for OpLocU { + #[inline] + fn length() -> i32 { + return 12; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> OpLocU { + return OpLocU::new( + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} \ No newline at end of file diff --git a/src/in/opnpc.rs b/src/in/opnpc.rs new file mode 100644 index 0000000..7b83c8e --- /dev/null +++ b/src/in/opnpc.rs @@ -0,0 +1,134 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct OpNpc { + #[wasm_bindgen(readonly)] + pub op: u8, + #[wasm_bindgen(readonly)] + pub nid: u16, +} + +impl OpNpc { + #[inline] + pub fn new( + op: u8, + nid: u16, + ) -> OpNpc { + return OpNpc { + op, + nid, + } + } +} + +impl MessageDecoder for OpNpc { + #[inline] + fn length() -> i32 { + return 2; + } + + #[inline] + fn decode(prot: ClientProt, mut buf: Packet) -> OpNpc { + let op: u8 = match prot { + ClientProt::OPNPC1 => 1, + ClientProt::OPNPC2 => 2, + ClientProt::OPNPC3 => 3, + ClientProt::OPNPC4 => 4, + ClientProt::OPNPC5 => 5, + _ => 0, + }; + return OpNpc::new( + op, + buf.g2(), + ); + } +} + +// ---- + +#[wasm_bindgen] +pub struct OpNpcT { + #[wasm_bindgen(readonly)] + pub nid: u16, + #[wasm_bindgen(readonly)] + pub spell: u16, +} + +impl OpNpcT { + #[inline] + pub fn new( + nid: u16, + spell: u16, + ) -> OpNpcT { + return OpNpcT { + nid, + spell, + } + } +} + +impl MessageDecoder for OpNpcT { + #[inline] + fn length() -> i32 { + return 4; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> OpNpcT { + return OpNpcT::new( + buf.g2(), + buf.g2(), + ); + } +} + +// ---- + +#[wasm_bindgen] +pub struct OpNpcU { + #[wasm_bindgen(readonly)] + pub nid: u16, + #[wasm_bindgen(readonly, js_name = useObj)] + pub use_obj: u16, + #[wasm_bindgen(readonly, js_name = useSlot)] + pub use_slot: u16, + #[wasm_bindgen(readonly, js_name = useComponent)] + pub use_component: u16, +} + +impl OpNpcU { + #[inline] + pub fn new( + nid: u16, + use_obj: u16, + use_slot: u16, + use_component: u16, + ) -> OpNpcU { + return OpNpcU { + nid, + use_obj, + use_slot, + use_component, + } + } +} + +impl MessageDecoder for OpNpcU { + #[inline] + fn length() -> i32 { + return 8; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> OpNpcU { + return OpNpcU::new( + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} \ No newline at end of file diff --git a/src/in/opobj.rs b/src/in/opobj.rs new file mode 100644 index 0000000..1a8de8f --- /dev/null +++ b/src/in/opobj.rs @@ -0,0 +1,164 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct OpObj { + #[wasm_bindgen(readonly)] + pub op: u8, + #[wasm_bindgen(readonly)] + pub x: u16, + #[wasm_bindgen(readonly)] + pub z: u16, + #[wasm_bindgen(readonly)] + pub obj: u16, +} + +impl OpObj { + #[inline] + pub fn new( + op: u8, + x: u16, + z: u16, + obj: u16, + ) -> OpObj { + return OpObj { + op, + x, + z, + obj, + } + } +} + +impl MessageDecoder for OpObj { + #[inline] + fn length() -> i32 { + return 6; + } + + #[inline] + fn decode(prot: ClientProt, mut buf: Packet) -> OpObj { + let op: u8 = match prot { + ClientProt::OPOBJ1 => 1, + ClientProt::OPOBJ2 => 2, + ClientProt::OPOBJ3 => 3, + ClientProt::OPOBJ4 => 4, + ClientProt::OPOBJ5 => 5, + _ => 0, + }; + return OpObj::new( + op, + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} + +// ---- + +#[wasm_bindgen] +pub struct OpObjT { + #[wasm_bindgen(readonly)] + pub x: u16, + #[wasm_bindgen(readonly)] + pub z: u16, + #[wasm_bindgen(readonly)] + pub obj: u16, + #[wasm_bindgen(readonly)] + pub spell: u16, +} + +impl OpObjT { + #[inline] + pub fn new( + x: u16, + z: u16, + obj: u16, + spell: u16, + ) -> OpObjT { + return OpObjT { + x, + z, + obj, + spell, + } + } +} + +impl MessageDecoder for OpObjT { + #[inline] + fn length() -> i32 { + return 8; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> OpObjT { + return OpObjT::new( + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} + +// ---- + +#[wasm_bindgen] +pub struct OpObjU { + #[wasm_bindgen(readonly)] + pub x: u16, + #[wasm_bindgen(readonly)] + pub z: u16, + #[wasm_bindgen(readonly)] + pub obj: u16, + #[wasm_bindgen(readonly, js_name = useObj)] + pub use_obj: u16, + #[wasm_bindgen(readonly, js_name = useSlot)] + pub use_slot: u16, + #[wasm_bindgen(readonly, js_name = useComponent)] + pub use_component: u16, +} + +impl OpObjU { + #[inline] + pub fn new( + x: u16, + z: u16, + obj: u16, + use_obj: u16, + use_slot: u16, + use_component: u16, + ) -> OpObjU { + return OpObjU { + x, + z, + obj, + use_obj, + use_slot, + use_component, + } + } +} + +impl MessageDecoder for OpObjU { + #[inline] + fn length() -> i32 { + return 12; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> OpObjU { + return OpObjU::new( + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} \ No newline at end of file diff --git a/src/in/opplayer.rs b/src/in/opplayer.rs new file mode 100644 index 0000000..d226271 --- /dev/null +++ b/src/in/opplayer.rs @@ -0,0 +1,133 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct OpPlayer { + #[wasm_bindgen(readonly)] + pub op: u8, + #[wasm_bindgen(readonly)] + pub pid: u16, +} + +impl OpPlayer { + #[inline] + pub fn new( + op: u8, + pid: u16, + ) -> OpPlayer { + return OpPlayer { + op, + pid, + } + } +} + +impl MessageDecoder for OpPlayer { + #[inline] + fn length() -> i32 { + return 2; + } + + #[inline] + fn decode(prot: ClientProt, mut buf: Packet) -> OpPlayer { + let op: u8 = match prot { + ClientProt::OPPLAYER1 => 1, + ClientProt::OPPLAYER2 => 2, + ClientProt::OPPLAYER3 => 3, + ClientProt::OPPLAYER4 => 4, + _ => 0, + }; + return OpPlayer::new( + op, + buf.g2(), + ); + } +} + +// ---- + +#[wasm_bindgen] +pub struct OpPlayerT { + #[wasm_bindgen(readonly)] + pub pid: u16, + #[wasm_bindgen(readonly)] + pub spell: u16, +} + +impl OpPlayerT { + #[inline] + pub fn new( + pid: u16, + spell: u16, + ) -> OpPlayerT { + return OpPlayerT { + pid, + spell, + } + } +} + +impl MessageDecoder for OpPlayerT { + #[inline] + fn length() -> i32 { + return 4; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> OpPlayerT { + return OpPlayerT::new( + buf.g2(), + buf.g2(), + ); + } +} + +// ---- + +#[wasm_bindgen] +pub struct OpPlayerU { + #[wasm_bindgen(readonly)] + pub pid: u16, + #[wasm_bindgen(readonly, js_name = useObj)] + pub use_obj: u16, + #[wasm_bindgen(readonly, js_name = useSlot)] + pub use_slot: u16, + #[wasm_bindgen(readonly, js_name = useComponent)] + pub use_component: u16, +} + +impl OpPlayerU { + #[inline] + pub fn new( + pid: u16, + use_obj: u16, + use_slot: u16, + use_component: u16, + ) -> OpPlayerU { + return OpPlayerU { + pid, + use_obj, + use_slot, + use_component, + } + } +} + +impl MessageDecoder for OpPlayerU { + #[inline] + fn length() -> i32 { + return 8; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> OpPlayerU { + return OpPlayerU::new( + buf.g2(), + buf.g2(), + buf.g2(), + buf.g2(), + ); + } +} \ No newline at end of file diff --git a/src/in/rebuild_getmaps.rs b/src/in/rebuild_getmaps.rs new file mode 100644 index 0000000..6fe829c --- /dev/null +++ b/src/in/rebuild_getmaps.rs @@ -0,0 +1,35 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct RebuildGetMaps { + #[wasm_bindgen(getter_with_clone, readonly)] + pub maps: Vec, +} + +impl RebuildGetMaps { + #[inline] + pub fn new(maps: Vec) -> RebuildGetMaps { + return RebuildGetMaps { + maps, + } + } +} + +impl MessageDecoder for RebuildGetMaps { + #[inline] + fn length() -> i32 { + return -1; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> RebuildGetMaps { + let mut maps: Vec = vec![0; buf.data.len() / 3]; + for index in 0..maps.len() { + unsafe { *maps.as_mut_ptr().add(index) = buf.g3() as u32 }; + } + return RebuildGetMaps::new(maps); + } +} \ No newline at end of file diff --git a/src/in/reportabuse.rs b/src/in/reportabuse.rs new file mode 100644 index 0000000..6223bc2 --- /dev/null +++ b/src/in/reportabuse.rs @@ -0,0 +1,45 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct ReportAbuse { + #[wasm_bindgen(readonly)] + pub offender: i64, + #[wasm_bindgen(readonly)] + pub reason: u8, + #[wasm_bindgen(readonly)] + pub mute: bool, +} + +impl ReportAbuse { + #[inline] + pub fn new( + offender: i64, + reason: u8, + mute: bool, + ) -> ReportAbuse { + return ReportAbuse { + offender, + reason, + mute, + } + } +} + +impl MessageDecoder for ReportAbuse { + #[inline] + fn length() -> i32 { + return 10; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> ReportAbuse { + return ReportAbuse::new( + buf.g8s(), + buf.g1(), + buf.g1() == 1, + ); + } +} \ No newline at end of file diff --git a/src/in/resume_countdialog.rs b/src/in/resume_countdialog.rs new file mode 100644 index 0000000..300d6d0 --- /dev/null +++ b/src/in/resume_countdialog.rs @@ -0,0 +1,31 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct ResumePCountDialog { + #[wasm_bindgen(readonly)] + pub input: i32, +} + +impl ResumePCountDialog { + #[inline] + pub fn new(input: i32) -> ResumePCountDialog { + return ResumePCountDialog { + input, + } + } +} + +impl MessageDecoder for ResumePCountDialog { + #[inline] + fn length() -> i32 { + return 4; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> ResumePCountDialog { + return ResumePCountDialog::new(buf.g4s()); + } +} \ No newline at end of file diff --git a/src/in/resume_pausebutton.rs b/src/in/resume_pausebutton.rs new file mode 100644 index 0000000..c9b232c --- /dev/null +++ b/src/in/resume_pausebutton.rs @@ -0,0 +1,31 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct ResumePauseButton { + #[wasm_bindgen(readonly)] + pub component: u16, +} + +impl ResumePauseButton { + #[inline] + pub fn new(component: u16) -> ResumePauseButton { + return ResumePauseButton { + component, + }; + } +} + +impl MessageDecoder for ResumePauseButton { + #[inline] + fn length() -> i32 { + return 2; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> ResumePauseButton { + return ResumePauseButton::new(buf.g2()); + } +} \ No newline at end of file diff --git a/src/in/tutorial_clickside.rs b/src/in/tutorial_clickside.rs new file mode 100644 index 0000000..3583a26 --- /dev/null +++ b/src/in/tutorial_clickside.rs @@ -0,0 +1,31 @@ +use crate::message::MessageDecoder; +use crate::packet::Packet; +use crate::prot::ClientProt; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct TutorialClickSide { + #[wasm_bindgen(readonly)] + pub tab: u8, +} + +impl TutorialClickSide { + #[inline] + pub fn new(tab: u8) -> TutorialClickSide { + return TutorialClickSide { + tab, + } + } +} + +impl MessageDecoder for TutorialClickSide { + #[inline] + fn length() -> i32 { + return 1; + } + + #[inline] + fn decode(_: ClientProt, mut buf: Packet) -> TutorialClickSide { + return TutorialClickSide::new(buf.g1()); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 811e758..182c33f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,12 +2,110 @@ use crate::coord::CoordGrid; use crate::grid::ZoneMap; -use crate::info::{NpcInfo, PlayerInfo}; +use crate::message::{IncomingPacket, MessageDecoder}; use crate::npc::Npc; +use crate::out::cam_lookat::CamLookAt; +use crate::out::cam_moveto::CamMoveTo; +use crate::out::cam_reset::CamReset; +use crate::out::cam_shake::CamShake; +use crate::out::chat_filter_settings::ChatFilterSettings; +use crate::out::count_dialog::PCountDialog; +use crate::out::data_land::{DataLand, DataLandDone}; +use crate::out::data_loc::{DataLoc, DataLocDone}; +use crate::out::enable_tracking::EnableTracking; +use crate::out::finish_tracking::FinishTracking; +use crate::out::hint_arrow::HintArrow; +use crate::out::if_close::IfClose; +use crate::out::if_openchat::IfOpenChat; +use crate::out::if_openmain::IfOpenMain; +use crate::out::if_openmainside::IfOpenMainSide; +use crate::out::if_openside::IfOpenSide; +use crate::out::if_setanim::IfSetAnim; +use crate::out::if_setcolour::IfSetColour; +use crate::out::if_sethide::IfSetHide; +use crate::out::if_setmodel::IfSetModel; +use crate::out::if_setnpchead::IfSetNpcHead; +use crate::out::if_setobject::IfSetObject; +use crate::out::if_setplayerhead::IfSetPlayerHead; +use crate::out::if_setposition::IfSetPosition; +use crate::out::if_setrecol::IfSetRecol; +use crate::out::if_settab::IfSetTab; +use crate::out::if_settabactive::IfSetTabActive; +use crate::out::if_settext::IfSetText; +use crate::out::last_login_info::LastLoginInfo; +use crate::out::loc_addchange::LocAddChange; +use crate::out::loc_anim::LocAnim; +use crate::out::loc_del::LocDel; +use crate::out::loc_merge::LocMerge; +use crate::out::logout::Logout; +use crate::out::map_anim::MapAnim; +use crate::out::map_projanim::MapProjAnim; +use crate::out::message_game::MessageGame; +use crate::out::message_private::MessagePrivateOut; +use crate::out::midi_jingle::MidiJingle; +use crate::out::midi_song::MidiSong; +use crate::out::npc_info::NpcInfo; +use crate::out::obj_add::ObjAdd; +use crate::out::obj_count::ObjCount; +use crate::out::obj_del::ObjDel; +use crate::out::obj_reveal::ObjReveal; +use crate::out::rebuild_normal::RebuildNormal; +use crate::out::reset_anims::ResetAnims; +use crate::out::reset_clientvarcache::ResetClientVarCache; +use crate::out::set_multiway::SetMultiway; +use crate::out::synth_sound::SynthSound; +use crate::out::tut_flash::TutFlash; +use crate::out::tut_open::TutOpen; +use crate::out::unset_map_flag::UnsetMapFlag; +use crate::out::update_friendlist::UpdateFriendList; +use crate::out::update_ignorelist::UpdateIgnoreList; +use crate::out::update_inv_full::UpdateInvFull; +use crate::out::update_inv_partial::UpdateInvPartial; +use crate::out::update_inv_stop_transmit::UpdateInvStopTransmit; +use crate::out::update_pid::UpdatePid; +use crate::out::update_reboot_timer::UpdateRebootTimer; +use crate::out::update_runenergy::UpdateRunEnergy; +use crate::out::update_runweight::UpdateRunWeight; +use crate::out::update_stat::UpdateStat; +use crate::out::update_zone_full_follows::UpdateZoneFullFollows; +use crate::out::update_zone_partial_enclosed::UpdateZonePartialEnclosed; +use crate::out::update_zone_partial_follows::UpdateZonePartialFollows; +use crate::out::varp_large::VarpLarge; +use crate::out::varp_small::VarpSmall; +use crate::packet::Packet; use crate::player::{Chat, ExactMove, Player}; +use crate::pool::PacketPool; +use crate::prot::{ClientInternalProt, ClientProt, ServerInternalProt}; +use crate::r#in::anticheat::{AnticheatCycle1, AnticheatCycle2, AnticheatCycle3, AnticheatCycle4, AnticheatCycle5, AnticheatCycle6, AnticheatOp1, AnticheatOp2, AnticheatOp3, AnticheatOp4, AnticheatOp5, AnticheatOp6, AnticheatOp7, AnticheatOp8, AnticheatOp9}; +use crate::r#in::chat_setmode::ChatSetMode; +use crate::r#in::client_cheat::ClientCheat; +use crate::r#in::close_modal::CloseModal; +use crate::r#in::event::{EventCameraPosition, EventTracking}; +use crate::r#in::friend::{FriendListAdd, FriendListDel}; +use crate::r#in::idle_timer::IdleTimer; +use crate::r#in::if_button::IfButton; +use crate::r#in::if_playerdesign::IfPlayerDesign; +use crate::r#in::ignore::{IgnoreListAdd, IgnoreListDel}; +use crate::r#in::inv_button::{InvButton, InvButtonD}; +use crate::r#in::message_private::MessagePrivate; +use crate::r#in::message_public::MessagePublic; +use crate::r#in::move_click::MoveClick; +use crate::r#in::no_timeout::NoTimeout; +use crate::r#in::opheld::{OpHeld, OpHeldT, OpHeldU}; +use crate::r#in::oploc::{OpLoc, OpLocT, OpLocU}; +use crate::r#in::opnpc::{OpNpc, OpNpcT, OpNpcU}; +use crate::r#in::opobj::{OpObj, OpObjT, OpObjU}; +use crate::r#in::opplayer::{OpPlayer, OpPlayerT, OpPlayerU}; +use crate::r#in::rebuild_getmaps::RebuildGetMaps; +use crate::r#in::reportabuse::ReportAbuse; +use crate::r#in::resume_countdialog::ResumePCountDialog; +use crate::r#in::resume_pausebutton::ResumePauseButton; +use crate::r#in::tutorial_clickside::TutorialClickSide; use crate::renderer::{NpcRenderer, PlayerRenderer}; use crate::visibility::Visibility; +use crate::wordpack::WordPack; use once_cell::sync::Lazy; +use out::player_info::PlayerInfo; use std::collections::HashMap; use std::ptr::{addr_of, addr_of_mut}; use wasm_bindgen::prelude::wasm_bindgen; @@ -15,15 +113,62 @@ use wasm_bindgen::prelude::wasm_bindgen; pub mod packet; pub mod renderer; pub mod build; +pub mod wordpack; mod coord; mod player; mod prot; mod message; -mod info; mod grid; mod npc; mod visibility; +mod category; +mod r#in; +mod out; +mod pool; + +macro_rules! read { + ($fn_name:ident, $js_name:literal, $struct:ty, $prot:expr) => { + #[wasm_bindgen(js_name = $js_name)] + pub unsafe fn $fn_name(bytes: Vec) -> $struct { + <$struct>::decode($prot, Packet::from(bytes)) + } + }; +} + +// these priorities are important for cases where the content developer wants to be aware of the +// bandwidth implications their script may run into and how it impacts the player experience + +// counted as part of the buffer_full command +// alternate names: LOW, CONTENT +macro_rules! buffer { + ($fn_name:ident, $js_name:literal, $struct:ty, ($($arg_name:ident: $arg_ty:ty),*), ($($arg_val:ident),*)) => { + #[wasm_bindgen(js_name = $js_name)] + pub unsafe fn $fn_name(pid: i32, $($arg_name: $arg_ty),*) -> Option> { + if pid == -1 { + return None; + } + match &mut *PLAYERS.as_mut_ptr().add(pid as usize) { + None => None, + Some(player) => { + player.buffer(&mut *POOL, &<$struct>::new($($arg_val),*)); + None + }, + } + } + }; +} + +// not counted as part of the buffer_full command +// alternate names: HIGH, ESSENTIAL, ENGINE +macro_rules! write { + ($fn_name:ident, $js_name:literal, $struct:ty, ($($arg_name:ident: $arg_ty:ty),*), ($($arg_val:ident),*)) => { + #[wasm_bindgen(js_name = $js_name)] + pub unsafe fn $fn_name($($arg_name: $arg_ty),*) -> Vec { + Player::write(&mut *POOL, &<$struct>::new($($arg_val),*)) + } + }; +} static mut PLAYERS: Lazy>> = Lazy::new(|| vec![None; 2048]); static mut PLAYER_GRID: Lazy>> = Lazy::new(|| HashMap::with_capacity(2048)); @@ -35,6 +180,8 @@ static mut NPC_RENDERER: Lazy = Lazy::new(NpcRenderer::new); static mut NPC_INFO: Lazy = Lazy::new(NpcInfo::new); static mut ZONE_MAP: Lazy = Lazy::new(ZoneMap::new); +static mut WORD_PACK: Lazy = Lazy::new(WordPack::new); +static mut POOL: Lazy = Lazy::new(PacketPool::new); #[wasm_bindgen(js_name = computePlayer)] pub unsafe fn compute_player( @@ -153,14 +300,13 @@ pub unsafe fn compute_player( } #[wasm_bindgen(js_name = playerInfo)] -pub unsafe fn player_info(pos: usize, pid: i32, dx: i32, dz: i32, rebuild: bool) -> Vec { +pub unsafe fn player_info(pid: i32, dx: i32, dz: i32, rebuild: bool) -> Option> { if pid == -1 { - return vec![]; + return None; } - if let Some(Some(ref mut player)) = PLAYERS.get_mut(pid as usize) { - return PLAYER_INFO.encode( - pos, + if let Some(player) = &mut *PLAYERS.as_mut_ptr().add(pid as usize) { + let bytes: Vec = PLAYER_INFO.encode( &mut **addr_of_mut!(PLAYER_RENDERER), &**addr_of!(PLAYERS), &mut **addr_of_mut!(ZONE_MAP), @@ -170,9 +316,16 @@ pub unsafe fn player_info(pos: usize, pid: i32, dx: i32, dz: i32, rebuild: bool) dz, rebuild, ); + let buf: &mut Packet = &mut *POOL.take(1 + 2 + bytes.len()); + buf.p1(ServerInternalProt::PLAYER_INFO as i32); + buf.pos += 2; + let start: usize = buf.pos; + buf.pdata(&bytes, 0, bytes.len()); + buf.psize2((buf.pos - start) as u16); + return unsafe { Some(buf.data.get_unchecked(0..buf.pos).to_vec()) }; } - return vec![]; + return None; } #[wasm_bindgen(js_name = addPlayer)] @@ -281,14 +434,13 @@ pub unsafe fn compute_npc( } #[wasm_bindgen(js_name = npcInfo)] -pub unsafe fn npc_info(pos: usize, pid: i32, dx: i32, dz: i32, rebuild: bool) -> Vec { +pub unsafe fn npc_info(pid: i32, dx: i32, dz: i32, rebuild: bool) -> Option> { if pid == -1 { - return vec![]; + return None; } - if let Some(Some(ref mut player)) = PLAYERS.get_mut(pid as usize) { - return NPC_INFO.encode( - pos, + if let Some(player) = &mut *PLAYERS.as_mut_ptr().add(pid as usize) { + let bytes: Vec = NPC_INFO.encode( &mut **addr_of_mut!(NPC_RENDERER), &mut **addr_of_mut!(NPCS), &mut **addr_of_mut!(ZONE_MAP), @@ -297,9 +449,16 @@ pub unsafe fn npc_info(pos: usize, pid: i32, dx: i32, dz: i32, rebuild: bool) -> dz, rebuild ); + let buf: &mut Packet = &mut *POOL.take(1 + 2 + bytes.len()); + buf.p1(ServerInternalProt::NPC_INFO as i32); + buf.pos += 2; + let start: usize = buf.pos; + buf.pdata(&bytes, 0, bytes.len()); + buf.psize2((buf.pos - start) as u16); + return unsafe { Some(buf.data.get_unchecked(0..buf.pos).to_vec()) }; } - return vec![]; + return None; } #[wasm_bindgen(js_name = addNpc)] @@ -371,3 +530,294 @@ pub unsafe fn cleanup_player_buildarea(pid: i32) { player.build.cleanup(); } } + +// ---- encoders + +buffer!(cam_lookat, "camLookAt", CamLookAt, (x: i32, z: i32, height: i32, speed: i32, multiplier: i32), (x, z, height, speed, multiplier)); +buffer!(cam_moveto, "camMoveTo", CamMoveTo, (x: i32, z: i32, height: i32, speed: i32, multiplier: i32), (x, z, height, speed, multiplier)); +buffer!(cam_reset, "camReset", CamReset, (), ()); +buffer!(cam_shake, "camShake", CamShake, (shake: i32, jitter: i32, amplitude: i32, frequency: i32), (shake, jitter, amplitude, frequency)); +buffer!(chat_filter_settings, "chatFilterSettings", ChatFilterSettings, (public: i32, private: i32, trade: i32), (public, private, trade)); +buffer!(count_dialog, "countDialog", PCountDialog, (), ()); +write!(data_land, "dataLand", DataLand, (x: i32, z: i32, offset: i32, length: i32, data: Vec), (x, z, offset, length, data)); +write!(data_land_done, "dataLandDone", DataLandDone, (x: i32, z: i32), (x, z)); +write!(data_loc, "dataLoc", DataLoc, (x: i32, z: i32, offset: i32, length: i32, data: Vec), (x, z, offset, length, data)); +write!(data_loc_done, "dataLocDone", DataLocDone, (x: i32, z: i32), (x, z)); +buffer!(enable_tracking, "enableTracking", EnableTracking, (), ()); +buffer!(finish_tracking, "finishTracking", FinishTracking, (), ()); +buffer!(hint_arrow, "hintArrow", HintArrow, (arrow: i32, nid: i32, pid2: i32, x: i32, z: i32, y: i32), (arrow, nid, pid2, x, z, y)); // todo: what should priority be? +buffer!(if_close, "ifClose", IfClose, (), ()); +buffer!(if_open_chat, "ifOpenChat", IfOpenChat, (component: i32), (component)); +buffer!(if_open_main, "ifOpenMain", IfOpenMain, (component: i32), (component)); +buffer!(if_open_main_side, "ifOpenMainSide", IfOpenMainSide, (main: i32, side: i32), (main, side)); +buffer!(if_open_side, "ifOpenSide", IfOpenSide, (component: i32), (component)); +buffer!(if_setanim, "ifSetAnim", IfSetAnim, (component: i32, seq: i32), (component, seq)); +buffer!(if_setcolour, "ifSetColour", IfSetColour, (component: i32, colour: i32), (component, colour)); +buffer!(if_sethide, "ifSetHide", IfSetHide, (component: i32, hidden: bool), (component, hidden)); +buffer!(if_setmodel, "ifSetModel", IfSetModel, (component: i32, model: i32), (component, model)); +buffer!(if_setnpchead, "ifSetNpcHead", IfSetNpcHead, (component: i32, npc: i32), (component, npc)); +buffer!(if_setobject, "ifSetObject", IfSetObject, (component: i32, obj: i32, scale: i32), (component, obj, scale)); +buffer!(if_setplayerhead, "ifSetPlayerHead", IfSetPlayerHead, (component: i32), (component)); +buffer!(if_setposition, "ifSetPosition", IfSetPosition, (component: i32, x: i32, y: i32), (component, x, y)); +buffer!(if_setrecol, "ifSetRecol", IfSetRecol, (component: i32, src: i32, dst: i32), (component, src, dst)); +buffer!(if_settab, "ifSetTab", IfSetTab, (component: i32, tab: i32), (component, tab)); +buffer!(if_settabactive, "ifSetTabActive", IfSetTabActive, (tab: i32), (tab)); +buffer!(if_settext, "ifSetText", IfSetText, (component: i32, text: String), (component, text)); +buffer!(last_login_info, "lastLoginInfo", LastLoginInfo, (lastIp: i32, daysSinceLogin: i32, daysSinceRecovery: i32, messages: i32), (lastIp, daysSinceLogin, daysSinceRecovery, messages)); +write!(loc_addchange, "locAddChange", LocAddChange, (coord: i32, loc: i32, shape: i32, angle: i32), (coord, loc, shape, angle)); +write!(loc_anim, "locAnim", LocAnim, (coord: i32, shape: i32, angle: i32, seq: i32), (coord, shape, angle, seq)); +write!(loc_del, "locDel", LocDel, (coord: i32, shape: i32, angle: i32), (coord, shape, angle)); +write!(loc_merge, "locMerge", LocMerge, (srcX: i32, srcZ: i32, shape: i32, angle: i32, loc: i32, start: i32, end: i32, pid: i32, east: i32, south: i32, west: i32, north: i32), (srcX, srcZ, shape, angle, loc, start, end, pid, east, south, west, north)); +write!(logout, "logout", Logout, (), ()); +write!(map_anim, "mapAnim", MapAnim, (coord: i32, spotanim: i32, height: i32, delay: i32), (coord, spotanim, height, delay)); +write!(map_projanim, "mapProjAnim", MapProjAnim, (srcX: i32, srcZ: i32, dstX: i32, dstZ: i32, target: i32, spotanim: i32, srcHeight: i32, dstHeight: i32, start: i32, end: i32, peak: i32, arc: i32), (srcX, srcZ, dstX, dstZ, target, spotanim, srcHeight, dstHeight, start, end, peak, arc)); +write!(message_game, "messageGame", MessageGame, (msg: String), (msg)); +write!(message_private_out, "messagePrivateOut", MessagePrivateOut, (from: i64, id: i32, staffModLevel: i32, msg: Vec), (from, id, staffModLevel, msg)); +buffer!(midi_jingle, "midiJingle", MidiJingle, (delay: i32, data: Vec), (delay, data)); +buffer!(midi_song, "midiSong", MidiSong, (name: String, crc: i32, length: i32), (name, crc, length)); +write!(obj_add, "objAdd", ObjAdd, (coord: i32, obj: i32, count: i32), (coord, obj, count)); +write!(obj_count, "objCount", ObjCount, (coord: i32, obj: i32, oldCount: i32, newCount: i32), (coord, obj, oldCount, newCount)); +write!(obj_del, "objDel", ObjDel, (coord: i32, obj: i32), (coord, obj)); +write!(obj_reveal, "objReveal", ObjReveal, (coord: i32, obj: i32, count: i32, receiver: i32), (coord, obj, count, receiver)); +write!(rebuild_normal, "rebuildNormal", RebuildNormal, (x: i32, z: i32, squares: Vec, maps: Vec, locs: Vec), (x, z, squares, maps, locs)); +write!(reset_anims, "resetAnims", ResetAnims, (), ()); // todo: what should priority be? +write!(reset_clientvarcache, "resetClientVarCache", ResetClientVarCache, (), ()); +buffer!(set_multiway, "setMultiway", SetMultiway, (hidden: bool), (hidden)); +buffer!(synth_sound, "synthSound", SynthSound, (synth: i32, loops: i32, delay: i32), (synth, loops, delay)); +buffer!(tut_flash, "tutFlash", TutFlash, (tab: i32), (tab)); +buffer!(tut_open, "tutOpen", TutOpen, (component: i32), (component)); +write!(unset_map_flag, "unsetMapFlag", UnsetMapFlag, (), ()); +buffer!(update_friendlist, "updateFriendList", UpdateFriendList, (name: i64, node: i32), (name, node)); +buffer!(update_ignorelist, "updateIgnoreList", UpdateIgnoreList, (names: Vec), (names)); +write!(update_inv_full, "updateInvFull", UpdateInvFull, (size: i32, component: i32, inv: Vec), (size, component, inv)); +write!(update_inv_partial, "updateInvPartial", UpdateInvPartial, (component: i32, slots: Vec, inv: Vec), (component, slots, inv)); +write!(update_inv_stop_transmit, "updateInvStopTransmit", UpdateInvStopTransmit, (component: i32), (component)); +write!(update_pid, "updatePid", UpdatePid, (pid: i32), (pid)); // todo: what should priority be? +buffer!(update_reboot_timer, "updateRebootTimer", UpdateRebootTimer, (ticks: i32), (ticks)); // todo: what should priority be? +buffer!(update_runenergy, "updateRunEnergy", UpdateRunEnergy, (energy: i32), (energy)); +buffer!(update_runweight, "updateRunWeight", UpdateRunWeight, (kg: i32), (kg)); +buffer!(update_stat, "updateStat", UpdateStat, (stat: i32, experience: i32, level: i32), (stat, experience, level)); +write!(update_zone_full_follows, "updateZoneFullFollows", UpdateZoneFullFollows, (x: i32, z: i32, originX: i32, originZ: i32), (x, z, originX, originZ)); +write!(update_zone_partial_enclosed, "updateZonePartialEnclosed", UpdateZonePartialEnclosed, (x: i32, z: i32, originX: i32, originZ: i32, data: Vec), (x, z, originX, originZ, data)); +write!(update_zone_partial_follows, "updateZonePartialFollows", UpdateZonePartialFollows, (x: i32, z: i32, originX: i32, originZ: i32), (x, z, originX, originZ)); +write!(varp_small, "varpSmall", VarpSmall, (id: i32, value: i32), (id, value)); +write!(varp_large, "varpLarge", VarpLarge, (id: i32, value: i32), (id, value)); + +// ---- decoders + +read!(client_cheat, "clientCheat", ClientCheat, ClientProt::CLIENT_CHEAT); +read!(close_modal, "closeModal", CloseModal, ClientProt::CLOSE_MODAL); +read!(friend_list_add, "friendListAdd", FriendListAdd, ClientProt::FRIENDLIST_ADD); +read!(friend_list_del, "friendListDel", FriendListDel, ClientProt::FRIENDLIST_DEL); +read!(idle_timer, "idleTimer", IdleTimer, ClientProt::IDLE_TIMER); +read!(if_button, "ifButton", IfButton, ClientProt::IF_BUTTON); +read!(if_player_design, "ifPlayerDesign", IfPlayerDesign, ClientProt::IF_PLAYERDESIGN); +read!(ignore_list_add, "ignoreListAdd", IgnoreListAdd, ClientProt::IGNORELIST_ADD); +read!(ignore_list_del, "ignoreListDel", IgnoreListDel, ClientProt::IGNORELIST_DEL); +read!(inv_button1, "invButton1", InvButton, ClientProt::INV_BUTTON1); +read!(inv_button2, "invButton2", InvButton, ClientProt::INV_BUTTON2); +read!(inv_button3, "invButton3", InvButton, ClientProt::INV_BUTTON3); +read!(inv_button4, "invButton4", InvButton, ClientProt::INV_BUTTON4); +read!(inv_button5, "invButton5", InvButton, ClientProt::INV_BUTTON5); +read!(inv_button_d, "invButtonD", InvButtonD, ClientProt::INV_BUTTOND); +read!(message_private, "messagePrivate", MessagePrivate, ClientProt::MESSAGE_PRIVATE); +read!(message_public, "messagePublic", MessagePublic, ClientProt::MESSAGE_PUBLIC); +read!(move_minimap_click, "moveMinimapClick", MoveClick, ClientProt::MOVE_MINIMAPCLICK); +read!(move_game_click, "moveGameClick", MoveClick, ClientProt::MOVE_GAMECLICK); +read!(move_op_click, "moveOpClick", MoveClick, ClientProt::MOVE_OPCLICK); +read!(no_timeout, "noTimeout", NoTimeout, ClientProt::NO_TIMEOUT); +read!(opheld1, "opheld1", OpHeld, ClientProt::OPHELD1); +read!(opheld2, "opheld2", OpHeld, ClientProt::OPHELD2); +read!(opheld3, "opheld3", OpHeld, ClientProt::OPHELD3); +read!(opheld4, "opheld4", OpHeld, ClientProt::OPHELD4); +read!(opheld5, "opheld5", OpHeld, ClientProt::OPHELD5); +read!(opheld_t, "opheldT", OpHeldT, ClientProt::OPHELDT); +read!(opheld_u, "opheldU", OpHeldU, ClientProt::OPHELDU); +read!(oploc1, "oploc1", OpLoc, ClientProt::OPLOC1); +read!(oploc2, "oploc2", OpLoc, ClientProt::OPLOC2); +read!(oploc3, "oploc3", OpLoc, ClientProt::OPLOC3); +read!(oploc4, "oploc4", OpLoc, ClientProt::OPLOC4); +read!(oploc5, "oploc5", OpLoc, ClientProt::OPLOC5); +read!(oploc_t, "oplocT", OpLocT, ClientProt::OPLOCT); +read!(oploc_u, "oplocU", OpLocU, ClientProt::OPLOCU); +read!(opnpc1, "opnpc1", OpNpc, ClientProt::OPNPC1); +read!(opnpc2, "opnpc2", OpNpc, ClientProt::OPNPC2); +read!(opnpc3, "opnpc3", OpNpc, ClientProt::OPNPC3); +read!(opnpc4, "opnpc4", OpNpc, ClientProt::OPNPC4); +read!(opnpc5, "opnpc5", OpNpc, ClientProt::OPNPC5); +read!(opnpc_t, "opnpcT", OpNpcT, ClientProt::OPNPCT); +read!(opnpc_u, "opnpcU", OpNpcU, ClientProt::OPNPCU); +read!(opobj1, "opobj1", OpObj, ClientProt::OPOBJ1); +read!(opobj2, "opobj2", OpObj, ClientProt::OPOBJ2); +read!(opobj3, "opobj3", OpObj, ClientProt::OPOBJ3); +read!(opobj4, "opobj4", OpObj, ClientProt::OPOBJ4); +read!(opobj5, "opobj5", OpObj, ClientProt::OPOBJ5); +read!(opobj_t, "opobjT", OpObjT, ClientProt::OPOBJT); +read!(opobj_u, "opobjU", OpObjU, ClientProt::OPOBJU); +read!(opplayer1, "opplayer1", OpPlayer, ClientProt::OPPLAYER1); +read!(opplayer2, "opplayer2", OpPlayer, ClientProt::OPPLAYER2); +read!(opplayer3, "opplayer3", OpPlayer, ClientProt::OPPLAYER3); +read!(opplayer4, "opplayer4", OpPlayer, ClientProt::OPPLAYER4); +read!(opplayer_t, "opplayerT", OpPlayerT, ClientProt::OPPLAYERT); +read!(opplayer_u, "opplayerU", OpPlayerU, ClientProt::OPPLAYERU); +read!(rebuild_getmaps, "rebuildGetMaps", RebuildGetMaps, ClientProt::REBUILD_GETMAPS); +read!(resume_pausebutton, "resumePauseButton", ResumePauseButton, ClientProt::RESUME_PAUSEBUTTON); +read!(resume_countdialog, "resumeCountDialog", ResumePCountDialog, ClientProt::RESUME_P_COUNTDIALOG); +read!(tutorial_clickside, "tutorialClickSide", TutorialClickSide, ClientProt::TUTORIAL_CLICKSIDE); +read!(chat_setmode, "chatSetMode", ChatSetMode, ClientProt::CHAT_SETMODE); +read!(event_tracking, "eventTracking", EventTracking, ClientProt::EVENT_TRACKING); +read!(report_abuse, "reportAbuse", ReportAbuse, ClientProt::REPORT_ABUSE); +read!(event_camera_position, "eventCameraPosition", EventCameraPosition, ClientProt::EVENT_CAMERA_POSITION); +read!(anticheatop1, "anticheatOp1", AnticheatOp1, ClientProt::ANTICHEAT_OPLOGIC1); +read!(anticheatop2, "anticheatOp2", AnticheatOp2, ClientProt::ANTICHEAT_OPLOGIC2); +read!(anticheatop3, "anticheatOp3", AnticheatOp3, ClientProt::ANTICHEAT_OPLOGIC3); +read!(anticheatop4, "anticheatOp4", AnticheatOp4, ClientProt::ANTICHEAT_OPLOGIC4); +read!(anticheatop5, "anticheatOp5", AnticheatOp5, ClientProt::ANTICHEAT_OPLOGIC5); +read!(anticheatop6, "anticheatOp6", AnticheatOp6, ClientProt::ANTICHEAT_OPLOGIC6); +read!(anticheatop7, "anticheatOp7", AnticheatOp7, ClientProt::ANTICHEAT_OPLOGIC7); +read!(anticheatop8, "anticheatOp8", AnticheatOp8, ClientProt::ANTICHEAT_OPLOGIC8); +read!(anticheatop9, "anticheatOp9", AnticheatOp9, ClientProt::ANTICHEAT_OPLOGIC9); +read!(anticheatcycle1, "anticheatCycle1", AnticheatCycle1, ClientProt::ANTICHEAT_CYCLELOGIC1); +read!(anticheatcycle2, "anticheatCycle2", AnticheatCycle2, ClientProt::ANTICHEAT_CYCLELOGIC2); +read!(anticheatcycle3, "anticheatCycle3", AnticheatCycle3, ClientProt::ANTICHEAT_CYCLELOGIC3); +read!(anticheatcycle4, "anticheatCycle4", AnticheatCycle4, ClientProt::ANTICHEAT_CYCLELOGIC4); +read!(anticheatcycle5, "anticheatCycle5", AnticheatCycle5, ClientProt::ANTICHEAT_CYCLELOGIC5); +read!(anticheatcycle6, "anticheatCycle6", AnticheatCycle6, ClientProt::ANTICHEAT_CYCLELOGIC6); + +// ---- misc + +static PACKET_LOOKUP: Lazy>> = Lazy::new(|| { + let mut lookup: Vec> = vec![None; 255]; + lookup[ClientInternalProt::CLIENT_CHEAT as usize] = Some(IncomingPacket::new(ClientProt::CLIENT_CHEAT as i32, ClientCheat::length())); + lookup[ClientInternalProt::CLOSE_MODAL as usize] = Some(IncomingPacket::new(ClientProt::CLOSE_MODAL as i32, CloseModal::length())); + lookup[ClientInternalProt::FRIENDLIST_ADD as usize] = Some(IncomingPacket::new(ClientProt::FRIENDLIST_ADD as i32, FriendListAdd::length())); + lookup[ClientInternalProt::FRIENDLIST_DEL as usize] = Some(IncomingPacket::new(ClientProt::FRIENDLIST_DEL as i32, FriendListDel::length())); + lookup[ClientInternalProt::IDLE_TIMER as usize] = Some(IncomingPacket::new(ClientProt::IDLE_TIMER as i32, IdleTimer::length())); + lookup[ClientInternalProt::IF_BUTTON as usize] = Some(IncomingPacket::new(ClientProt::IF_BUTTON as i32, IfButton::length())); + lookup[ClientInternalProt::IF_PLAYERDESIGN as usize] = Some(IncomingPacket::new(ClientProt::IF_PLAYERDESIGN as i32, IfPlayerDesign::length())); + lookup[ClientInternalProt::IGNORELIST_ADD as usize] = Some(IncomingPacket::new(ClientProt::IGNORELIST_ADD as i32, IgnoreListAdd::length())); + lookup[ClientInternalProt::IGNORELIST_DEL as usize] = Some(IncomingPacket::new(ClientProt::IGNORELIST_DEL as i32, IgnoreListDel::length())); + lookup[ClientInternalProt::INV_BUTTON1 as usize] = Some(IncomingPacket::new(ClientProt::INV_BUTTON1 as i32, InvButton::length())); + lookup[ClientInternalProt::INV_BUTTON2 as usize] = Some(IncomingPacket::new(ClientProt::INV_BUTTON2 as i32, InvButton::length())); + lookup[ClientInternalProt::INV_BUTTON3 as usize] = Some(IncomingPacket::new(ClientProt::INV_BUTTON3 as i32, InvButton::length())); + lookup[ClientInternalProt::INV_BUTTON4 as usize] = Some(IncomingPacket::new(ClientProt::INV_BUTTON4 as i32, InvButton::length())); + lookup[ClientInternalProt::INV_BUTTON5 as usize] = Some(IncomingPacket::new(ClientProt::INV_BUTTON5 as i32, InvButton::length())); + lookup[ClientInternalProt::INV_BUTTOND as usize] = Some(IncomingPacket::new(ClientProt::INV_BUTTOND as i32, InvButtonD::length())); + lookup[ClientInternalProt::MESSAGE_PRIVATE as usize] = Some(IncomingPacket::new(ClientProt::MESSAGE_PRIVATE as i32, MessagePrivate::length())); + lookup[ClientInternalProt::MESSAGE_PUBLIC as usize] = Some(IncomingPacket::new(ClientProt::MESSAGE_PUBLIC as i32, MessagePublic::length())); + lookup[ClientInternalProt::MOVE_MINIMAPCLICK as usize] = Some(IncomingPacket::new(ClientProt::MOVE_MINIMAPCLICK as i32, MoveClick::length())); + lookup[ClientInternalProt::MOVE_GAMECLICK as usize] = Some(IncomingPacket::new(ClientProt::MOVE_GAMECLICK as i32, MoveClick::length())); + lookup[ClientInternalProt::MOVE_OPCLICK as usize] = Some(IncomingPacket::new(ClientProt::MOVE_OPCLICK as i32, MoveClick::length())); + lookup[ClientInternalProt::NO_TIMEOUT as usize] = Some(IncomingPacket::new(ClientProt::NO_TIMEOUT as i32, NoTimeout::length())); + lookup[ClientInternalProt::OPHELD1 as usize] = Some(IncomingPacket::new(ClientProt::OPHELD1 as i32, OpHeld::length())); + lookup[ClientInternalProt::OPHELD2 as usize] = Some(IncomingPacket::new(ClientProt::OPHELD2 as i32, OpHeld::length())); + lookup[ClientInternalProt::OPHELD3 as usize] = Some(IncomingPacket::new(ClientProt::OPHELD3 as i32, OpHeld::length())); + lookup[ClientInternalProt::OPHELD4 as usize] = Some(IncomingPacket::new(ClientProt::OPHELD4 as i32, OpHeld::length())); + lookup[ClientInternalProt::OPHELD5 as usize] = Some(IncomingPacket::new(ClientProt::OPHELD5 as i32, OpHeld::length())); + lookup[ClientInternalProt::OPHELDT as usize] = Some(IncomingPacket::new(ClientProt::OPHELDT as i32, OpHeldT::length())); + lookup[ClientInternalProt::OPHELDU as usize] = Some(IncomingPacket::new(ClientProt::OPHELDU as i32, OpHeldU::length())); + lookup[ClientInternalProt::OPLOC1 as usize] = Some(IncomingPacket::new(ClientProt::OPLOC1 as i32, OpLoc::length())); + lookup[ClientInternalProt::OPLOC2 as usize] = Some(IncomingPacket::new(ClientProt::OPLOC2 as i32, OpLoc::length())); + lookup[ClientInternalProt::OPLOC3 as usize] = Some(IncomingPacket::new(ClientProt::OPLOC3 as i32, OpLoc::length())); + lookup[ClientInternalProt::OPLOC4 as usize] = Some(IncomingPacket::new(ClientProt::OPLOC4 as i32, OpLoc::length())); + lookup[ClientInternalProt::OPLOC5 as usize] = Some(IncomingPacket::new(ClientProt::OPLOC5 as i32, OpLoc::length())); + lookup[ClientInternalProt::OPLOCT as usize] = Some(IncomingPacket::new(ClientProt::OPLOCT as i32, OpLocT::length())); + lookup[ClientInternalProt::OPLOCU as usize] = Some(IncomingPacket::new(ClientProt::OPLOCU as i32, OpLocU::length())); + lookup[ClientInternalProt::OPNPC1 as usize] = Some(IncomingPacket::new(ClientProt::OPNPC1 as i32, OpNpc::length())); + lookup[ClientInternalProt::OPNPC2 as usize] = Some(IncomingPacket::new(ClientProt::OPNPC2 as i32, OpNpc::length())); + lookup[ClientInternalProt::OPNPC3 as usize] = Some(IncomingPacket::new(ClientProt::OPNPC3 as i32, OpNpc::length())); + lookup[ClientInternalProt::OPNPC4 as usize] = Some(IncomingPacket::new(ClientProt::OPNPC4 as i32, OpNpc::length())); + lookup[ClientInternalProt::OPNPC5 as usize] = Some(IncomingPacket::new(ClientProt::OPNPC5 as i32, OpNpc::length())); + lookup[ClientInternalProt::OPNPCT as usize] = Some(IncomingPacket::new(ClientProt::OPNPCT as i32, OpNpcT::length())); + lookup[ClientInternalProt::OPNPCU as usize] = Some(IncomingPacket::new(ClientProt::OPNPCU as i32, OpNpcU::length())); + lookup[ClientInternalProt::OPOBJ1 as usize] = Some(IncomingPacket::new(ClientProt::OPOBJ1 as i32, OpObj::length())); + lookup[ClientInternalProt::OPOBJ2 as usize] = Some(IncomingPacket::new(ClientProt::OPOBJ2 as i32, OpObj::length())); + lookup[ClientInternalProt::OPOBJ3 as usize] = Some(IncomingPacket::new(ClientProt::OPOBJ3 as i32, OpObj::length())); + lookup[ClientInternalProt::OPOBJ4 as usize] = Some(IncomingPacket::new(ClientProt::OPOBJ4 as i32, OpObj::length())); + lookup[ClientInternalProt::OPOBJ5 as usize] = Some(IncomingPacket::new(ClientProt::OPOBJ5 as i32, OpObj::length())); + lookup[ClientInternalProt::OPOBJT as usize] = Some(IncomingPacket::new(ClientProt::OPOBJT as i32, OpObjT::length())); + lookup[ClientInternalProt::OPOBJU as usize] = Some(IncomingPacket::new(ClientProt::OPOBJU as i32, OpObjU::length())); + lookup[ClientInternalProt::OPPLAYER1 as usize] = Some(IncomingPacket::new(ClientProt::OPPLAYER1 as i32, OpPlayer::length())); + lookup[ClientInternalProt::OPPLAYER2 as usize] = Some(IncomingPacket::new(ClientProt::OPPLAYER2 as i32, OpPlayer::length())); + lookup[ClientInternalProt::OPPLAYER3 as usize] = Some(IncomingPacket::new(ClientProt::OPPLAYER3 as i32, OpPlayer::length())); + lookup[ClientInternalProt::OPPLAYER4 as usize] = Some(IncomingPacket::new(ClientProt::OPPLAYER4 as i32, OpPlayer::length())); + lookup[ClientInternalProt::OPPLAYERT as usize] = Some(IncomingPacket::new(ClientProt::OPPLAYERT as i32, OpPlayerT::length())); + lookup[ClientInternalProt::OPPLAYERU as usize] = Some(IncomingPacket::new(ClientProt::OPPLAYERU as i32, OpPlayerU::length())); + lookup[ClientInternalProt::REBUILD_GETMAPS as usize] = Some(IncomingPacket::new(ClientProt::REBUILD_GETMAPS as i32, RebuildGetMaps::length())); + lookup[ClientInternalProt::RESUME_PAUSEBUTTON as usize] = Some(IncomingPacket::new(ClientProt::RESUME_PAUSEBUTTON as i32, ResumePauseButton::length())); + lookup[ClientInternalProt::RESUME_P_COUNTDIALOG as usize] = Some(IncomingPacket::new(ClientProt::RESUME_P_COUNTDIALOG as i32, ResumePCountDialog::length())); + lookup[ClientInternalProt::TUTORIAL_CLICKSIDE as usize] = Some(IncomingPacket::new(ClientProt::TUTORIAL_CLICKSIDE as i32, TutorialClickSide::length())); + lookup[ClientInternalProt::CHAT_SETMODE as usize] = Some(IncomingPacket::new(ClientProt::CHAT_SETMODE as i32, ChatSetMode::length())); + lookup[ClientInternalProt::EVENT_TRACKING as usize] = Some(IncomingPacket::new(ClientProt::EVENT_TRACKING as i32, EventTracking::length())); + lookup[ClientInternalProt::REPORT_ABUSE as usize] = Some(IncomingPacket::new(ClientProt::REPORT_ABUSE as i32, ReportAbuse::length())); + lookup[ClientInternalProt::EVENT_CAMERA_POSITION as usize] = Some(IncomingPacket::new(ClientProt::EVENT_CAMERA_POSITION as i32, EventCameraPosition::length())); + lookup[ClientInternalProt::ANTICHEAT_OPLOGIC1 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_OPLOGIC1 as i32, AnticheatOp1::length())); + lookup[ClientInternalProt::ANTICHEAT_OPLOGIC2 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_OPLOGIC2 as i32, AnticheatOp2::length())); + lookup[ClientInternalProt::ANTICHEAT_OPLOGIC3 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_OPLOGIC3 as i32, AnticheatOp3::length())); + lookup[ClientInternalProt::ANTICHEAT_OPLOGIC4 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_OPLOGIC4 as i32, AnticheatOp4::length())); + lookup[ClientInternalProt::ANTICHEAT_OPLOGIC5 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_OPLOGIC5 as i32, AnticheatOp5::length())); + lookup[ClientInternalProt::ANTICHEAT_OPLOGIC6 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_OPLOGIC6 as i32, AnticheatOp6::length())); + lookup[ClientInternalProt::ANTICHEAT_OPLOGIC7 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_OPLOGIC7 as i32, AnticheatOp7::length())); + lookup[ClientInternalProt::ANTICHEAT_OPLOGIC8 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_OPLOGIC8 as i32, AnticheatOp8::length())); + lookup[ClientInternalProt::ANTICHEAT_OPLOGIC9 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_OPLOGIC9 as i32, AnticheatOp9::length())); + lookup[ClientInternalProt::ANTICHEAT_CYCLELOGIC1 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_CYCLELOGIC1 as i32, AnticheatCycle1::length())); + lookup[ClientInternalProt::ANTICHEAT_CYCLELOGIC2 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_CYCLELOGIC2 as i32, AnticheatCycle2::length())); + lookup[ClientInternalProt::ANTICHEAT_CYCLELOGIC3 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_CYCLELOGIC3 as i32, AnticheatCycle3::length())); + lookup[ClientInternalProt::ANTICHEAT_CYCLELOGIC4 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_CYCLELOGIC4 as i32, AnticheatCycle4::length())); + lookup[ClientInternalProt::ANTICHEAT_CYCLELOGIC5 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_CYCLELOGIC5 as i32, AnticheatCycle5::length())); + lookup[ClientInternalProt::ANTICHEAT_CYCLELOGIC6 as usize] = Some(IncomingPacket::new(ClientProt::ANTICHEAT_CYCLELOGIC6 as i32, AnticheatCycle6::length())); + return lookup; +}); + +#[wasm_bindgen(js_name = nextBufferedWrite)] +pub unsafe fn next_buffered_write(pid: i32) -> Option> { + if pid == -1 { + return None; + } + return match &mut *PLAYERS.as_mut_ptr().add(pid as usize) { + None => None, + Some(player) => player.write_queue.pop_front(), + }; +} + +#[wasm_bindgen(js_name = nextBufferedRead)] +pub unsafe fn next_buffered_read(id: i32) -> i16 { + return match &*PACKET_LOOKUP.as_ptr().add(id as usize) { + None => -1, + Some(packet) => ((packet.id as i16) << 8) | (packet.length as i16 & 0xff), + } +} + +#[wasm_bindgen(js_name = isBufferFull)] +pub unsafe fn is_buffer_full(pid: i32) -> bool { + if pid == -1 { + return false; + } + return match &*PLAYERS.as_ptr().add(pid as usize) { + None => false, + Some(player) => player + .write_queue + .iter() + .map(|packet| packet.len()) + .scan(0, |acc, len| { + *acc += len; + return if *acc >= 5000 { + None + } else { + Some(*acc) + } + }) + .last() + .unwrap_or(0) >= 5000 + }; +} + +#[wasm_bindgen(js_name = unpackWords)] +pub unsafe fn unpack_words(bytes: Vec) -> String { + return WORD_PACK.unpack(Packet::from(bytes)); +} + +#[wasm_bindgen(js_name = packWords)] +pub unsafe fn pack_words(msg: String) -> Vec { + return WORD_PACK.pack(msg); +} diff --git a/src/message.rs b/src/message.rs index 6581ca0..02772db 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,9 +1,40 @@ use crate::packet::Packet; +use crate::prot::ClientProt; pub trait InfoMessage { fn encode(&self, buf: &mut Packet); fn test(&self) -> usize; - fn persists(&self) -> bool; +} + +pub trait MessageEncoder { + fn id(&self) -> i32; + fn length(&self) -> i32; + fn encode(&self, buf: &mut Packet); + fn test(&self) -> usize; +} + +pub trait MessageDecoder { + fn length() -> i32; + fn decode(prot: ClientProt, buf: Packet) -> T; +} + +#[derive(Clone)] +pub struct IncomingPacket { + pub id: i32, + pub length: i32, +} + +impl IncomingPacket { + #[inline] + pub fn new( + id: i32, + length: i32 + ) -> IncomingPacket { + return IncomingPacket { + id, + length, + } + } } // ---- players @@ -32,11 +63,6 @@ impl InfoMessage for PlayerInfoAppearance { fn test(&self) -> usize { return 1 + self.bytes.len(); } - - #[inline] - fn persists(&self) -> bool { - return true; - } } // ---- @@ -64,11 +90,6 @@ impl InfoMessage for PlayerInfoFaceEntity { fn test(&self) -> usize { return 2; } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -102,11 +123,6 @@ impl InfoMessage for PlayerInfoFaceCoord { fn test(&self) -> usize { return 4; } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -140,11 +156,6 @@ impl InfoMessage for PlayerInfoAnim { fn test(&self) -> usize { return 3; } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -172,11 +183,6 @@ impl InfoMessage for PlayerInfoSay { fn test(&self) -> usize { return 1 + self.say.len(); } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -218,11 +224,6 @@ impl InfoMessage for PlayerInfoDamage { fn test(&self) -> usize { return 4; } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -265,11 +266,6 @@ impl InfoMessage for PlayerInfoChat { fn test(&self) -> usize { return 1 + 1 + 1 + 1 + self.bytes.len(); } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -306,11 +302,6 @@ impl InfoMessage for PlayerInfoSpotanim { fn test(&self) -> usize { return 6; } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -364,11 +355,6 @@ impl InfoMessage for PlayerInfoExactMove { fn test(&self) -> usize { return 9; } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- npcs @@ -396,11 +382,6 @@ impl InfoMessage for NpcInfoFaceEntity { fn test(&self) -> usize { return 2; } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -434,11 +415,6 @@ impl InfoMessage for NpcInfoFaceCoord { fn test(&self) -> usize { return 4; } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -472,11 +448,6 @@ impl InfoMessage for NpcInfoAnim { fn test(&self) -> usize { return 3; } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -504,11 +475,6 @@ impl InfoMessage for NpcInfoSay { fn test(&self) -> usize { return 1 + self.say.len(); } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -550,11 +516,6 @@ impl InfoMessage for NpcInfoDamage { fn test(&self) -> usize { return 4; } - - #[inline] - fn persists(&self) -> bool { - return false; - } } // ---- @@ -573,17 +534,15 @@ impl NpcInfoChangeType { } impl InfoMessage for NpcInfoChangeType { + #[inline] fn encode(&self, buf: &mut Packet) { buf.p2(self.change_type); } + #[inline] fn test(&self) -> usize { return 2; } - - fn persists(&self) -> bool { - return false; - } } // ---- @@ -620,11 +579,4 @@ impl InfoMessage for NpcInfoSpotanim { fn test(&self) -> usize { return 6; } - - #[inline] - fn persists(&self) -> bool { - return false; - } } - -// ---- \ No newline at end of file diff --git a/src/out/cam_lookat.rs b/src/out/cam_lookat.rs new file mode 100644 index 0000000..39711a1 --- /dev/null +++ b/src/out/cam_lookat.rs @@ -0,0 +1,56 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct CamLookAt { + x: i32, + z: i32, + height: i32, + speed: i32, + multiplier: i32, +} + +impl CamLookAt { + #[inline] + pub const fn new( + x: i32, + z: i32, + height: i32, + speed: i32, + multiplier: i32, + ) -> CamLookAt { + return CamLookAt { + x, + z, + height, + speed, + multiplier, + } + } +} + +impl MessageEncoder for CamLookAt { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::CAM_LOOKAT as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 6; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.x); + buf.p1(self.z); + buf.p2(self.height); + buf.p1(self.speed); + buf.p1(self.multiplier); + } + + #[inline] + fn test(&self) -> usize { + return 6; + } +} \ No newline at end of file diff --git a/src/out/cam_moveto.rs b/src/out/cam_moveto.rs new file mode 100644 index 0000000..ebb5951 --- /dev/null +++ b/src/out/cam_moveto.rs @@ -0,0 +1,56 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct CamMoveTo { + x: i32, + z: i32, + height: i32, + speed: i32, + multiplier: i32, +} + +impl CamMoveTo { + #[inline] + pub const fn new( + x: i32, + z: i32, + height: i32, + speed: i32, + multiplier: i32, + ) -> CamMoveTo { + return CamMoveTo { + x, + z, + height, + speed, + multiplier, + } + } +} + +impl MessageEncoder for CamMoveTo { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::CAM_MOVETO as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 6; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.x); + buf.p1(self.z); + buf.p2(self.height); + buf.p1(self.speed); + buf.p1(self.multiplier); + } + + #[inline] + fn test(&self) -> usize { + return 6; + } +} \ No newline at end of file diff --git a/src/out/cam_reset.rs b/src/out/cam_reset.rs new file mode 100644 index 0000000..23124dd --- /dev/null +++ b/src/out/cam_reset.rs @@ -0,0 +1,32 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct CamReset {} + +impl CamReset { + #[inline] + pub const fn new() -> CamReset { + return CamReset {} + } +} + +impl MessageEncoder for CamReset { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::CAM_RESET as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 0; + } + + #[inline] + fn encode(&self, _: &mut Packet) {} + + #[inline] + fn test(&self) -> usize { + return 0; + } +} \ No newline at end of file diff --git a/src/out/cam_shake.rs b/src/out/cam_shake.rs new file mode 100644 index 0000000..6542715 --- /dev/null +++ b/src/out/cam_shake.rs @@ -0,0 +1,52 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct CamShake { + shake: i32, + jitter: i32, + amplitude: i32, + frequency: i32, +} + +impl CamShake { + #[inline] + pub const fn new( + shake: i32, + jitter: i32, + amplitude: i32, + frequency: i32, + ) -> CamShake { + return CamShake { + shake, + jitter, + amplitude, + frequency, + } + } +} + +impl MessageEncoder for CamShake { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::CAM_SHAKE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 4; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.shake); // direction? + buf.p1(self.jitter); + buf.p1(self.amplitude); + buf.p1(self.frequency); + } + + #[inline] + fn test(&self) -> usize { + return 4; + } +} \ No newline at end of file diff --git a/src/out/chat_filter_settings.rs b/src/out/chat_filter_settings.rs new file mode 100644 index 0000000..001fa7b --- /dev/null +++ b/src/out/chat_filter_settings.rs @@ -0,0 +1,48 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct ChatFilterSettings { + public: i32, + private: i32, + trade: i32, +} + +impl ChatFilterSettings { + #[inline] + pub const fn new( + public: i32, + private: i32, + trade: i32, + ) -> ChatFilterSettings { + return ChatFilterSettings { + public, + private, + trade, + } + } +} + +impl MessageEncoder for ChatFilterSettings { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::CHAT_FILTER_SETTINGS as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 3; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.public); + buf.p1(self.private); + buf.p1(self.trade); + } + + #[inline] + fn test(&self) -> usize { + return 3; + } +} \ No newline at end of file diff --git a/src/out/count_dialog.rs b/src/out/count_dialog.rs new file mode 100644 index 0000000..38e930a --- /dev/null +++ b/src/out/count_dialog.rs @@ -0,0 +1,32 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct PCountDialog {} + +impl PCountDialog { + #[inline] + pub const fn new() -> PCountDialog { + return PCountDialog {} + } +} + +impl MessageEncoder for PCountDialog { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::P_COUNTDIALOG as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 0; + } + + #[inline] + fn encode(&self, _: &mut Packet) {} + + #[inline] + fn test(&self) -> usize { + return 0; + } +} \ No newline at end of file diff --git a/src/out/data_land.rs b/src/out/data_land.rs new file mode 100644 index 0000000..7845861 --- /dev/null +++ b/src/out/data_land.rs @@ -0,0 +1,99 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct DataLand { + x: i32, + z: i32, + offset: i32, + length: i32, + data: Vec, +} + +impl DataLand { + #[inline] + pub const fn new( + x: i32, + z: i32, + offset: i32, + length: i32, + data: Vec, + ) -> DataLand { + return DataLand { + x, + z, + offset, + length, + data, + } + } +} + +impl MessageEncoder for DataLand { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::DATA_LAND as i32; + } + + #[inline] + fn length(&self) -> i32 { + return -2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.x); + buf.p1(self.z); + buf.p2(self.offset); + buf.p2(self.length); + buf.pdata(&self.data, 0, self.data.len()); + } + + #[inline] + fn test(&self) -> usize { + return 6 + self.data.len(); + } +} + +// ---- + +pub struct DataLandDone { + x: i32, + z: i32, +} + +impl DataLandDone { + #[inline] + pub const fn new( + x: i32, + z: i32, + ) -> DataLandDone { + return DataLandDone { + x, + z, + } + } +} + +impl MessageEncoder for DataLandDone { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::DATA_LAND_DONE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.x); + buf.p1(self.z); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} diff --git a/src/out/data_loc.rs b/src/out/data_loc.rs new file mode 100644 index 0000000..5625bfa --- /dev/null +++ b/src/out/data_loc.rs @@ -0,0 +1,99 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct DataLoc { + x: i32, + z: i32, + offset: i32, + length: i32, + data: Vec, +} + +impl DataLoc { + #[inline] + pub const fn new( + x: i32, + z: i32, + offset: i32, + length: i32, + data: Vec, + ) -> DataLoc { + return DataLoc { + x, + z, + offset, + length, + data, + } + } +} + +impl MessageEncoder for DataLoc { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::DATA_LOC as i32; + } + + #[inline] + fn length(&self) -> i32 { + return -2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.x); + buf.p1(self.z); + buf.p2(self.offset); + buf.p2(self.length); + buf.pdata(&self.data, 0, self.data.len()); + } + + #[inline] + fn test(&self) -> usize { + return 6 + self.data.len(); + } +} + +// ---- + +pub struct DataLocDone { + x: i32, + z: i32, +} + +impl DataLocDone { + #[inline] + pub const fn new( + x: i32, + z: i32, + ) -> DataLocDone { + return DataLocDone { + x, + z, + } + } +} + +impl MessageEncoder for DataLocDone { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::DATA_LOC_DONE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.x); + buf.p1(self.z); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} diff --git a/src/out/enable_tracking.rs b/src/out/enable_tracking.rs new file mode 100644 index 0000000..d968026 --- /dev/null +++ b/src/out/enable_tracking.rs @@ -0,0 +1,32 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct EnableTracking {} + +impl EnableTracking { + #[inline] + pub const fn new() -> EnableTracking { + return EnableTracking {} + } +} + +impl MessageEncoder for EnableTracking { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::ENABLE_TRACKING as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 0; + } + + #[inline] + fn encode(&self, _: &mut Packet) {} + + #[inline] + fn test(&self) -> usize { + return 0; + } +} \ No newline at end of file diff --git a/src/out/finish_tracking.rs b/src/out/finish_tracking.rs new file mode 100644 index 0000000..e2e4584 --- /dev/null +++ b/src/out/finish_tracking.rs @@ -0,0 +1,32 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct FinishTracking {} + +impl FinishTracking { + #[inline] + pub const fn new() -> FinishTracking { + return FinishTracking {} + } +} + +impl MessageEncoder for FinishTracking { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::FINISH_TRACKING as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 0; + } + + #[inline] + fn encode(&self, _: &mut Packet) {} + + #[inline] + fn test(&self) -> usize { + return 0; + } +} \ No newline at end of file diff --git a/src/out/hint_arrow.rs b/src/out/hint_arrow.rs new file mode 100644 index 0000000..1ef679f --- /dev/null +++ b/src/out/hint_arrow.rs @@ -0,0 +1,85 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct HintArrow { + arrow: i32, + nid: i32, + pid: i32, + x: i32, + z: i32, + y: i32, +} + +impl HintArrow { + #[inline] + pub const fn new( + arrow: i32, + nid: i32, + pid: i32, + x: i32, + z: i32, + y: i32, + ) -> HintArrow { + return HintArrow { + arrow, + nid, + pid, + x, + z, + y, + } + } +} + +impl MessageEncoder for HintArrow { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::HINT_ARROW as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 6; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + match self.arrow { + 1 => { + buf.p1(self.arrow); + buf.p2(self.nid); + buf.p2(0); + buf.p1(0); + }, + 2..=6 => { + // 2 - 64, 64 offset - centered + // 3 - 0, 64 offset - far left + // 4 - 128, 64 offset - far right + // 5 - 64, 0 offset - bottom left + // 6 - 64, 128 offset - top left + buf.p1(self.arrow); + buf.p2(self.x); + buf.p2(self.z); + buf.p1(self.y); + }, + 10 => { + buf.p1(self.arrow); + buf.p2(self.pid); + buf.p2(0); + buf.p1(0); + }, + _ => { + buf.p1(-1); + buf.p2(0); + buf.p2(0); + buf.p1(0); + }, + } + } + + #[inline] + fn test(&self) -> usize { + return 6; + } +} \ No newline at end of file diff --git a/src/out/if_close.rs b/src/out/if_close.rs new file mode 100644 index 0000000..e856dce --- /dev/null +++ b/src/out/if_close.rs @@ -0,0 +1,32 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfClose {} + +impl IfClose { + #[inline] + pub const fn new() -> IfClose { + return IfClose {} + } +} + +impl MessageEncoder for IfClose { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_CLOSE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 0; + } + + #[inline] + fn encode(&self, _: &mut Packet) {} + + #[inline] + fn test(&self) -> usize { + return 0; + } +} \ No newline at end of file diff --git a/src/out/if_openchat.rs b/src/out/if_openchat.rs new file mode 100644 index 0000000..7fa549d --- /dev/null +++ b/src/out/if_openchat.rs @@ -0,0 +1,38 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfOpenChat { + component: i32, +} + +impl IfOpenChat { + #[inline] + pub const fn new(component:i32) -> IfOpenChat { + return IfOpenChat { + component, + } + } +} + +impl MessageEncoder for IfOpenChat { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_OPENCHAT as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/if_openmain.rs b/src/out/if_openmain.rs new file mode 100644 index 0000000..539549d --- /dev/null +++ b/src/out/if_openmain.rs @@ -0,0 +1,38 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfOpenMain { + component: i32, +} + +impl IfOpenMain { + #[inline] + pub const fn new(component:i32) -> IfOpenMain { + return IfOpenMain { + component, + } + } +} + +impl MessageEncoder for IfOpenMain { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_OPENMAIN as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/if_openmainside.rs b/src/out/if_openmainside.rs new file mode 100644 index 0000000..87a0d10 --- /dev/null +++ b/src/out/if_openmainside.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfOpenMainSide { + main: i32, + side: i32, +} + +impl IfOpenMainSide { + #[inline] + pub const fn new( + main: i32, + side: i32, + ) -> IfOpenMainSide { + return IfOpenMainSide { + main, + side, + } + } +} + +impl MessageEncoder for IfOpenMainSide { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_OPENMAIN_SIDE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 4; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.main); + buf.p2(self.side); + } + + #[inline] + fn test(&self) -> usize { + return 4; + } +} \ No newline at end of file diff --git a/src/out/if_openside.rs b/src/out/if_openside.rs new file mode 100644 index 0000000..1573324 --- /dev/null +++ b/src/out/if_openside.rs @@ -0,0 +1,38 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfOpenSide { + component: i32, +} + +impl IfOpenSide { + #[inline] + pub const fn new(component:i32) -> IfOpenSide { + return IfOpenSide { + component, + } + } +} + +impl MessageEncoder for IfOpenSide { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_OPENSIDE as i32 + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/if_setanim.rs b/src/out/if_setanim.rs new file mode 100644 index 0000000..ef53b7d --- /dev/null +++ b/src/out/if_setanim.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetAnim { + component: i32, + seq: i32, +} + +impl IfSetAnim { + #[inline] + pub const fn new( + component: i32, + seq: i32, + ) -> IfSetAnim { + return IfSetAnim { + component, + seq, + } + } +} + +impl MessageEncoder for IfSetAnim { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETANIM as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 4; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + buf.p2(self.seq); + } + + #[inline] + fn test(&self) -> usize { + return 4; + } +} \ No newline at end of file diff --git a/src/out/if_setcolour.rs b/src/out/if_setcolour.rs new file mode 100644 index 0000000..75e5b7d --- /dev/null +++ b/src/out/if_setcolour.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetColour { + component: i32, + colour: i32, +} + +impl IfSetColour { + #[inline] + pub const fn new( + component: i32, + colour: i32, + ) -> IfSetColour { + return IfSetColour { + component, + colour, + } + } +} + +impl MessageEncoder for IfSetColour { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETCOLOUR as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 4; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + buf.p2(self.colour); + } + + #[inline] + fn test(&self) -> usize { + return 4; + } +} \ No newline at end of file diff --git a/src/out/if_sethide.rs b/src/out/if_sethide.rs new file mode 100644 index 0000000..602e85b --- /dev/null +++ b/src/out/if_sethide.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetHide { + component: i32, + hidden: bool, +} + +impl IfSetHide { + #[inline] + pub const fn new( + component: i32, + hidden: bool, + ) -> IfSetHide { + return IfSetHide { + component, + hidden, + } + } +} + +impl MessageEncoder for IfSetHide { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETHIDE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 3; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + buf.p1(if self.hidden { 1 } else { 0 }); + } + + #[inline] + fn test(&self) -> usize { + return 3; + } +} \ No newline at end of file diff --git a/src/out/if_setmodel.rs b/src/out/if_setmodel.rs new file mode 100644 index 0000000..7756b2c --- /dev/null +++ b/src/out/if_setmodel.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetModel { + component: i32, + model: i32, +} + +impl IfSetModel { + #[inline] + pub const fn new( + component: i32, + model: i32, + ) -> IfSetModel { + return IfSetModel { + component, + model, + } + } +} + +impl MessageEncoder for IfSetModel { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETMODEL as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 4; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + buf.p2(self.model); + } + + #[inline] + fn test(&self) -> usize { + return 4; + } +} \ No newline at end of file diff --git a/src/out/if_setnpchead.rs b/src/out/if_setnpchead.rs new file mode 100644 index 0000000..c100bda --- /dev/null +++ b/src/out/if_setnpchead.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetNpcHead { + component: i32, + npc: i32, +} + +impl IfSetNpcHead { + #[inline] + pub const fn new( + component: i32, + npc: i32, + ) -> IfSetNpcHead { + return IfSetNpcHead { + component, + npc, + } + } +} + +impl MessageEncoder for IfSetNpcHead { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETNPCHEAD as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 4; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + buf.p2(self.npc); + } + + #[inline] + fn test(&self) -> usize { + return 4; + } +} \ No newline at end of file diff --git a/src/out/if_setobject.rs b/src/out/if_setobject.rs new file mode 100644 index 0000000..c7ff302 --- /dev/null +++ b/src/out/if_setobject.rs @@ -0,0 +1,48 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetObject { + component: i32, + obj: i32, + scale: i32, +} + +impl IfSetObject { + #[inline] + pub const fn new( + component: i32, + obj: i32, + scale: i32, + ) -> IfSetObject { + return IfSetObject { + component, + obj, + scale, + } + } +} + +impl MessageEncoder for IfSetObject { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETOBJECT as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 6; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + buf.p2(self.obj); + buf.p2(self.scale); + } + + #[inline] + fn test(&self) -> usize { + return 6; + } +} \ No newline at end of file diff --git a/src/out/if_setplayerhead.rs b/src/out/if_setplayerhead.rs new file mode 100644 index 0000000..4bd687a --- /dev/null +++ b/src/out/if_setplayerhead.rs @@ -0,0 +1,40 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetPlayerHead { + component: i32, +} + +impl IfSetPlayerHead { + #[inline] + pub const fn new( + component: i32, + ) -> IfSetPlayerHead { + return IfSetPlayerHead { + component, + } + } +} + +impl MessageEncoder for IfSetPlayerHead { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETPLAYERHEAD as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/if_setposition.rs b/src/out/if_setposition.rs new file mode 100644 index 0000000..6f35166 --- /dev/null +++ b/src/out/if_setposition.rs @@ -0,0 +1,48 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetPosition { + component: i32, + x: i32, + y: i32, +} + +impl IfSetPosition { + #[inline] + pub const fn new( + component: i32, + x: i32, + y: i32, + ) -> IfSetPosition { + return IfSetPosition { + component, + x, + y, + } + } +} + +impl MessageEncoder for IfSetPosition { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETPOSITION as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 6; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + buf.p2(self.x); + buf.p2(self.y); + } + + #[inline] + fn test(&self) -> usize { + return 6; + } +} \ No newline at end of file diff --git a/src/out/if_setrecol.rs b/src/out/if_setrecol.rs new file mode 100644 index 0000000..d48cafe --- /dev/null +++ b/src/out/if_setrecol.rs @@ -0,0 +1,48 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetRecol { + component: i32, + src: i32, + dst: i32, +} + +impl IfSetRecol { + #[inline] + pub const fn new( + component: i32, + src: i32, + dst: i32, + ) -> IfSetRecol { + return IfSetRecol { + component, + src, + dst, + } + } +} + +impl MessageEncoder for IfSetRecol { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETRECOL as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 6; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + buf.p2(self.src); + buf.p2(self.dst); + } + + #[inline] + fn test(&self) -> usize { + return 6; + } +} \ No newline at end of file diff --git a/src/out/if_settab.rs b/src/out/if_settab.rs new file mode 100644 index 0000000..0102d6b --- /dev/null +++ b/src/out/if_settab.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetTab { + component: i32, + tab: i32, +} + +impl IfSetTab { + #[inline] + pub const fn new( + component: i32, + tab: i32, + ) -> IfSetTab { + return IfSetTab { + component, + tab, + } + } +} + +impl MessageEncoder for IfSetTab { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETTAB as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 3; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + buf.p1(self.tab); + } + + #[inline] + fn test(&self) -> usize { + return 3; + } +} \ No newline at end of file diff --git a/src/out/if_settabactive.rs b/src/out/if_settabactive.rs new file mode 100644 index 0000000..0d55973 --- /dev/null +++ b/src/out/if_settabactive.rs @@ -0,0 +1,40 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetTabActive { + tab: i32, +} + +impl IfSetTabActive { + #[inline] + pub const fn new( + tab: i32, + ) -> IfSetTabActive { + return IfSetTabActive { + tab, + } + } +} + +impl MessageEncoder for IfSetTabActive { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETTAB_ACTIVE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 1; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.tab); + } + + #[inline] + fn test(&self) -> usize { + return 1; + } +} \ No newline at end of file diff --git a/src/out/if_settext.rs b/src/out/if_settext.rs new file mode 100644 index 0000000..fd9f8f0 --- /dev/null +++ b/src/out/if_settext.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct IfSetText { + component: i32, + text: String, +} + +impl IfSetText { + #[inline] + pub const fn new( + component: i32, + text: String, + ) -> IfSetText { + return IfSetText { + component, + text, + } + } +} + +impl MessageEncoder for IfSetText { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::IF_SETTEXT as i32; + } + + #[inline] + fn length(&self) -> i32 { + return -2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + buf.pjstr(&self.text, 10); + } + + #[inline] + fn test(&self) -> usize { + return 3 + self.text.len(); + } +} \ No newline at end of file diff --git a/src/out/last_login_info.rs b/src/out/last_login_info.rs new file mode 100644 index 0000000..51767ce --- /dev/null +++ b/src/out/last_login_info.rs @@ -0,0 +1,52 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct LastLoginInfo { + last_ip: i32, + days_since_login: i32, + days_since_recovery: i32, + messages: i32, +} + +impl LastLoginInfo { + #[inline] + pub const fn new( + last_ip: i32, + days_since_login: i32, + days_since_recovery: i32, + messages: i32, + ) -> LastLoginInfo { + return LastLoginInfo { + last_ip, + days_since_login, + days_since_recovery, + messages, + } + } +} + +impl MessageEncoder for LastLoginInfo { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::LAST_LOGIN_INFO as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 9; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p4(self.last_ip); + buf.p2(self.days_since_login); + buf.p1(self.days_since_recovery); + buf.p2(self.messages); + } + + #[inline] + fn test(&self) -> usize { + return 9; + } +} \ No newline at end of file diff --git a/src/out/loc_addchange.rs b/src/out/loc_addchange.rs new file mode 100644 index 0000000..0a02fdb --- /dev/null +++ b/src/out/loc_addchange.rs @@ -0,0 +1,51 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct LocAddChange { + coord: i32, + loc: i32, + shape: i32, + angle: i32, +} + +impl LocAddChange { + #[inline] + pub const fn new( + coord: i32, + loc: i32, + shape: i32, + angle: i32, + ) -> LocAddChange { + return LocAddChange { + coord, + loc, + shape, + angle, + } + } +} + +impl MessageEncoder for LocAddChange { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::LOC_ADD_CHANGE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 4; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.coord); + buf.p1((self.shape << 2) | (self.angle & 0x3)); + buf.p2(self.loc); + } + + #[inline] + fn test(&self) -> usize { + return 4; + } +} \ No newline at end of file diff --git a/src/out/loc_anim.rs b/src/out/loc_anim.rs new file mode 100644 index 0000000..104d696 --- /dev/null +++ b/src/out/loc_anim.rs @@ -0,0 +1,51 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct LocAnim { + coord: i32, + shape: i32, + angle: i32, + seq: i32, +} + +impl LocAnim { + #[inline] + pub const fn new( + coord: i32, + shape: i32, + angle: i32, + seq: i32, + ) -> LocAnim { + return LocAnim { + coord, + shape, + angle, + seq, + } + } +} + +impl MessageEncoder for LocAnim { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::LOC_ANIM as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 4; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.coord); + buf.p1((self.shape << 2) | (self.angle & 0x3)); + buf.p2(self.seq); + } + + #[inline] + fn test(&self) -> usize { + return 4; + } +} \ No newline at end of file diff --git a/src/out/loc_del.rs b/src/out/loc_del.rs new file mode 100644 index 0000000..0d60ac5 --- /dev/null +++ b/src/out/loc_del.rs @@ -0,0 +1,47 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct LocDel { + coord: i32, + shape: i32, + angle: i32, +} + +impl LocDel { + #[inline] + pub const fn new( + coord: i32, + shape: i32, + angle: i32, + ) -> LocDel { + return LocDel { + coord, + shape, + angle, + } + } +} + +impl MessageEncoder for LocDel { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::LOC_DEL as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.coord); + buf.p1((self.shape << 2) | (self.angle & 0x3)); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/loc_merge.rs b/src/out/loc_merge.rs new file mode 100644 index 0000000..1c407d8 --- /dev/null +++ b/src/out/loc_merge.rs @@ -0,0 +1,85 @@ +use crate::coord::CoordGrid; +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct LocMerge { + coord: i32, + src_x: i32, + src_z: i32, + shape: i32, + angle: i32, + loc: i32, + start: i32, + end: i32, + pid: i32, + east: i32, + south: i32, + west: i32, + north: i32, +} + +impl LocMerge { + #[inline] + pub const fn new( + src_x: i32, + src_z: i32, + shape: i32, + angle: i32, + loc: i32, + start: i32, + end: i32, + pid: i32, + east: i32, + south: i32, + west: i32, + north: i32, + ) -> LocMerge { + return LocMerge { + coord: CoordGrid::pack_zone_coord(src_x as u16, src_z as u16) as i32, + src_x, + src_z, + shape, + angle, + loc, + start, + end, + pid, + east, + south, + west, + north, + } + } +} + +impl MessageEncoder for LocMerge { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::LOC_MERGE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 14; + } + #[inline] + + fn encode(&self, buf: &mut Packet) { + buf.p1(self.coord); + buf.p1((self.shape << 2) | (self.angle & 0x3)); + buf.p2(self.loc); + buf.p2(self.start); + buf.p2(self.end); + buf.p2(self.pid); + buf.p1(self.east - self.src_x); + buf.p1(self.south - self.src_z); + buf.p1(self.west - self.src_x); + buf.p1(self.north - self.src_z); + } + + #[inline] + fn test(&self) -> usize { + return 14; + } +} \ No newline at end of file diff --git a/src/out/logout.rs b/src/out/logout.rs new file mode 100644 index 0000000..15ae191 --- /dev/null +++ b/src/out/logout.rs @@ -0,0 +1,32 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct Logout {} + +impl Logout { + #[inline] + pub const fn new() -> Logout { + return Logout {} + } +} + +impl MessageEncoder for Logout { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::LOGOUT as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 0; + } + + #[inline] + fn encode(&self, _: &mut Packet) {} + + #[inline] + fn test(&self) -> usize { + return 0; + } +} \ No newline at end of file diff --git a/src/out/map_anim.rs b/src/out/map_anim.rs new file mode 100644 index 0000000..962f2ca --- /dev/null +++ b/src/out/map_anim.rs @@ -0,0 +1,52 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct MapAnim { + coord: i32, + spotanim: i32, + height: i32, + delay: i32, +} + +impl MapAnim { + #[inline] + pub const fn new( + coord: i32, + spotanim: i32, + height: i32, + delay: i32, + ) -> MapAnim { + return MapAnim { + coord, + spotanim, + height, + delay, + } + } +} + +impl MessageEncoder for MapAnim { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::MAP_ANIM as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 6; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.coord); + buf.p2(self.spotanim); + buf.p1(self.height); + buf.p2(self.delay); + } + + #[inline] + fn test(&self) -> usize { + return 6; + } +} \ No newline at end of file diff --git a/src/out/map_projanim.rs b/src/out/map_projanim.rs new file mode 100644 index 0000000..61d71ef --- /dev/null +++ b/src/out/map_projanim.rs @@ -0,0 +1,86 @@ +use crate::coord::CoordGrid; +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct MapProjAnim { + coord: i32, + src_x: i32, + src_z: i32, + dst_x: i32, + dst_z: i32, + target: i32, + spotanim: i32, + src_height: i32, + dst_height: i32, + start: i32, + end: i32, + peak: i32, + arc: i32, +} + +impl MapProjAnim { + #[inline] + pub const fn new( + src_x: i32, + src_z: i32, + dst_x: i32, + dst_z: i32, + target: i32, + spotanim: i32, + src_height: i32, + dst_height: i32, + start: i32, + end: i32, + peak: i32, + arc: i32, + ) -> MapProjAnim { + return MapProjAnim { + coord: CoordGrid::pack_zone_coord(src_x as u16, src_z as u16) as i32, + src_x, + src_z, + dst_x, + dst_z, + target, + spotanim, + src_height, + dst_height, + start, + end, + peak, + arc, + } + } +} + +impl MessageEncoder for MapProjAnim { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::MAP_PROJANIM as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 15; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.coord); + buf.p1(self.dst_x - self.src_x); + buf.p1(self.dst_z - self.src_z); + buf.p2(self.target); // 0: coord, > 0: npc, < 0: player + buf.p2(self.spotanim); + buf.p1(self.src_height); + buf.p1(self.dst_height); + buf.p2(self.start); + buf.p2(self.end); + buf.p1(self.peak); + buf.p1(self.arc); + } + + #[inline] + fn test(&self) -> usize { + return 15; + } +} \ No newline at end of file diff --git a/src/out/message_game.rs b/src/out/message_game.rs new file mode 100644 index 0000000..2d0bc51 --- /dev/null +++ b/src/out/message_game.rs @@ -0,0 +1,38 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct MessageGame { + msg: String, +} + +impl MessageGame { + #[inline] + pub const fn new(msg: String) -> MessageGame { + return MessageGame { + msg, + } + } +} + +impl MessageEncoder for MessageGame { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::MESSAGE_GAME as i32 + } + + #[inline] + fn length(&self) -> i32 { + return -1; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.pjstr(&self.msg, 10); + } + + #[inline] + fn test(&self) -> usize { + return 1 + self.msg.len(); + } +} \ No newline at end of file diff --git a/src/out/message_private.rs b/src/out/message_private.rs new file mode 100644 index 0000000..a32d792 --- /dev/null +++ b/src/out/message_private.rs @@ -0,0 +1,57 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct MessagePrivateOut { + from: i64, + id: i32, + staff_mod_level: i32, + msg: Vec, +} + +impl MessagePrivateOut { + #[inline] + pub const fn new( + from: i64, + id: i32, + staff_mod_level: i32, + msg: Vec, + ) -> MessagePrivateOut { + return MessagePrivateOut { + from, + id, + staff_mod_level, + msg, + } + } +} + +impl MessageEncoder for MessagePrivateOut { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::MESSAGE_PRIVATE as i32 + } + + #[inline] + fn length(&self) -> i32 { + return -1; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + let mut staff_mod_level = self.staff_mod_level; + if staff_mod_level > 0 { + staff_mod_level += 1; + } + + buf.p8(self.from); + buf.p4(self.id); + buf.p1(staff_mod_level); + buf.pdata(&self.msg, 0, self.msg.len()) + } + + #[inline] + fn test(&self) -> usize { + return 14 + self.msg.len(); + } +} \ No newline at end of file diff --git a/src/out/midi_jingle.rs b/src/out/midi_jingle.rs new file mode 100644 index 0000000..afed196 --- /dev/null +++ b/src/out/midi_jingle.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct MidiJingle { + delay: i32, + data: Vec, +} + +impl MidiJingle { + #[inline] + pub const fn new( + delay: i32, + data: Vec, + ) -> MidiJingle { + return MidiJingle { + delay, + data, + } + } +} + +impl MessageEncoder for MidiJingle { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::MIDI_JINGLE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return -2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.delay); + buf.pdata(&self.data, 0, self.data.len()); + } + + #[inline] + fn test(&self) -> usize { + return 2 + self.data.len(); + } +} \ No newline at end of file diff --git a/src/out/midi_song.rs b/src/out/midi_song.rs new file mode 100644 index 0000000..e66a511 --- /dev/null +++ b/src/out/midi_song.rs @@ -0,0 +1,48 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct MidiSong { + name: String, + crc: i32, + length: i32, +} + +impl MidiSong { + #[inline] + pub const fn new( + name: String, + crc: i32, + length: i32, + ) -> MidiSong { + return MidiSong { + name, + crc, + length, + } + } +} + +impl MessageEncoder for MidiSong { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::MIDI_SONG as i32; + } + + #[inline] + fn length(&self) -> i32 { + return -1; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.pjstr(&self.name, 10); + buf.p4(self.crc); + buf.p4(self.length); + } + + #[inline] + fn test(&self) -> usize { + return 9 + self.name.len(); + } +} \ No newline at end of file diff --git a/src/out/mod.rs b/src/out/mod.rs new file mode 100644 index 0000000..b6cdd78 --- /dev/null +++ b/src/out/mod.rs @@ -0,0 +1,69 @@ +pub mod if_openmain; +pub mod if_openside; +pub mod message_game; +pub mod player_info; +pub mod npc_info; +pub mod cam_lookat; +pub mod cam_moveto; +pub mod cam_reset; +pub mod cam_shake; +pub mod chat_filter_settings; +pub mod data_land; +pub mod data_loc; +pub mod enable_tracking; +pub mod finish_tracking; +pub mod hint_arrow; +pub mod if_close; +pub mod if_openchat; +pub mod if_openmainside; +pub mod if_settab; +pub mod if_setanim; +pub mod if_setcolour; +pub mod if_sethide; +pub mod if_setmodel; +pub mod if_setnpchead; +pub mod if_setobject; +pub mod if_setplayerhead; +pub mod if_setposition; +pub mod if_setrecol; +pub mod if_settext; +pub mod if_settabactive; +pub mod last_login_info; +pub mod loc_addchange; +pub mod loc_anim; +pub mod loc_del; +pub mod loc_merge; +pub mod logout; +pub mod map_anim; +pub mod map_projanim; +pub mod message_private; +pub mod midi_jingle; +pub mod midi_song; +pub mod obj_add; +pub mod obj_count; +pub mod obj_del; +pub mod obj_reveal; +pub mod count_dialog; +pub mod rebuild_normal; +pub mod reset_anims; +pub mod reset_clientvarcache; +pub mod set_multiway; +pub mod synth_sound; +pub mod tut_flash; +pub mod tut_open; +pub mod unset_map_flag; +pub mod update_friendlist; +pub mod update_ignorelist; +pub mod update_inv_stop_transmit; +pub mod update_runenergy; +pub mod update_runweight; +pub mod update_reboot_timer; +pub mod update_stat; +pub mod update_pid; +pub mod update_zone_full_follows; +pub mod update_zone_partial_follows; +pub mod update_zone_partial_enclosed; +pub mod varp_large; +pub mod varp_small; +pub mod update_inv_full; +pub mod update_inv_partial; \ No newline at end of file diff --git a/src/out/npc_info.rs b/src/out/npc_info.rs new file mode 100644 index 0000000..bf66703 --- /dev/null +++ b/src/out/npc_info.rs @@ -0,0 +1,307 @@ +use crate::build::BuildArea; +use crate::coord::CoordGrid; +use crate::grid::ZoneMap; +use crate::message::{NpcInfoFaceCoord, NpcInfoFaceEntity}; +use crate::npc::Npc; +use crate::packet::Packet; +use crate::player::Player; +use crate::prot::NpcInfoProt; +use crate::renderer::NpcRenderer; + +pub struct NpcInfo { + buf: Packet, + updates: Packet, +} + +impl NpcInfo { + const BITS_ADD: usize = 13 + 11 + 5 + 5 + 1; + const BITS_RUN: usize = 1 + 2 + 3 + 3 + 1; + const BITS_WALK: usize = 1 + 2 + 3 + 1; + const BITS_EXTEND: usize = 1 + 2; + + #[inline] + pub fn new() -> NpcInfo { + return NpcInfo { + buf: Packet::new(5000), + updates: Packet::new(5000), + } + } + + #[inline] + pub fn encode( + &mut self, + renderer: &mut NpcRenderer, + npcs: &mut [Option], + map: &mut ZoneMap, + player: &mut Player, + dx: i32, + dz: i32, + rebuild: bool, + ) -> Vec { + let build: &mut BuildArea = &mut player.build; + + if rebuild || dx > BuildArea::PREFERRED_VIEW_DISTANCE as i32 || dz > BuildArea::PREFERRED_VIEW_DISTANCE as i32 { + build.rebuild_npcs(); + } + + self.buf.pos = 0; + self.buf.bit_pos = 0; + self.updates.pos = 0; + self.updates.bit_pos = 0; + + self.buf.bits(); + let bytes: usize = self.write_npcs(npcs, renderer, player, 0); + self.write_new_npcs(map, npcs, renderer, player, bytes); + if self.updates.pos > 0 { + self.buf.pbit(13, 8191); + self.buf.bytes(); + self.buf.pdata(&self.updates.data, 0, self.updates.pos); + } else { + self.buf.bytes(); + } + return unsafe { self.buf.data.get_unchecked(0..self.buf.pos).to_vec() }; + } + + #[inline] + fn write_npcs( + &mut self, + npcs: &mut [Option], + renderer: &mut NpcRenderer, + player: &mut Player, + mut bytes: usize + ) -> usize { + self.buf.pbit(8, player.build.npcs.len() as i32); + for nid in player.build.npcs.iter() { + match unsafe { &mut *npcs.as_mut_ptr().add(nid as usize) } { + Some(other) => { + if other.nid == -1 || other.tele || other.coord.y() != player.coord.y() || !CoordGrid::within_distance_sw(&player.coord, &other.coord, BuildArea::PREFERRED_VIEW_DISTANCE) || !other.active { + self.remove(player, nid); + other.observers = (other.observers - 1).max(0); + } else { + let len: usize = renderer.highdefinitions(nid); + if other.run_dir != -1 { + self.run(renderer, other, len > 0 && self.fits(bytes + 1, NpcInfo::BITS_RUN, len)); + } else if other.walk_dir != -1 { + self.walk(renderer, other, len > 0 && self.fits(bytes + 1, NpcInfo::BITS_WALK, len)); + } else if len > 0 && self.fits(bytes + 1, NpcInfo::BITS_EXTEND, len) { + self.extend(renderer, other); + } else { + self.idle(); + } + bytes += len + 1; + } + } + _ => self.remove(player, nid), + } + } + return bytes; + } + + #[inline] + fn write_new_npcs( + &mut self, + map: &mut ZoneMap, + npcs: &mut [Option], + renderer: &mut NpcRenderer, + player: &mut Player, + mut bytes: usize + ) { + for nid in player.build.get_nearby_npcs(npcs, map, player.coord.x(), player.coord.y(), player.coord.z()) { + if player.build.npcs.contains(nid) { + continue; + } + if player.build.npcs.len() >= BuildArea::PREFERRED_NPCS as usize { + return; + } + if let Some(other) = unsafe { &mut *npcs.as_mut_ptr().add(nid as usize) } { + let len: usize = renderer.lowdefinitions(nid) + renderer.highdefinitions(nid); + // bits to add npc + extended info size + bits to break loop (13) + if !self.fits(bytes + 1, NpcInfo::BITS_ADD, len) { + // more npcs get added next tick + return; + } + self.add(renderer, player, other, other.nid, other.ntype, other.coord.x() as i32 - player.coord.x() as i32, other.coord.z() as i32 - player.coord.z() as i32); + other.observers = other.observers + 1; + bytes += len + 1; + } + } + } + + #[inline] + fn add( + &mut self, + renderer: &mut NpcRenderer, + player: &mut Player, + other: &Npc, + nid: i32, + ntype: i32, + x: i32, + z: i32, + ) { + self.buf.pbit(13, nid); + self.buf.pbit(11, ntype); + self.buf.pbit(5, x); + self.buf.pbit(5, z); + self.buf.pbit(1, 1); // extend + self.lowdefinition(renderer, other); + player.build.npcs.insert(other.nid); + } + + #[inline] + fn remove( + &mut self, + player: &mut Player, + other: i32 + ) { + self.buf.pbit(1, 1); + self.buf.pbit(2, 3); + player.build.npcs.remove(other); + } + + #[inline] + fn run( + &mut self, + renderer: &mut NpcRenderer, + other: &Npc, + extend: bool + ) { + self.buf.pbit(1, 1); + self.buf.pbit(2, 2); + self.buf.pbit(3, other.walk_dir as i32); + self.buf.pbit(3, other.run_dir as i32); + if extend { + self.buf.pbit(1, 1); + self.highdefinition(renderer, other); + } else { + self.buf.pbit(1, 0); + } + } + + #[inline] + fn walk( + &mut self, + renderer: &mut NpcRenderer, + other: &Npc, + extend: bool + ) { + self.buf.pbit(1, 1); + self.buf.pbit(2, 1); + self.buf.pbit(3, other.walk_dir as i32); + if extend { + self.buf.pbit(1, 1); + self.highdefinition(renderer, other); + } else { + self.buf.pbit(1, 0); + } + } + + #[inline] + fn extend( + &mut self, + renderer: &mut NpcRenderer, + other: &Npc + ) { + self.buf.pbit(1, 1); + self.buf.pbit(2, 0); + self.highdefinition(renderer, other); + } + + #[inline] + fn idle(&mut self) { + self.buf.pbit(1, 0); + } + + #[inline] + fn highdefinition( + &mut self, + renderer: &mut NpcRenderer, + other: &Npc + ) { + self.write_blocks(renderer, other.nid, other.masks); + } + + #[inline] + fn lowdefinition( + &mut self, + renderer: &mut NpcRenderer, + other: &Npc + ) { + let nid: i32 = other.nid; + let mut masks: u32 = other.masks; + + if other.face_entity != -1 && !renderer.has(nid, NpcInfoProt::FACE_ENTITY) { + renderer.cache( + nid, + &NpcInfoFaceEntity::new(other.face_entity), + NpcInfoProt::FACE_ENTITY, + ); + masks |= NpcInfoProt::FACE_ENTITY as u32; + } + + if !renderer.has(nid, NpcInfoProt::FACE_COORD) { + if other.face_x != -1 { + renderer.cache( + nid, + &NpcInfoFaceCoord::new(other.face_x, other.face_z), + NpcInfoProt::FACE_COORD, + ); + } else if other.orientation_x != -1 { + renderer.cache( + nid, + &NpcInfoFaceCoord::new(other.orientation_x, other.orientation_z), + NpcInfoProt::FACE_COORD, + ); + } else { + renderer.cache( + nid, + &NpcInfoFaceCoord::new(CoordGrid::fine(other.coord.x(), 1), CoordGrid::fine(other.coord.z(), 1)), + NpcInfoProt::FACE_COORD, + ); + } + } + + masks |= NpcInfoProt::FACE_COORD as u32; + + self.write_blocks(renderer, nid, masks); + } + + #[inline] + fn write_blocks( + &mut self, + renderer: &mut NpcRenderer, + nid: i32, + masks: u32, + ) { + self.updates.p1((masks & 0xff) as i32); + // ---- + // an optimization *could* be made where all of these are just 1 block of bytes... + // the same could NOT be done for players bcuz of how exact_move works... + if masks & NpcInfoProt::ANIM as u32 != 0 { + renderer.write(&mut self.updates, nid, NpcInfoProt::ANIM); + } + if masks & NpcInfoProt::FACE_ENTITY as u32 != 0 { + renderer.write(&mut self.updates, nid, NpcInfoProt::FACE_ENTITY); + } + if masks & NpcInfoProt::SAY as u32 != 0 { + renderer.write(&mut self.updates, nid, NpcInfoProt::SAY); + } + if masks & NpcInfoProt::DAMAGE as u32 != 0 { + renderer.write(&mut self.updates, nid, NpcInfoProt::DAMAGE); + } + if masks & NpcInfoProt::CHANGE_TYPE as u32 != 0 { + renderer.write(&mut self.updates, nid, NpcInfoProt::CHANGE_TYPE); + } + if masks & NpcInfoProt::SPOT_ANIM as u32 != 0 { + renderer.write(&mut self.updates, nid, NpcInfoProt::SPOT_ANIM); + } + if masks & NpcInfoProt::FACE_COORD as u32 != 0 { + renderer.write(&mut self.updates, nid, NpcInfoProt::FACE_COORD); + } + } + + #[inline] + const fn fits(&self, bytes: usize, bits_to_add: usize, bytes_to_add: usize) -> bool { + // 7 aligns to the next byte + return ((self.buf.bit_pos + bits_to_add + 7) >> 3) + bytes + bytes_to_add <= 4997; + } +} \ No newline at end of file diff --git a/src/out/obj_add.rs b/src/out/obj_add.rs new file mode 100644 index 0000000..dbf8b47 --- /dev/null +++ b/src/out/obj_add.rs @@ -0,0 +1,48 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct ObjAdd { + coord: i32, + obj: i32, + count: i32, +} + +impl ObjAdd { + #[inline] + pub const fn new( + coord: i32, + obj: i32, + count: i32, + ) -> ObjAdd { + return ObjAdd { + coord, + obj, + count, + } + } +} + +impl MessageEncoder for ObjAdd { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::OBJ_ADD as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 5; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.coord); + buf.p2(self.obj); + buf.p2(self.count.min(65535)); + } + + #[inline] + fn test(&self) -> usize { + return 5; + } +} \ No newline at end of file diff --git a/src/out/obj_count.rs b/src/out/obj_count.rs new file mode 100644 index 0000000..7173928 --- /dev/null +++ b/src/out/obj_count.rs @@ -0,0 +1,52 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct ObjCount { + coord: i32, + obj: i32, + old_count: i32, + new_count: i32, +} + +impl ObjCount { + #[inline] + pub const fn new( + coord: i32, + obj: i32, + old_count: i32, + new_count: i32, + ) -> ObjCount { + return ObjCount { + coord, + obj, + old_count, + new_count, + } + } +} + +impl MessageEncoder for ObjCount { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::OBJ_COUNT as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 7; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.coord); + buf.p2(self.obj); + buf.p2(self.old_count.min(65535)); + buf.p2(self.new_count.min(65535)); + } + + #[inline] + fn test(&self) -> usize { + return 7; + } +} \ No newline at end of file diff --git a/src/out/obj_del.rs b/src/out/obj_del.rs new file mode 100644 index 0000000..6fd1e37 --- /dev/null +++ b/src/out/obj_del.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct ObjDel { + coord: i32, + obj: i32, +} + +impl ObjDel { + #[inline] + pub const fn new( + coord: i32, + obj: i32, + ) -> ObjDel { + return ObjDel { + coord, + obj, + } + } +} + +impl MessageEncoder for ObjDel { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::OBJ_DEL as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 3; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.coord); + buf.p2(self.obj); + } + + #[inline] + fn test(&self) -> usize { + return 3; + } +} \ No newline at end of file diff --git a/src/out/obj_reveal.rs b/src/out/obj_reveal.rs new file mode 100644 index 0000000..1328258 --- /dev/null +++ b/src/out/obj_reveal.rs @@ -0,0 +1,52 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct ObjReveal { + coord: i32, + obj: i32, + count: i32, + receiver: i32, +} + +impl ObjReveal { + #[inline] + pub const fn new( + coord: i32, + obj: i32, + count: i32, + receiver: i32, + ) -> ObjReveal { + return ObjReveal { + coord, + obj, + count, + receiver, + } + } +} + +impl MessageEncoder for ObjReveal { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::OBJ_REVEAL as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 7; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.coord); + buf.p2(self.obj); + buf.p2(self.count.min(65535)); + buf.p2(self.receiver); + } + + #[inline] + fn test(&self) -> usize { + return 7; + } +} \ No newline at end of file diff --git a/src/info.rs b/src/out/player_info.rs similarity index 57% rename from src/info.rs rename to src/out/player_info.rs index c2bbbd0..737d397 100644 --- a/src/info.rs +++ b/src/out/player_info.rs @@ -1,12 +1,11 @@ use crate::build::BuildArea; use crate::coord::CoordGrid; use crate::grid::ZoneMap; -use crate::message::{NpcInfoFaceCoord, NpcInfoFaceEntity, PlayerInfoFaceCoord, PlayerInfoFaceEntity}; -use crate::npc::Npc; +use crate::message::{PlayerInfoFaceCoord, PlayerInfoFaceEntity}; use crate::packet::Packet; use crate::player::Player; -use crate::prot::{NpcInfoProt, PlayerInfoProt}; -use crate::renderer::{NpcRenderer, PlayerRenderer}; +use crate::prot::PlayerInfoProt; +use crate::renderer::PlayerRenderer; use crate::visibility::Visibility; use std::collections::HashMap; @@ -32,7 +31,6 @@ impl PlayerInfo { #[inline] pub fn encode( &mut self, - pos: usize, renderer: &mut PlayerRenderer, players: &[Option], map: &mut ZoneMap, @@ -57,7 +55,7 @@ impl PlayerInfo { self.buf.bits(); let bytes1: usize = self.write_local_player(renderer, player); - let bytes2: usize = self.write_players(players, renderer, player, bytes1 + pos); + let bytes2: usize = self.write_players(players, renderer, player, bytes1); self.write_new_players(map, players, renderer, grid, player, bytes2); if self.updates.pos > 0 { self.buf.pbit(11, 2047); @@ -401,305 +399,6 @@ impl PlayerInfo { } } - #[inline] - const fn fits(&self, bytes: usize, bits_to_add: usize, bytes_to_add: usize) -> bool { - // 7 aligns to the next byte - return ((self.buf.bit_pos + bits_to_add + 7) >> 3) + bytes + bytes_to_add <= 4997; - } -} - -pub struct NpcInfo { - buf: Packet, - updates: Packet, -} - -impl NpcInfo { - const BITS_ADD: usize = 13 + 11 + 5 + 5 + 1; - const BITS_RUN: usize = 1 + 2 + 3 + 3 + 1; - const BITS_WALK: usize = 1 + 2 + 3 + 1; - const BITS_EXTEND: usize = 1 + 2; - - #[inline] - pub fn new() -> NpcInfo { - return NpcInfo { - buf: Packet::new(5000), - updates: Packet::new(5000), - } - } - - #[inline] - pub fn encode( - &mut self, - pos: usize, - renderer: &mut NpcRenderer, - npcs: &mut [Option], - map: &mut ZoneMap, - player: &mut Player, - dx: i32, - dz: i32, - rebuild: bool, - ) -> Vec { - let build: &mut BuildArea = &mut player.build; - - if rebuild || dx > BuildArea::PREFERRED_VIEW_DISTANCE as i32 || dz > BuildArea::PREFERRED_VIEW_DISTANCE as i32 { - build.rebuild_npcs(); - } - - self.buf.pos = 0; - self.buf.bit_pos = 0; - self.updates.pos = 0; - self.updates.bit_pos = 0; - - self.buf.bits(); - let bytes: usize = self.write_npcs(npcs, renderer, player, pos); - self.write_new_npcs(map, npcs, renderer, player, bytes); - if self.updates.pos > 0 { - self.buf.pbit(13, 8191); - self.buf.bytes(); - self.buf.pdata(&self.updates.data, 0, self.updates.pos); - } else { - self.buf.bytes(); - } - return unsafe { self.buf.data.get_unchecked(0..self.buf.pos).to_vec() }; - } - - #[inline] - fn write_npcs( - &mut self, - npcs: &mut [Option], - renderer: &mut NpcRenderer, - player: &mut Player, - mut bytes: usize - ) -> usize { - self.buf.pbit(8, player.build.npcs.len() as i32); - for nid in player.build.npcs.iter() { - match unsafe { &mut *npcs.as_mut_ptr().add(nid as usize) } { - Some(other) => { - if other.nid == -1 || other.tele || other.coord.y() != player.coord.y() || !CoordGrid::within_distance_sw(&player.coord, &other.coord, BuildArea::PREFERRED_VIEW_DISTANCE) || !other.active { - self.remove(player, nid); - other.observers = (other.observers - 1).max(0); - } else { - let len: usize = renderer.highdefinitions(nid); - if other.run_dir != -1 { - self.run(renderer, other, len > 0 && self.fits(bytes + 1, NpcInfo::BITS_RUN, len)); - } else if other.walk_dir != -1 { - self.walk(renderer, other, len > 0 && self.fits(bytes + 1, NpcInfo::BITS_WALK, len)); - } else if len > 0 && self.fits(bytes + 1, NpcInfo::BITS_EXTEND, len) { - self.extend(renderer, other); - } else { - self.idle(); - } - bytes += len + 1; - } - } - _ => self.remove(player, nid), - } - } - return bytes; - } - - #[inline] - fn write_new_npcs( - &mut self, - map: &mut ZoneMap, - npcs: &mut [Option], - renderer: &mut NpcRenderer, - player: &mut Player, - mut bytes: usize - ) { - for nid in player.build.get_nearby_npcs(npcs, map, player.coord.x(), player.coord.y(), player.coord.z()) { - if player.build.npcs.contains(nid) { - continue; - } - if player.build.npcs.len() >= BuildArea::PREFERRED_NPCS as usize { - return; - } - if let Some(other) = unsafe { &mut *npcs.as_mut_ptr().add(nid as usize) } { - let len: usize = renderer.lowdefinitions(nid) + renderer.highdefinitions(nid); - // bits to add npc + extended info size + bits to break loop (13) - if !self.fits(bytes + 1, NpcInfo::BITS_ADD, len) { - // more npcs get added next tick - return; - } - self.add(renderer, player, other, other.nid, other.ntype, other.coord.x() as i32 - player.coord.x() as i32, other.coord.z() as i32 - player.coord.z() as i32); - other.observers = other.observers + 1; - bytes += len + 1; - } - } - } - - #[inline] - fn add( - &mut self, - renderer: &mut NpcRenderer, - player: &mut Player, - other: &Npc, - nid: i32, - ntype: i32, - x: i32, - z: i32, - ) { - self.buf.pbit(13, nid); - self.buf.pbit(11, ntype); - self.buf.pbit(5, x); - self.buf.pbit(5, z); - self.buf.pbit(1, 1); // extend - self.lowdefinition(renderer, other); - player.build.npcs.insert(other.nid); - } - - #[inline] - fn remove( - &mut self, - player: &mut Player, - other: i32 - ) { - self.buf.pbit(1, 1); - self.buf.pbit(2, 3); - player.build.npcs.remove(other); - } - - #[inline] - fn run( - &mut self, - renderer: &mut NpcRenderer, - other: &Npc, - extend: bool - ) { - self.buf.pbit(1, 1); - self.buf.pbit(2, 2); - self.buf.pbit(3, other.walk_dir as i32); - self.buf.pbit(3, other.run_dir as i32); - if extend { - self.buf.pbit(1, 1); - self.highdefinition(renderer, other); - } else { - self.buf.pbit(1, 0); - } - } - - #[inline] - fn walk( - &mut self, - renderer: &mut NpcRenderer, - other: &Npc, - extend: bool - ) { - self.buf.pbit(1, 1); - self.buf.pbit(2, 1); - self.buf.pbit(3, other.walk_dir as i32); - if extend { - self.buf.pbit(1, 1); - self.highdefinition(renderer, other); - } else { - self.buf.pbit(1, 0); - } - } - - #[inline] - fn extend( - &mut self, - renderer: &mut NpcRenderer, - other: &Npc - ) { - self.buf.pbit(1, 1); - self.buf.pbit(2, 0); - self.highdefinition(renderer, other); - } - - #[inline] - fn idle(&mut self) { - self.buf.pbit(1, 0); - } - - #[inline] - fn highdefinition( - &mut self, - renderer: &mut NpcRenderer, - other: &Npc - ) { - self.write_blocks(renderer, other.nid, other.masks); - } - - #[inline] - fn lowdefinition( - &mut self, - renderer: &mut NpcRenderer, - other: &Npc - ) { - let nid: i32 = other.nid; - let mut masks: u32 = other.masks; - - if other.face_entity != -1 && !renderer.has(nid, NpcInfoProt::FACE_ENTITY) { - renderer.cache( - nid, - &NpcInfoFaceEntity::new(other.face_entity), - NpcInfoProt::FACE_ENTITY, - ); - masks |= NpcInfoProt::FACE_ENTITY as u32; - } - - if !renderer.has(nid, NpcInfoProt::FACE_COORD) { - if other.face_x != -1 { - renderer.cache( - nid, - &NpcInfoFaceCoord::new(other.face_x, other.face_z), - NpcInfoProt::FACE_COORD, - ); - } else if other.orientation_x != -1 { - renderer.cache( - nid, - &NpcInfoFaceCoord::new(other.orientation_x, other.orientation_z), - NpcInfoProt::FACE_COORD, - ); - } else { - renderer.cache( - nid, - &NpcInfoFaceCoord::new(CoordGrid::fine(other.coord.x(), 1), CoordGrid::fine(other.coord.z(), 1)), - NpcInfoProt::FACE_COORD, - ); - } - } - - masks |= NpcInfoProt::FACE_COORD as u32; - - self.write_blocks(renderer, nid, masks); - } - - #[inline] - fn write_blocks( - &mut self, - renderer: &mut NpcRenderer, - nid: i32, - masks: u32, - ) { - self.updates.p1((masks & 0xff) as i32); - // ---- - // an optimization *could* be made where all of these are just 1 block of bytes... - // the same could NOT be done for players bcuz of how exact_move works... - if masks & NpcInfoProt::ANIM as u32 != 0 { - renderer.write(&mut self.updates, nid, NpcInfoProt::ANIM); - } - if masks & NpcInfoProt::FACE_ENTITY as u32 != 0 { - renderer.write(&mut self.updates, nid, NpcInfoProt::FACE_ENTITY); - } - if masks & NpcInfoProt::SAY as u32 != 0 { - renderer.write(&mut self.updates, nid, NpcInfoProt::SAY); - } - if masks & NpcInfoProt::DAMAGE as u32 != 0 { - renderer.write(&mut self.updates, nid, NpcInfoProt::DAMAGE); - } - if masks & NpcInfoProt::CHANGE_TYPE as u32 != 0 { - renderer.write(&mut self.updates, nid, NpcInfoProt::CHANGE_TYPE); - } - if masks & NpcInfoProt::SPOT_ANIM as u32 != 0 { - renderer.write(&mut self.updates, nid, NpcInfoProt::SPOT_ANIM); - } - if masks & NpcInfoProt::FACE_COORD as u32 != 0 { - renderer.write(&mut self.updates, nid, NpcInfoProt::FACE_COORD); - } - } - #[inline] const fn fits(&self, bytes: usize, bits_to_add: usize, bytes_to_add: usize) -> bool { // 7 aligns to the next byte diff --git a/src/out/rebuild_normal.rs b/src/out/rebuild_normal.rs new file mode 100644 index 0000000..53c0706 --- /dev/null +++ b/src/out/rebuild_normal.rs @@ -0,0 +1,58 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct RebuildNormal { + x: i32, + z: i32, + squares: Vec, + maps: Vec, + locs: Vec, +} + +impl RebuildNormal { + #[inline] + pub const fn new( + x: i32, + z: i32, + squares: Vec, + maps: Vec, + locs: Vec, + ) -> RebuildNormal { + return RebuildNormal { + x, + z, + squares, + maps, + locs, + } + } +} + +impl MessageEncoder for RebuildNormal { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::REBUILD_NORMAL as i32; + } + + #[inline] + fn length(&self) -> i32 { + return -2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.x); + buf.p2(self.z); + for index in 0..self.squares.len() { + buf.p2(unsafe { *self.squares.as_ptr().add(index) as i32 }); + buf.p4(unsafe { *self.maps.as_ptr().add(index) }); + buf.p4(unsafe { *self.locs.as_ptr().add(index) }); + } + } + + #[inline] + fn test(&self) -> usize { + return 2 + 2 + self.squares.len() * (1 + 1 + 4 + 4); + } +} \ No newline at end of file diff --git a/src/out/reset_anims.rs b/src/out/reset_anims.rs new file mode 100644 index 0000000..eb2429d --- /dev/null +++ b/src/out/reset_anims.rs @@ -0,0 +1,32 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct ResetAnims {} + +impl ResetAnims { + #[inline] + pub const fn new() -> ResetAnims { + return ResetAnims {} + } +} + +impl MessageEncoder for ResetAnims { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::RESET_ANIMS as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 0; + } + + #[inline] + fn encode(&self, _: &mut Packet) {} + + #[inline] + fn test(&self) -> usize { + return 0; + } +} \ No newline at end of file diff --git a/src/out/reset_clientvarcache.rs b/src/out/reset_clientvarcache.rs new file mode 100644 index 0000000..4e34338 --- /dev/null +++ b/src/out/reset_clientvarcache.rs @@ -0,0 +1,32 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct ResetClientVarCache {} + +impl ResetClientVarCache { + #[inline] + pub const fn new() -> ResetClientVarCache { + return ResetClientVarCache {} + } +} + +impl MessageEncoder for ResetClientVarCache { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::RESET_CLIENT_VARCACHE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 0; + } + + #[inline] + fn encode(&self, _: &mut Packet) {} + + #[inline] + fn test(&self) -> usize { + return 0; + } +} \ No newline at end of file diff --git a/src/out/set_multiway.rs b/src/out/set_multiway.rs new file mode 100644 index 0000000..1a3f9a9 --- /dev/null +++ b/src/out/set_multiway.rs @@ -0,0 +1,38 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct SetMultiway { + hidden: bool, +} + +impl SetMultiway { + #[inline] + pub const fn new(hidden: bool) -> SetMultiway { + return SetMultiway { + hidden, + } + } +} + +impl MessageEncoder for SetMultiway { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::SET_MULTIWAY as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 1; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(if self.hidden { 1 } else { 0 }); + } + + #[inline] + fn test(&self) -> usize { + return 1; + } +} \ No newline at end of file diff --git a/src/out/synth_sound.rs b/src/out/synth_sound.rs new file mode 100644 index 0000000..da948c5 --- /dev/null +++ b/src/out/synth_sound.rs @@ -0,0 +1,48 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct SynthSound { + synth: i32, + loops: i32, + delay: i32, +} + +impl SynthSound { + #[inline] + pub const fn new( + synth: i32, + loops: i32, + delay: i32, + ) -> SynthSound { + return SynthSound { + synth, + loops, + delay, + } + } +} + +impl MessageEncoder for SynthSound { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::SYNTH_SOUND as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 5; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.synth); + buf.p1(self.loops); + buf.p2(self.delay); + } + + #[inline] + fn test(&self) -> usize { + return 5; + } +} \ No newline at end of file diff --git a/src/out/tut_flash.rs b/src/out/tut_flash.rs new file mode 100644 index 0000000..1a1cee9 --- /dev/null +++ b/src/out/tut_flash.rs @@ -0,0 +1,40 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct TutFlash { + tab: i32, +} + +impl TutFlash { + #[inline] + pub const fn new( + tab: i32, + ) -> TutFlash { + return TutFlash { + tab, + } + } +} + +impl MessageEncoder for TutFlash { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::TUT_FLASH as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 1; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.tab); + } + + #[inline] + fn test(&self) -> usize { + return 1; + } +} \ No newline at end of file diff --git a/src/out/tut_open.rs b/src/out/tut_open.rs new file mode 100644 index 0000000..6edaf3f --- /dev/null +++ b/src/out/tut_open.rs @@ -0,0 +1,40 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct TutOpen { + component: i32, +} + +impl TutOpen { + #[inline] + pub const fn new( + component: i32, + ) -> TutOpen { + return TutOpen { + component, + } + } +} + +impl MessageEncoder for TutOpen { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::TUT_OPEN as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/unset_map_flag.rs b/src/out/unset_map_flag.rs new file mode 100644 index 0000000..9369c54 --- /dev/null +++ b/src/out/unset_map_flag.rs @@ -0,0 +1,32 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UnsetMapFlag {} + +impl UnsetMapFlag { + #[inline] + pub const fn new() -> UnsetMapFlag { + return UnsetMapFlag {} + } +} + +impl MessageEncoder for UnsetMapFlag { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UNSET_MAP_FLAG as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 0; + } + + #[inline] + fn encode(&self, _: &mut Packet) {} + + #[inline] + fn test(&self) -> usize { + return 0; + } +} \ No newline at end of file diff --git a/src/out/update_friendlist.rs b/src/out/update_friendlist.rs new file mode 100644 index 0000000..c1a26fb --- /dev/null +++ b/src/out/update_friendlist.rs @@ -0,0 +1,41 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateFriendList { + name: i64, + node: i32, +} + +impl UpdateFriendList { + #[inline] + pub const fn new(name: i64, node: i32) -> UpdateFriendList { + return UpdateFriendList { + name, + node, + } + } +} + +impl MessageEncoder for UpdateFriendList { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_FRIENDLIST as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 9; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p8(self.name); + buf.p1(self.node); + } + + #[inline] + fn test(&self) -> usize { + return 9; + } +} \ No newline at end of file diff --git a/src/out/update_ignorelist.rs b/src/out/update_ignorelist.rs new file mode 100644 index 0000000..d19ae66 --- /dev/null +++ b/src/out/update_ignorelist.rs @@ -0,0 +1,40 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateIgnoreList { + names: Vec, +} + +impl UpdateIgnoreList { + #[inline] + pub const fn new(names: Vec) -> UpdateIgnoreList { + return UpdateIgnoreList { + names, + } + } +} + +impl MessageEncoder for UpdateIgnoreList { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_IGNORELIST as i32; + } + + #[inline] + fn length(&self) -> i32 { + return -2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + for &name in self.names.iter() { + buf.p8(name); + } + } + + #[inline] + fn test(&self) -> usize { + return 8 * self.names.len(); + } +} \ No newline at end of file diff --git a/src/out/update_inv_full.rs b/src/out/update_inv_full.rs new file mode 100644 index 0000000..db2d49d --- /dev/null +++ b/src/out/update_inv_full.rs @@ -0,0 +1,74 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateInvFull { + size: i32, + component: i32, + inv: Vec, +} + +impl UpdateInvFull { + #[inline] + pub const fn new( + size: i32, + component: i32, + inv: Vec, + ) -> UpdateInvFull { + return UpdateInvFull { + size, + component, + inv, + } + } +} + +impl MessageEncoder for UpdateInvFull { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_INV_FULL as i32; + } + + #[inline] + fn length(&self) -> i32 { + return -2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + // todo: size should be the index of the last non-empty slot + buf.p2(self.component); + buf.p1(self.size); + for &packed in &self.inv[..self.size as usize] { + let obj: i32 = (packed >> 31) as i32; + if obj != -1 { + let count: i32 = (packed & 0x7fffffff) as i32; + buf.p2(obj + 1); + if count >= 0xff { + buf.p1(0xff); + buf.p4(count); + } else { + buf.p1(count); + } + } else { + buf.p2(0); + buf.p1(0); + } + } + } + + #[inline] + fn test(&self) -> usize { + let mut length: usize = 3; + for &packed in &self.inv[..self.size as usize] { + let obj: i32 = (packed >> 31) as i32; + if obj != -1 { + let count = (packed & 0x7fffffff) as i32; + length += 2 + if count >= 0xff { 5 } else { 1 }; + } else { + length += 3; + } + } + return length + } +} \ No newline at end of file diff --git a/src/out/update_inv_partial.rs b/src/out/update_inv_partial.rs new file mode 100644 index 0000000..3ef2a26 --- /dev/null +++ b/src/out/update_inv_partial.rs @@ -0,0 +1,77 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateInvPartial { + component: i32, + slots: Vec, + inv: Vec, +} + +impl UpdateInvPartial { + #[inline] + pub const fn new( + component: i32, + slots: Vec, + inv: Vec, + ) -> UpdateInvPartial { + return UpdateInvPartial { + component, + slots, + inv, + } + } +} + +impl MessageEncoder for UpdateInvPartial { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_INV_PARTIAL as i32; + } + + #[inline] + fn length(&self) -> i32 { + return -2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + // todo: size should be the index of the last non-empty slot + buf.p2(self.component); + for &slot in &self.slots { + let packed: i64 = self.inv[slot as usize]; + let obj: i32 = (packed >> 31) as i32; + buf.p1(slot); + if obj != -1 { + let count: i32 = (packed & 0x7fffffff) as i32; + buf.p2(obj + 1); + if count >= 0xff { + buf.p1(0xff); + buf.p4(count); + } else { + buf.p1(count); + } + } else { + buf.p2(0); + buf.p1(0); + } + } + } + + #[inline] + fn test(&self) -> usize { + let mut length: usize = 2; + for &slot in &self.slots { + let packed: i64 = self.inv[slot as usize]; + let obj: i32 = (packed >> 31) as i32; + length += 1; + if obj != -1 { + let count: i32 = (packed & 0x7fffffff) as i32; + length += if count >= 0xff { 5 } else { 1 }; + } else { + length += 3; + } + } + return length; + } +} \ No newline at end of file diff --git a/src/out/update_inv_stop_transmit.rs b/src/out/update_inv_stop_transmit.rs new file mode 100644 index 0000000..48523af --- /dev/null +++ b/src/out/update_inv_stop_transmit.rs @@ -0,0 +1,40 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateInvStopTransmit { + component: i32, +} + +impl UpdateInvStopTransmit { + #[inline] + pub const fn new( + component: i32, + ) -> UpdateInvStopTransmit { + return UpdateInvStopTransmit { + component, + } + } +} + +impl MessageEncoder for UpdateInvStopTransmit { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_INV_STOP_TRANSMIT as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.component); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/update_pid.rs b/src/out/update_pid.rs new file mode 100644 index 0000000..4fafe75 --- /dev/null +++ b/src/out/update_pid.rs @@ -0,0 +1,40 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdatePid { + pid: i32, +} + +impl UpdatePid { + #[inline] + pub const fn new( + pid: i32, + ) -> UpdatePid { + return UpdatePid { + pid, + } + } +} + +impl MessageEncoder for UpdatePid { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_PID as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.pid); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/update_reboot_timer.rs b/src/out/update_reboot_timer.rs new file mode 100644 index 0000000..a84a344 --- /dev/null +++ b/src/out/update_reboot_timer.rs @@ -0,0 +1,40 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateRebootTimer { + ticks: i32, +} + +impl UpdateRebootTimer { + #[inline] + pub const fn new( + ticks: i32, + ) -> UpdateRebootTimer { + return UpdateRebootTimer { + ticks, + } + } +} + +impl MessageEncoder for UpdateRebootTimer { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_REBOOT_TIMER as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.ticks); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/update_runenergy.rs b/src/out/update_runenergy.rs new file mode 100644 index 0000000..45c66de --- /dev/null +++ b/src/out/update_runenergy.rs @@ -0,0 +1,40 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateRunEnergy { + energy: i32, +} + +impl UpdateRunEnergy { + #[inline] + pub const fn new( + energy: i32, + ) -> UpdateRunEnergy { + return UpdateRunEnergy { + energy, + } + } +} + +impl MessageEncoder for UpdateRunEnergy { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_RUNENERGY as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 1; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.energy / 100); + } + + #[inline] + fn test(&self) -> usize { + return 1; + } +} \ No newline at end of file diff --git a/src/out/update_runweight.rs b/src/out/update_runweight.rs new file mode 100644 index 0000000..5f7931e --- /dev/null +++ b/src/out/update_runweight.rs @@ -0,0 +1,40 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateRunWeight { + kg: i32, +} + +impl UpdateRunWeight { + #[inline] + pub const fn new( + kg: i32, + ) -> UpdateRunWeight { + return UpdateRunWeight { + kg, + } + } +} + +impl MessageEncoder for UpdateRunWeight { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_RUNWEIGHT as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.kg); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/update_stat.rs b/src/out/update_stat.rs new file mode 100644 index 0000000..6cc9734 --- /dev/null +++ b/src/out/update_stat.rs @@ -0,0 +1,48 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateStat { + stat: i32, + experience: i32, + level: i32, +} + +impl UpdateStat { + #[inline] + pub const fn new( + stat: i32, + experience: i32, + level: i32, + ) -> UpdateStat { + return UpdateStat { + stat, + experience, + level, + } + } +} + +impl MessageEncoder for UpdateStat { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_STAT as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 6; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1(self.stat); + buf.p4(self.experience / 10); + buf.p1(self.level); // not base level + } + + #[inline] + fn test(&self) -> usize { + return 6; + } +} \ No newline at end of file diff --git a/src/out/update_zone_full_follows.rs b/src/out/update_zone_full_follows.rs new file mode 100644 index 0000000..cb3890b --- /dev/null +++ b/src/out/update_zone_full_follows.rs @@ -0,0 +1,51 @@ +use crate::coord::CoordGrid; +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateZoneFullFollows { + x: i32, + z: i32, + origin_x: i32, + origin_z: i32, +} + +impl UpdateZoneFullFollows { + #[inline] + pub const fn new( + x: i32, + z: i32, + origin_x: i32, + origin_z: i32, + ) -> UpdateZoneFullFollows { + return UpdateZoneFullFollows { + x, + z, + origin_x, + origin_z, + } + } +} + +impl MessageEncoder for UpdateZoneFullFollows { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_ZONE_FULL_FOLLOWS as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1((self.x << 3) - CoordGrid::origin(self.origin_x as u16) as i32); + buf.p1((self.z << 3) - CoordGrid::origin(self.origin_z as u16) as i32); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/update_zone_partial_enclosed.rs b/src/out/update_zone_partial_enclosed.rs new file mode 100644 index 0000000..9992002 --- /dev/null +++ b/src/out/update_zone_partial_enclosed.rs @@ -0,0 +1,55 @@ +use crate::coord::CoordGrid; +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateZonePartialEnclosed { + x: i32, + z: i32, + origin_x: i32, + origin_z: i32, + data: Vec, +} + +impl UpdateZonePartialEnclosed { + #[inline] + pub const fn new( + x: i32, + z: i32, + origin_x: i32, + origin_z: i32, + data: Vec, + ) -> UpdateZonePartialEnclosed { + return UpdateZonePartialEnclosed { + x, + z, + origin_x, + origin_z, + data, + } + } +} + +impl MessageEncoder for UpdateZonePartialEnclosed { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_ZONE_PARTIAL_ENCLOSED as i32; + } + + #[inline] + fn length(&self) -> i32 { + return -2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1((self.x << 3) - CoordGrid::origin(self.origin_x as u16) as i32); + buf.p1((self.z << 3) - CoordGrid::origin(self.origin_z as u16) as i32); + buf.pdata(&self.data, 0, self.data.len()); + } + + #[inline] + fn test(&self) -> usize { + return 2 + self.data.len(); + } +} \ No newline at end of file diff --git a/src/out/update_zone_partial_follows.rs b/src/out/update_zone_partial_follows.rs new file mode 100644 index 0000000..5af20e3 --- /dev/null +++ b/src/out/update_zone_partial_follows.rs @@ -0,0 +1,51 @@ +use crate::coord::CoordGrid; +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct UpdateZonePartialFollows { + x: i32, + z: i32, + origin_x: i32, + origin_z: i32, +} + +impl UpdateZonePartialFollows { + #[inline] + pub const fn new( + x: i32, + z: i32, + origin_x: i32, + origin_z: i32, + ) -> UpdateZonePartialFollows { + return UpdateZonePartialFollows { + x, + z, + origin_x, + origin_z, + } + } +} + +impl MessageEncoder for UpdateZonePartialFollows { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::UPDATE_ZONE_PARTIAL_FOLLOWS as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 2; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p1((self.x << 3) - CoordGrid::origin(self.origin_x as u16) as i32); + buf.p1((self.z << 3) - CoordGrid::origin(self.origin_z as u16) as i32); + } + + #[inline] + fn test(&self) -> usize { + return 2; + } +} \ No newline at end of file diff --git a/src/out/varp_large.rs b/src/out/varp_large.rs new file mode 100644 index 0000000..18543e0 --- /dev/null +++ b/src/out/varp_large.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct VarpLarge { + varp: i32, + value: i32, +} + +impl VarpLarge { + #[inline] + pub const fn new( + varp: i32, + value: i32, + ) -> VarpLarge { + return VarpLarge { + varp, + value, + }; + } +} + +impl MessageEncoder for VarpLarge { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::VARP_LARGE as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 6; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.varp); + buf.p4(self.value); + } + + #[inline] + fn test(&self) -> usize { + return 6; + } +} \ No newline at end of file diff --git a/src/out/varp_small.rs b/src/out/varp_small.rs new file mode 100644 index 0000000..2b48c9c --- /dev/null +++ b/src/out/varp_small.rs @@ -0,0 +1,44 @@ +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::prot::ServerInternalProt; + +pub struct VarpSmall { + varp: i32, + value: i32, +} + +impl VarpSmall { + #[inline] + pub const fn new( + varp: i32, + value: i32, + ) -> VarpSmall { + return VarpSmall { + varp, + value, + }; + } +} + +impl MessageEncoder for VarpSmall { + #[inline] + fn id(&self) -> i32 { + return ServerInternalProt::VARP_SMALL as i32; + } + + #[inline] + fn length(&self) -> i32 { + return 3; + } + + #[inline] + fn encode(&self, buf: &mut Packet) { + buf.p2(self.varp); + buf.p1(self.value); + } + + #[inline] + fn test(&self) -> usize { + return 3; + } +} \ No newline at end of file diff --git a/src/player.rs b/src/player.rs index 72ec4fb..b4f6993 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,6 +1,10 @@ use crate::build::BuildArea; use crate::coord::CoordGrid; +use crate::message::MessageEncoder; +use crate::packet::Packet; +use crate::pool::PacketPool; use crate::visibility::Visibility; +use std::collections::VecDeque; #[derive(Clone)] pub struct Player { @@ -34,6 +38,7 @@ pub struct Player { pub graphic_height: i32, pub graphic_delay: i32, pub exact_move: Option, + pub write_queue: VecDeque>, } #[derive(Clone)] @@ -89,9 +94,40 @@ impl Player { graphic_height: -1, graphic_delay: -1, exact_move: None, + write_queue: VecDeque::with_capacity(64), } } + #[inline] + pub fn buffer(&mut self, pool: &mut PacketPool, message: &dyn MessageEncoder) { + self.write_queue.push_back(Player::write(pool, message)); + } + + #[inline] + pub fn write(pool: &mut PacketPool, message: &dyn MessageEncoder) -> Vec { + let id: i32 = message.id(); + let offset: usize = match message.length() { + -1 => 1 + 1, + -2 => 1 + 2, + _ => 1 + 0, + }; + let mut buf: &mut Packet = pool.take(offset + message.test()); + buf.p1(id); + match message.length() { + -1 => buf.pos += 1, + -2 => buf.pos += 2, + _ => {} + }; + let start: usize = buf.pos; + message.encode(&mut buf); + match message.length() { + -1 => buf.psize1((buf.pos - start) as u8), + -2 => buf.psize2((buf.pos - start) as u16), + _ => {} + }; + return unsafe { buf.data.get_unchecked(0..buf.pos).to_vec() }; + } + #[inline] pub fn cleanup(&mut self) { self.walk_dir = -1; @@ -118,6 +154,7 @@ impl Player { self.graphic_height = -1; self.graphic_delay = -1; self.exact_move = None; + self.write_queue.clear(); } } diff --git a/src/pool.rs b/src/pool.rs new file mode 100644 index 0000000..6fa1426 --- /dev/null +++ b/src/pool.rs @@ -0,0 +1,29 @@ +use crate::packet::Packet; + +pub struct PacketPool { + packet_100b: Packet, + packet_5kb: Packet, +} + +impl PacketPool { + pub fn new() -> PacketPool { + return PacketPool { + packet_100b: Packet::new(100), + packet_5kb: Packet::new(5000), + } + } + + pub fn take(&mut self, len: usize) -> &mut Packet { + return if len <= 100 { + let packet: &mut Packet = &mut self.packet_100b; + packet.pos = 0; + packet.bit_pos = 0; + packet + } else { + let packet: &mut Packet = &mut self.packet_5kb; + packet.pos = 0; + packet.bit_pos = 0; + packet + } + } +} \ No newline at end of file diff --git a/src/prot.rs b/src/prot.rs index c106204..9e285df 100644 --- a/src/prot.rs +++ b/src/prot.rs @@ -1,9 +1,10 @@ #![allow(non_camel_case_types)] +#![allow(dead_code)] use wasm_bindgen::prelude::wasm_bindgen; #[repr(u16)] -#[derive(Eq, Hash, PartialEq)] +#[derive(PartialEq)] #[wasm_bindgen] pub enum PlayerInfoProt { APPEARANCE = 0x1, @@ -38,7 +39,6 @@ impl PlayerInfoProt { } #[repr(u16)] -#[derive(Eq, Hash, PartialEq)] #[wasm_bindgen] pub enum NpcInfoProt { ANIM = 0x2, @@ -64,4 +64,298 @@ impl NpcInfoProt { NpcInfoProt::FACE_COORD => 6, } } +} + +#[repr(u8)] +#[wasm_bindgen] +#[derive(PartialEq)] +pub enum ClientProt { + REBUILD_GETMAPS, + + NO_TIMEOUT, + + IDLE_TIMER, + + EVENT_TRACKING, + EVENT_CAMERA_POSITION, + + ANTICHEAT_OPLOGIC1, + ANTICHEAT_OPLOGIC2, + ANTICHEAT_OPLOGIC3, + ANTICHEAT_OPLOGIC4, + ANTICHEAT_OPLOGIC5, + ANTICHEAT_OPLOGIC6, + ANTICHEAT_OPLOGIC7, + ANTICHEAT_OPLOGIC8, + ANTICHEAT_OPLOGIC9, + + ANTICHEAT_CYCLELOGIC1, + ANTICHEAT_CYCLELOGIC2, + ANTICHEAT_CYCLELOGIC3, + ANTICHEAT_CYCLELOGIC4, + ANTICHEAT_CYCLELOGIC5, + ANTICHEAT_CYCLELOGIC6, + + OPOBJ1, + OPOBJ2, + OPOBJ3, + OPOBJ4, + OPOBJ5, + OPOBJT, + OPOBJU, + + OPNPC1, + OPNPC2, + OPNPC3, + OPNPC4, + OPNPC5, + OPNPCT, + OPNPCU, + + OPLOC1, + OPLOC2, + OPLOC3, + OPLOC4, + OPLOC5, + OPLOCT, + OPLOCU, + + OPPLAYER1, + OPPLAYER2, + OPPLAYER3, + OPPLAYER4, + OPPLAYERT, + OPPLAYERU, + + OPHELD1, + OPHELD2, + OPHELD3, + OPHELD4, + OPHELD5, + OPHELDT, + OPHELDU, + + INV_BUTTON1, + INV_BUTTON2, + INV_BUTTON3, + INV_BUTTON4, + INV_BUTTON5, + IF_BUTTON, + + RESUME_PAUSEBUTTON, + CLOSE_MODAL, + RESUME_P_COUNTDIALOG, + TUTORIAL_CLICKSIDE, + + MOVE_OPCLICK, + REPORT_ABUSE, + MOVE_MINIMAPCLICK, + INV_BUTTOND, + IGNORELIST_DEL, + IGNORELIST_ADD, + IF_PLAYERDESIGN, + CHAT_SETMODE, + MESSAGE_PRIVATE, + FRIENDLIST_DEL, + FRIENDLIST_ADD, + CLIENT_CHEAT, + MESSAGE_PUBLIC, + MOVE_GAMECLICK, +} + +#[repr(u8)] +pub enum ServerInternalProt { + // interfaces + IF_OPENCHAT = 14, + IF_OPENMAIN_SIDE = 28, + IF_CLOSE = 129, + IF_SETTAB = 167, + IF_OPENMAIN = 168, + IF_OPENSIDE = 195, + + // updating interfaces + IF_SETCOLOUR = 2, // NXT naming + IF_SETHIDE = 26, // NXT naming + IF_SETOBJECT = 46, // NXT naming + IF_SETTAB_ACTIVE = 84, + IF_SETMODEL = 87, // NXT naming + IF_SETRECOL = 103, // NXT naming + IF_SETANIM = 146, // NXT naming + IF_SETPLAYERHEAD = 197, // NXT naming + IF_SETTEXT = 201, // NXT naming + IF_SETNPCHEAD = 204, // NXT naming + IF_SETPOSITION = 209, // NXT naming + + // tutorial area + TUT_FLASH = 126, + TUT_OPEN = 185, + + // inventory + UPDATE_INV_STOP_TRANSMIT = 15, // NXT naming + UPDATE_INV_FULL = 98, // NXT naming + UPDATE_INV_PARTIAL = 213, // NXT naming + + // camera control + CAM_LOOKAT = 74, // NXT naming + CAM_SHAKE = 13, // NXT naming + CAM_MOVETO = 3, // NXT naming + CAM_RESET = 239, // NXT naming + + // entity updates + NPC_INFO = 1, // NXT naming + PLAYER_INFO = 184, // NXT naming + + // input tracking + FINISH_TRACKING = 133, + ENABLE_TRACKING = 226, + + // social + MESSAGE_GAME = 4, // NXT naming + UPDATE_IGNORELIST = 21, // NXT naming + CHAT_FILTER_SETTINGS = 32, // NXT naming + MESSAGE_PRIVATE = 41, // NXT naming + UPDATE_FRIENDLIST = 152, // NXT naming + + // misc + UNSET_MAP_FLAG = 19, // NXT has "SET_MAP_FLAG" but we cannot control the position + UPDATE_RUNWEIGHT = 22, // NXT naming + HINT_ARROW = 25, // NXT naming + UPDATE_REBOOT_TIMER = 43, // NXT naming + UPDATE_STAT = 44, // NXT naming + UPDATE_RUNENERGY = 68, // NXT naming + RESET_ANIMS = 136, // NXT naming + UPDATE_PID = 139, + LAST_LOGIN_INFO = 140, // NXT naming + LOGOUT = 142, // NXT naming + P_COUNTDIALOG = 243, // named after runescript command + client resume_p_countdialog packet + SET_MULTIWAY = 254, + + // maps + DATA_LOC_DONE = 20, + DATA_LAND_DONE = 80, + DATA_LAND = 132, + DATA_LOC = 220, + REBUILD_NORMAL = 237, // NXT naming (do we really need _normal if there's no region rebuild?) + + // vars + VARP_SMALL = 150, // NXT naming + VARP_LARGE = 175, // NXT naming + RESET_CLIENT_VARCACHE = 193, // NXT naming + + // audio + SYNTH_SOUND = 12, // NXT naming + MIDI_SONG = 54, // NXT naming + MIDI_JINGLE = 212, // NXT naming + + // zones + UPDATE_ZONE_PARTIAL_FOLLOWS = 7, // NXT naming + UPDATE_ZONE_FULL_FOLLOWS = 135, // NXT naming + UPDATE_ZONE_PARTIAL_ENCLOSED = 162, // NXT naming + LOC_MERGE = 23, // based on runescript command p_locmerge + LOC_ANIM = 42, // NXT naming + OBJ_DEL = 49, // NXT naming + OBJ_REVEAL = 50, // NXT naming + LOC_ADD_CHANGE = 59, // NXT naming + MAP_PROJANIM = 69, // NXT naming + LOC_DEL = 76, // NXT naming + OBJ_COUNT = 151, // NXT naming + MAP_ANIM = 191, // NXT naming + OBJ_ADD = 223, // NXT naming +} + +#[repr(u8)] +pub enum ClientInternalProt { + REBUILD_GETMAPS = 150, + + NO_TIMEOUT = 108, // NXT naming + + IDLE_TIMER = 70, + + EVENT_TRACKING = 81, + EVENT_CAMERA_POSITION = 189, // NXT naming + + // autogenerated as part of obfuscation process + ANTICHEAT_OPLOGIC1 = 7, + ANTICHEAT_OPLOGIC2 = 88, + ANTICHEAT_OPLOGIC3 = 30, + ANTICHEAT_OPLOGIC4 = 176, + ANTICHEAT_OPLOGIC5 = 220, + ANTICHEAT_OPLOGIC6 = 66, + ANTICHEAT_OPLOGIC7 = 17, + ANTICHEAT_OPLOGIC8 = 2, + ANTICHEAT_OPLOGIC9 = 238, + + // autogenerated as part of obfuscation process + ANTICHEAT_CYCLELOGIC1 = 233, + ANTICHEAT_CYCLELOGIC2 = 146, + ANTICHEAT_CYCLELOGIC3 = 215, + ANTICHEAT_CYCLELOGIC4 = 236, + ANTICHEAT_CYCLELOGIC5 = 85, + ANTICHEAT_CYCLELOGIC6 = 219, + + OPOBJ1 = 140, // NXT naming + OPOBJ2 = 40, // NXT naming + OPOBJ3 = 200, // NXT naming + OPOBJ4 = 178, // NXT naming + OPOBJ5 = 247, // NXT naming + OPOBJT = 138, // NXT naming + OPOBJU = 239, // NXT naming + + OPNPC1 = 194, // NXT naming + OPNPC2 = 8, // NXT naming + OPNPC3 = 27, // NXT naming + OPNPC4 = 113, // NXT naming + OPNPC5 = 100, // NXT naming + OPNPCT = 134, // NXT naming + OPNPCU = 202, // NXT naming + + OPLOC1 = 245, // NXT naming + OPLOC2 = 172, // NXT naming + OPLOC3 = 96, // NXT naming + OPLOC4 = 97, // NXT naming + OPLOC5 = 116, // NXT naming + OPLOCT = 9, // NXT naming + OPLOCU = 75, // NXT naming + + OPPLAYER1 = 164, // NXT naming + OPPLAYER2 = 53, // NXT naming + OPPLAYER3 = 185, // NXT naming + OPPLAYER4 = 206, // NXT naming + OPPLAYERT = 177, // NXT naming + OPPLAYERU = 248, // NXT naming + + OPHELD1 = 195, // name based on runescript trigger + OPHELD2 = 71, // name based on runescript trigger + OPHELD3 = 133, // name based on runescript trigger + OPHELD4 = 157, // name based on runescript trigger + OPHELD5 = 211, // name based on runescript trigger + OPHELDT = 48, // name based on runescript trigger + OPHELDU = 130, // name based on runescript trigger + + INV_BUTTON1 = 31, // NXT has "IF_BUTTON1" but for our interface system, this makes more sense + INV_BUTTON2 = 59, // NXT has "IF_BUTTON2" but for our interface system, this makes more sense + INV_BUTTON3 = 212, // NXT has "IF_BUTTON3" but for our interface system, this makes more sense + INV_BUTTON4 = 38, // NXT has "IF_BUTTON4" but for our interface system, this makes more sense + INV_BUTTON5 = 6, // NXT has "IF_BUTTON5" but for our interface system, this makes more sense + IF_BUTTON = 155, // NXT naming + + RESUME_PAUSEBUTTON = 235, // NXT naming + CLOSE_MODAL = 231, // NXT naming + RESUME_P_COUNTDIALOG = 237, // NXT naming + TUTORIAL_CLICKSIDE = 175, + + MOVE_OPCLICK = 93, // comes with OP packets, name based on other MOVE packets + REPORT_ABUSE = 190, + MOVE_MINIMAPCLICK = 165, // NXT naming + INV_BUTTOND = 159, // NXT has "IF_BUTTOND" but for our interface system, this makes more sense + IGNORELIST_DEL = 171, // NXT naming + IGNORELIST_ADD = 79, // NXT naming + IF_PLAYERDESIGN = 52, + CHAT_SETMODE = 244, // NXT naming + MESSAGE_PRIVATE = 148, // NXT naming + FRIENDLIST_DEL = 11, // NXT naming + FRIENDLIST_ADD = 118, // NXT naming + CLIENT_CHEAT = 4, // NXT naming + MESSAGE_PUBLIC = 158, // NXT naming + MOVE_GAMECLICK = 181, // NXT naming } \ No newline at end of file diff --git a/src/renderer.rs b/src/renderer.rs index 149836b..d15ed67 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -153,11 +153,12 @@ impl PlayerRenderer { #[inline] pub fn cache(&mut self, id: i32, message: &dyn InfoMessage, prot: PlayerInfoProt) -> usize { unsafe { + let persist: bool = prot == PlayerInfoProt::APPEARANCE; let cache: &mut Vec>> = &mut *self.caches.as_mut_ptr().add(prot.to_index()); - if (*cache.as_ptr().add(id as usize)).is_some() && !message.persists() { - return 0; - } - return PlayerRenderer::encode_info(cache, id, message); + return match *cache.as_ptr().add(id as usize) { + None => PlayerRenderer::encode_info(cache, id, message), + Some(_) => if !persist { 0 } else { PlayerRenderer::encode_info(cache, id, message) }, + }; } } @@ -343,10 +344,10 @@ impl NpcRenderer { pub fn cache(&mut self, id: i32, message: &dyn InfoMessage, prot: NpcInfoProt) -> usize { unsafe { let cache: &mut Vec>> = &mut *self.caches.as_mut_ptr().add(prot.to_index()); - if (*cache.as_ptr().add(id as usize)).is_some() && !message.persists() { - return 0; - } - return NpcRenderer::encode_info(cache, id, message); + return match *cache.as_ptr().add(id as usize) { + None => NpcRenderer::encode_info(cache, id, message), + Some(_) => 0, + }; } } diff --git a/src/wordpack.rs b/src/wordpack.rs new file mode 100644 index 0000000..c16818e --- /dev/null +++ b/src/wordpack.rs @@ -0,0 +1,130 @@ +use crate::packet::Packet; + +pub struct WordPack { + pack: Packet, + unpack: Vec, +} + +impl WordPack { + const CHAR_LOOKUP: [char; 61] = [ + ' ', + 'e', 't', 'a', 'o', 'i', 'h', 'n', 's', 'r', 'd', 'l', 'u', 'm', + 'w', 'c', 'y', 'f', 'g', 'p', 'b', 'v', 'k', 'x', 'j', 'q', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + ' ', '!', '?', '.', ',', ':', ';', '(', ')', '-', + '&', '*', '\\', '\'', '@', '#', '+', '=', '£', '$', '%', '"', '[', ']' + ]; + + #[inline] + pub fn new() -> WordPack { + return WordPack { + pack: Packet::new(100), + unpack: Vec::with_capacity(100), + }; + } + + #[inline] + pub unsafe fn unpack(&mut self, mut packet: Packet) -> String { + self.unpack.clear(); + + let mut carry: i32 = -1; + + for _ in 0..packet.len() { + if self.unpack.len() >= 80 { + break; + } + + let data: u8 = packet.g1(); + let mut nibble: u8 = (data >> 4) & 0xf; + + if carry != -1 { + self.unpack.push(*WordPack::CHAR_LOOKUP.as_ptr().add((((carry << 4) + nibble as i32) - 195) as usize)); + carry = -1; + } else if nibble < 13 { + self.unpack.push(*WordPack::CHAR_LOOKUP.as_ptr().add(nibble as usize)); + } else { + carry = nibble as i32; + } + + nibble = data & 0xf; + + if carry != -1 { + self.unpack.push(*WordPack::CHAR_LOOKUP.as_ptr().add((((carry << 4) + nibble as i32) - 195) as usize)); + carry = -1; + } else if nibble < 13 { + self.unpack.push(*WordPack::CHAR_LOOKUP.as_ptr().add(nibble as usize)); + } else { + carry = nibble as i32; + } + } + + WordPack::sentence_case(&mut self.unpack); + + return self.unpack.iter().collect(); + } + + #[inline] + pub unsafe fn pack(&mut self, input: String) -> Vec { + self.pack.pos = 0; + + let mut carry: i32 = -1; + let mut count: i32 = 0; + + for c in input.chars() { + if count >= 80 { + break; + } + + let c: char = c.to_ascii_lowercase(); + count += 1; + + let mut index = 0; + for (j, &ch) in WordPack::CHAR_LOOKUP.iter().enumerate() { + if ch == c { + index = j as i32; + break; + } + } + + if index > 12 { + index += 195; + } + + if carry == -1 { + if index < 13 { + carry = index; + } else { + self.pack.p1(index); + } + } else if index < 13 { + self.pack.p1((carry << 4) + index); + carry = -1; + } else { + self.pack.p1((carry << 4) + (index >> 4)); + carry = index & 0xf; + } + } + + if carry != -1 { + self.pack.p1(carry << 4); + } + + return self.pack.data.get_unchecked(0..self.pack.pos).to_vec(); + } + + #[inline] + pub fn sentence_case(chars: &mut [char]) { + let mut punctuation = true; + + for c in chars.iter_mut() { + if punctuation && c.is_ascii_lowercase() { + *c = c.to_ascii_uppercase(); + punctuation = false; + } + + if *c == '.' || *c == '!' { + punctuation = true; + } + } + } +} \ No newline at end of file diff --git a/tests/wordpack.rs b/tests/wordpack.rs new file mode 100644 index 0000000..4b1cca7 --- /dev/null +++ b/tests/wordpack.rs @@ -0,0 +1,24 @@ +use rsbuf::packet::Packet; +use rsbuf::wordpack::WordPack; + +#[test] +fn test_unpack_test() { + let packet: Packet = Packet::from(vec![33, 130]); + unsafe { assert_eq!("Test", WordPack::new().unpack(packet)) }; +} + +#[test] +fn test_unpack_zezima() { + let packet: Packet = Packet::from(vec![221, 29, 213, 208, 48]); + unsafe { assert_eq!("Zezima ", WordPack::new().unpack(packet)) }; +} + +#[test] +fn test_pack_test() { + unsafe { assert_eq!(WordPack::new().pack("Test".to_string()), vec![33, 130]) }; +} + +#[test] +fn test_pack_zezima() { + unsafe { assert_eq!(WordPack::new().pack("Zezima".to_string()), vec![221, 29, 213, 208, 48]) }; +}