wgtk/net/element/
base.rs

1//! Definition of elements related to base application.
2//! 
3//! Such elements are sent from the client to the base application and also
4//! replies to such elements if they are requests.
5
6use std::io::{self, Read, Write};
7
8use crate::net::bundle::{BundleElementWriter, TopElementReader, BundleElement, BundleResult};
9use crate::util::io::*;
10
11use super::{SimpleElement, TopElement, NoopElement, ElementLength, ElementIdRange};
12use super::entity::{MethodCall, MethodCallWrapper, MethodCallExt};
13
14
15/// This modules defines in constants the numerical identifiers for
16/// base app elements.
17pub mod id {
18
19    use super::ElementIdRange;
20
21    pub const CLIENT_AUTH: u8           = 0x00;
22    pub const CLIENT_SESSION_KEY: u8    = 0x01;
23
24    pub const CELL_ENTITY_METHOD: ElementIdRange = ElementIdRange::new(0x0F, 0x87);
25    pub const BASE_ENTITY_METHOD: ElementIdRange = ElementIdRange::new(0x88, 0xFE);
26
27}
28
29
30/// Sent by the client to the server without encryption in order to authenticate,
31/// the server then compares with its internal login keys from past successful
32/// logins on the login app.
33/// 
34/// This element is usually a request, in such case a [`ServerSessionKey`] must be 
35/// sent as a reply.
36#[derive(Debug, Clone)]
37pub struct ClientAuth {
38    /// The login key that was sent by the login application, part of the  element
39    /// [`super::login::LoginSuccess`].
40    pub login_key: u32,
41    /// The current number of attempts.
42    pub attempts_count: u8,
43    /// Unknown 16-bits value at the end.
44    pub unk: u16,
45}
46
47impl SimpleElement for ClientAuth {
48
49    fn encode(&self, write: &mut impl Write) -> io::Result<()> {
50        write.write_u32(self.login_key)?;
51        write.write_u8(self.attempts_count)?;
52        write.write_u16(self.unk)
53    }
54
55    fn decode(read: &mut impl Read, _len: usize) -> io::Result<Self> {
56        Ok(Self {
57            login_key: read.read_u32()?, 
58            attempts_count: read.read_u8()?,
59            unk: read.read_u16()?,
60        })
61    }
62
63}
64
65impl TopElement for ClientAuth {
66    const LEN: ElementLength = ElementLength::Fixed(7);
67}
68
69
70/// Replied by the server to the client when receiving a [`ClientAuth`] request 
71/// element. The key must be a new session 
72#[derive(Debug, Clone)]
73pub struct ServerSessionKey {
74    /// The server session key, should not be the same as the login session key.
75    pub session_key: u32,
76}
77
78impl SimpleElement for ServerSessionKey {
79
80    fn encode(&self, write: &mut impl Write) -> io::Result<()> {
81        write.write_u32(self.session_key)
82    }
83
84    fn decode(read: &mut impl Read, _len: usize) -> io::Result<Self> {
85        Ok(Self { session_key: read.read_u32()? })
86    }
87    
88}
89
90
91/// Sent by the client on login (and apparently randomly after login) to return 
92/// the session key that was sent by the server in the [`ServerSessionKey`] 
93/// reply.
94#[derive(Debug, Clone)]
95pub struct ClientSessionKey {
96    /// The server session key
97    pub session_key: u32,
98}
99
100impl ClientSessionKey {
101    pub const ID: u8 = 0x01;
102}
103
104impl SimpleElement for ClientSessionKey {
105
106    fn encode(&self, write: &mut impl Write) -> io::Result<()> {
107        write.write_u32(self.session_key)
108    }
109
110    fn decode(read: &mut impl Read, _len: usize) -> io::Result<Self> {
111        Ok(Self { session_key: read.read_u32()? })
112    }
113
114}
115
116impl TopElement for ClientSessionKey {
117    const LEN: ElementLength = ElementLength::Fixed(4);
118}
119
120
121/// Sent by the client to the base app to call a cell method for the given
122/// entity ID.
123#[derive(Debug, Clone)]
124pub struct CellEntityMethod<M: MethodCall> {
125    /// The entity ID on which we'll call the method, must be set to 0 if
126    /// the current player is targeted.
127    pub entity_id: u32,
128    /// The method call.
129    pub method: M,
130}
131
132impl<M: MethodCall> CellEntityMethod<M> {
133
134    /// Write this cell entity method call to the given bundle.
135    pub fn write(self, writer: BundleElementWriter) {
136        MethodCallWrapper::new(self.method, CellEntityMethodExt {
137            entity_id: self.entity_id,
138        }).write(writer);
139    }
140
141    /// Read this cell entity method call from the given top element reader.
142    pub fn read(reader: TopElementReader) -> BundleResult<BundleElement<Self>> {
143        MethodCallWrapper::<M, CellEntityMethodExt>::read(reader).map(|res| {
144            res.map(|wrapper| Self {
145                entity_id: wrapper.ext.entity_id,
146                method: wrapper.method,
147            })
148        })
149    }
150
151}
152
153struct CellEntityMethodExt {
154    entity_id: u32,
155}
156
157impl MethodCallExt for CellEntityMethodExt {
158    const ID_RANGE: ElementIdRange = id::CELL_ENTITY_METHOD;
159}
160
161impl SimpleElement for CellEntityMethodExt {
162
163    fn encode(&self, write: &mut impl Write) -> io::Result<()> {
164        write.write_u32(self.entity_id)
165    }
166
167    fn decode(read: &mut impl Read, _len: usize) -> io::Result<Self> {
168        Ok(Self { entity_id: read.read_u32()? })
169    }
170
171}
172
173impl TopElement for CellEntityMethodExt {
174    const LEN: ElementLength = ElementLength::Variable16;
175}
176
177
178/// Sent by the client to the base app to call a base method for the 
179/// currently connected entity.
180#[derive(Debug, Clone)]
181pub struct BaseEntityMethod<M: MethodCall> {
182    pub method: M,
183}
184
185impl<M: MethodCall> BaseEntityMethod<M> {
186
187    /// Write this base entity method call to the given bundle.
188    pub fn write(self, writer: BundleElementWriter) {
189        MethodCallWrapper::new(self.method, BaseEntityMethodExt).write(writer);
190    }
191
192    /// Read this base entity method call from the given top element reader.
193    pub fn read(reader: TopElementReader) -> BundleResult<BundleElement<Self>> {
194        MethodCallWrapper::<M, BaseEntityMethodExt>::read(reader).map(|res| {
195            res.map(|wrapper| Self {
196                method: wrapper.method,
197            })
198        })
199    }
200
201}
202
203#[derive(Default)]
204struct BaseEntityMethodExt;
205
206impl MethodCallExt for BaseEntityMethodExt {
207    const ID_RANGE: ElementIdRange = id::BASE_ENTITY_METHOD;
208}
209
210impl NoopElement for BaseEntityMethodExt {}
211
212impl TopElement for BaseEntityMethodExt {
213    const LEN: ElementLength = ElementLength::Variable16;
214}