1use binrw::BinRead;
6use binrw::BinWrite;
7use binrw::VecArgs;
8use binrw::helpers::until_eof;
9use binrw::io::Cursor;
10use binrw::io::Read;
11use binrw::io::Seek;
12use binrw::io::Write;
13
14use crate::constants::*;
15use crate::message::gm;
16
17#[derive(BinRead, BinWrite, Debug, Clone, Copy, PartialEq, Eq)]
19#[brw(repr = u16)]
20#[repr(u16)]
21pub enum IdleCommand {
22 Summon = 0,
23 SpecialSummon = 1,
24 Reposition = 2,
25 SetMonster = 3,
26 SetSpellTrap = 4,
27 Activate = 5,
28 EnterBattlePhase = 6,
29 EnterEndPhase = 7,
30 ShuffleDeck = 8,
31}
32
33#[derive(BinRead, BinWrite, Debug, Clone, Copy, PartialEq, Eq)]
35#[brw(repr = u16)]
36#[repr(u16)]
37pub enum BattleCommand {
38 Activate = 0,
39 Attack = 1,
40 EnterMainPhase2 = 2,
41 EnterEndPhase = 3,
42}
43
44#[derive(Debug, Clone)]
50pub enum Response {
51 Cancel,
55 SelectIdleCommand(IdleCommand, u16),
57 SelectBattleCommand(BattleCommand, u16),
59 SelectYesNo(bool),
62 SelectOption(u8),
65 SelectChain(u8),
67 DeclineChain,
69 SelectPosition(Position),
71 SelectCards(Vec<u16>),
73 SelectUnselectCards(u16),
75 SelectTribute(Vec<u16>),
77 SelectSum(Vec<u16>),
79 SelectCounter(Vec<u16>),
81 SelectPlace(CorePlayer, Location, u8),
84 DeclinePlace,
87 SortCards(Vec<u16>),
89 KeepCardOrder,
91 AnnounceRace(Race),
93 AnnounceAttribute(Attribute),
95 AnnounceCard(u32),
97 Unknown(Vec<u8>),
99}
100
101impl BinWrite for Response {
102 type Args<'a> = ();
103
104 fn write_options<W: Write + Seek>(&self, writer: &mut W, endian: binrw::Endian, _args: ()) -> binrw::BinResult<()> {
105 let args = ();
106 match self {
107 Response::Cancel => (-1i32).write_options(writer, endian, args)?,
108 Response::SelectIdleCommand(command, card_index) => {
109 command.write_options(writer, endian, args)?;
110 card_index.write_options(writer, endian, args)?;
111 }
112 Response::SelectBattleCommand(command, card_index) => {
113 command.write_options(writer, endian, args)?;
114 card_index.write_options(writer, endian, args)?;
115 }
116 Response::SelectYesNo(yes) => u8::from(*yes).write_options(writer, endian, args)?,
117 Response::SelectOption(index) => index.write_options(writer, endian, args)?,
118 Response::SelectChain(index) => index.write_options(writer, endian, args)?,
119 Response::DeclineChain => (-1i32).write_options(writer, endian, args)?,
120 Response::SelectPosition(position) => position.write_options(writer, endian, args)?,
121 Response::SelectCards(card_indices) => {
122 let len = card_indices.len() as u8;
123 len.write_options(writer, endian, args)?;
124 card_indices.write_options(writer, endian, args)?;
125 }
126 Response::SelectUnselectCards(card_index) => {
127 1u8.write_options(writer, endian, args)?;
128 card_index.write_options(writer, endian, args)?;
129 }
130 Response::SelectTribute(card_indices) => {
131 let len = card_indices.len() as u8;
132 len.write_options(writer, endian, args)?;
133 card_indices.write_options(writer, endian, args)?;
134 }
135 Response::SelectSum(card_indices) => {
136 let len = card_indices.len() as u8;
137 len.write_options(writer, endian, args)?;
138 card_indices.write_options(writer, endian, args)?;
139 }
140 Response::SelectCounter(counts) => counts.write_options(writer, endian, args)?,
141 Response::SelectPlace(player, location, sequence) => {
142 player.write_options(writer, endian, args)?;
143 location.write_options(writer, endian, args)?;
144 sequence.write_options(writer, endian, args)?;
145 }
146 Response::DeclinePlace => [0u8; 3].write_options(writer, endian, args)?,
147 Response::SortCards(order) => order.write_options(writer, endian, args)?,
148 Response::KeepCardOrder => 0xffu8.write_options(writer, endian, args)?,
149 Response::AnnounceRace(races) => races.write_options(writer, endian, args)?,
150 Response::AnnounceAttribute(attributes) => attributes.write_options(writer, endian, args)?,
151 Response::AnnounceCard(code) => code.write_options(writer, endian, args)?,
152 Response::Unknown(data) => data.write_options(writer, endian, args)?,
153 }
154 Ok(())
155 }
156}
157
158impl Response {
159 pub fn len(&self) -> usize {
160 match self {
161 Response::Cancel => 4,
162 Response::SelectIdleCommand(_, _) => 4,
163 Response::SelectBattleCommand(_, _) => 4,
164 Response::SelectYesNo(_) => 1,
165 Response::SelectOption(_) => 1,
166 Response::SelectChain(_) => 1,
167 Response::DeclineChain => 4,
168 Response::SelectPosition(_) => 1,
169 Response::SelectCards(card_indices) => 1 + card_indices.len() * 2,
170 Response::SelectUnselectCards(_) => 3,
171 Response::SelectTribute(card_indices) => 1 + card_indices.len() * 2,
172 Response::SelectSum(card_indices) => 1 + card_indices.len() * 2,
173 Response::SelectCounter(counts) => counts.len() * 2,
174 Response::SelectPlace(_, _, _) => 3,
175 Response::DeclinePlace => 3,
176 Response::SortCards(order) => order.len() * 2,
177 Response::KeepCardOrder => 1,
178 Response::AnnounceRace(_) => 4,
179 Response::AnnounceAttribute(_) => 4,
180 Response::AnnounceCard(_) => 4,
181 Response::Unknown(data) => data.len(),
182 }
183 }
184
185 pub fn resolve(&mut self, message_type: gm::MessageType) -> binrw::BinResult<()> {
186 let data = match self {
187 Response::Unknown(data) => data,
188 _ => return Ok(()),
189 };
190 *self = Self::parse(&mut Cursor::new(data.as_slice()), binrw::Endian::Little, message_type)?;
191 Ok(())
192 }
193
194 fn parse<R: Read + Seek>(reader: &mut R, endian: binrw::Endian, message_type: gm::MessageType) -> binrw::BinResult<Response> {
195 match message_type {
196 gm::MessageType::SelectIdleCommand => Ok(Response::SelectIdleCommand(IdleCommand::read_options(reader, endian, ())?, u16::read_options(reader, endian, ())?)),
197 gm::MessageType::SelectBattleCommand => Ok(Response::SelectBattleCommand(BattleCommand::read_options(reader, endian, ())?, u16::read_options(reader, endian, ())?)),
198 gm::MessageType::SelectEffectYesNo | gm::MessageType::SelectYesNo => Ok(Response::SelectYesNo(u8::read_options(reader, endian, ())? != 0)),
199 gm::MessageType::SelectOption | gm::MessageType::AnnounceNumber => Ok(Response::SelectOption(u8::read_options(reader, endian, ())?)),
200 gm::MessageType::SelectPosition => Ok(Response::SelectPosition(Position::read_options(reader, endian, ())?)),
201 gm::MessageType::SelectCounter => Ok(Response::SelectCounter(until_eof::<_, u16, (), Vec<u16>>(reader, endian, ())?)),
202 gm::MessageType::AnnounceRace => Ok(Response::AnnounceRace(Race::read_options(reader, endian, ())?)),
203 gm::MessageType::AnnounceAttribute => Ok(Response::AnnounceAttribute(Attribute::read_options(reader, endian, ())?)),
204 gm::MessageType::AnnounceCard => Ok(Response::AnnounceCard(u32::read_options(reader, endian, ())?)),
205 gm::MessageType::SelectChain => {
206 if read_all_remaining(reader)? == &(-1i32).to_le_bytes() {
207 return Ok(Response::DeclineChain);
208 }
209 Ok(Response::SelectChain(u8::read_options(reader, endian, ())?))
210 }
211 gm::MessageType::SelectCard => {
212 if read_all_remaining(reader)? == &(-1i32).to_le_bytes() {
213 return Ok(Response::Cancel);
214 }
215 let len = u8::read_options(reader, endian, ())?;
216 Ok(Response::SelectCards(Vec::<u16>::read_options(reader, endian, VecArgs { count: len as usize, inner: () })?))
217 }
218 gm::MessageType::SelectUnselectCard => {
219 if read_all_remaining(reader)? == &(-1i32).to_le_bytes() {
220 return Ok(Response::Cancel);
221 }
222 let marker = u8::read_options(reader, endian, ())?;
223 if marker != 1 {
224 return Err(binrw::Error::NoVariantMatch { pos: reader.stream_position()? });
225 }
226 Ok(Response::SelectUnselectCards(u16::read_options(reader, endian, ())?))
227 }
228 gm::MessageType::SelectTribute => {
229 if read_all_remaining(reader)? == &(-1i32).to_le_bytes() {
230 return Ok(Response::Cancel);
231 }
232 let len = u8::read_options(reader, endian, ())?;
233 Ok(Response::SelectTribute(Vec::<u16>::read_options(reader, endian, VecArgs { count: len as usize, inner: () })?))
234 }
235 gm::MessageType::SelectSum => {
236 let len = u8::read_options(reader, endian, ())?;
237 Ok(Response::SelectSum(Vec::<u16>::read_options(reader, endian, VecArgs { count: len as usize, inner: () })?))
238 }
239 gm::MessageType::SelectPlace | gm::MessageType::SelectDisableField => {
240 let player = CorePlayer::read_options(reader, endian, ())?;
241 let location = Location::read_options(reader, endian, ())?;
242 let sequence = u8::read_options(reader, endian, ())?;
243 if player == CorePlayer::FirstAttackPlayer && location.is_empty() && sequence == 0 {
244 Ok(Response::DeclinePlace)
245 } else {
246 Ok(Response::SelectPlace(player, location, sequence))
247 }
248 }
249 gm::MessageType::SortCard => {
250 if read_all_remaining(reader)? == &[0xffu8] {
251 return Ok(Response::KeepCardOrder);
252 }
253 Ok(Response::SortCards(until_eof::<_, u16, (), Vec<u16>>(reader, endian, ())?))
254 }
255 _ => Err(binrw::Error::NoVariantMatch { pos: reader.stream_position()? }),
256 }
257 }
258}
259
260impl BinRead for Response {
261 type Args<'a> = Option<gm::MessageType>;
262
263 fn read_options<R: Read + Seek>(reader: &mut R, endian: binrw::Endian, message_type: Self::Args<'_>) -> binrw::BinResult<Self> {
264 match message_type {
265 Some(message_type) => Self::parse(reader, endian, message_type),
266 None => Ok(Response::Unknown(until_eof::<_, u8, (), Vec<u8>>(reader, endian, ())?)),
267 }
268 }
269}
270
271fn read_all_remaining<R: Read + Seek>(reader: &mut R) -> binrw::BinResult<Vec<u8>> {
272 let pos = reader.stream_position()?;
273 let mut data = Vec::new();
274 reader.read_to_end(&mut data)?;
275 reader.seek(std::io::SeekFrom::Start(pos))?;
276 Ok(data)
277}