1use std::io::prelude::Read;
7use std::io::prelude::Write;
8use std::io::prelude::Seek;
9
10use binrw::BinRead;
11use binrw::BinReaderExt;
12use binrw::BinWrite;
13use binrw::VecArgs;
14
15use crate::constants::*;
16use crate::message::game_message::CardCode;
17use crate::message::game_message::GameMessage;
18use ygopro_derive::GameMessage;
19
20#[derive(BinRead, BinWrite, Clone, Debug, GameMessage)]
21pub struct CardPosition<const CODE: bool, const SUB_SEQUENCE: bool, const DESCRIPTION: bool> {
22 #[brw(if(CODE))]
23 #[mask]
24 #[mask_if(self.controller != player)]
25 pub code: CardCode,
26 pub controller: CorePlayer,
27 pub location: Location,
28 pub sequence: i8,
29 #[brw(if(SUB_SEQUENCE))]
30 pub sub_sequence: i8,
31 #[brw(if(DESCRIPTION))]
32 pub description: i32
33}
34
35#[derive(BinRead, BinWrite, Debug, Copy, Clone, PartialEq, Eq)]
38pub struct InfoLocation {
39 pub controller: CorePlayer,
40 pub location: Location,
41 pub sequence: u8,
42 #[br(if(!location.contains(Location::Overlay), Position::Any))]
43 #[bw(if(!location.contains(Location::Overlay)))]
44 pub position: Position,
45 #[brw(if(location.contains(Location::Overlay)))]
46 pub overlay_sequence: u8
47}
48
49impl InfoLocation {
50 pub fn should_mask(&self) -> bool {
51 if self.position.intersects(Position::Reveal) {
52 return false;
53 }
54 if self.location.contains(Location::Hand) {
55 !self.position.intersects(Position::Faceup)
56 } else {
57 self.position.intersects(Position::Facedown)
58 }
59 }
60}
61
62#[derive(Clone, Debug)]
63pub enum QueryData {
64 Clear,
65 Code(i32),
66 Position(InfoLocation),
67 Alias(i32),
68 Type(Type),
69 Level(i32),
70 Rank(i32),
71 Attribute(Attribute),
72 Race(Race),
73 Attack(i32),
74 Defense(i32),
75 BaseAttack(i32),
76 BaseDefense(i32),
77 Reason(Reason),
78 ReasonCard(i32),
79 EquipCard(CardPosition<false, true, false>),
80 TargetCard(Vec<CardPosition<false, true, false>>),
81 OverlayCard(Vec<u32>),
82 Counters(Vec<(u16, u16)>),
83 Owner(CorePlayer),
84 Status(Status),
85 LeftScale(i32),
86 RightScale(i32),
87 Link(i32, Linkmarkers)
88}
89
90pub(crate) struct QueryDatas(Vec<QueryData>);
91
92impl BinRead for QueryDatas {
93 type Args<'a> = ();
94
95 fn read_options<R: Read + Seek>(reader: &mut R, endian: binrw::Endian, _: Self::Args<'_>,) -> binrw::prelude::BinResult<Self> {
96 let query = Query::read_options(reader, endian, ())?;
97 let mut query_datas = Vec::new();
98 if query.is_empty() { query_datas.push(QueryData::Clear); }
99 if query.contains(Query::Code) { query_datas.push(QueryData::Code(i32::read_options(reader, endian, ())?)); }
100 if query.contains(Query::Position) {
101 query_datas.push(QueryData::Position(InfoLocation::read_options(reader, endian, ())?));
102 }
103 if query.contains(Query::Alias) { query_datas.push(QueryData::Alias(i32::read_options(reader, endian, ())?)); }
104 if query.contains(Query::Type) { query_datas.push(QueryData::Type(Type::read_options(reader, endian, ())?)); }
105 if query.contains(Query::Level) { query_datas.push(QueryData::Level(i32::read_options(reader, endian, ())?)); }
106 if query.contains(Query::Rank) { query_datas.push(QueryData::Rank(i32::read_options(reader, endian, ())?)); }
107 if query.contains(Query::Attribute) { query_datas.push(QueryData::Attribute(Attribute::read_options(reader, endian, ())?)); }
108 if query.contains(Query::Race) { query_datas.push(QueryData::Race(Race::read_options(reader, endian, ())?)); }
109 if query.contains(Query::Attack) { query_datas.push(QueryData::Attack(i32::read_options(reader, endian, ())?)); }
110 if query.contains(Query::Defense) { query_datas.push(QueryData::Defense(i32::read_options(reader, endian, ())?)); }
111 if query.contains(Query::BaseAttack) { query_datas.push(QueryData::BaseAttack(i32::read_options(reader, endian, ())?)); }
112 if query.contains(Query::BaseDefense) { query_datas.push(QueryData::BaseDefense(i32::read_options(reader, endian, ())?)); }
113 if query.contains(Query::Reason) { query_datas.push(QueryData::Reason(Reason::read_options(reader, endian, ())?)); }
114 if query.contains(Query::ReasonCard) { query_datas.push(QueryData::ReasonCard(i32::read_options(reader, endian, ())?)); }
115 if query.contains(Query::EquipCard) { query_datas.push(QueryData::EquipCard(CardPosition::<false,true,false>::read_options(reader, endian, ())?)); }
116 if query.contains(Query::TargetCard) {
117 let count = u32::read_options(reader, endian, ())? as usize;
118 query_datas.push(QueryData::TargetCard(Vec::<CardPosition<false, true, false>>::read_options(reader, endian, VecArgs { count, inner: () })?));
119 }
120 if query.contains(Query::OverlayCard) {
121 let count = u32::read_options(reader, endian, ())? as usize;
122 query_datas.push(QueryData::OverlayCard(Vec::<u32>::read_options(reader, endian, VecArgs { count, inner: () })?));
123 }
124 if query.contains(Query::Counters) {
125 let count = u32::read_options(reader, endian, ())? as usize;
126 query_datas.push(QueryData::Counters(Vec::<(u16, u16)>::read_options(reader, endian, VecArgs { count, inner: () })?));
127 }
128 if query.contains(Query::Owner) {
129 query_datas.push(QueryData::Owner(CorePlayer::read_options(reader, endian, ())?));
130 reader.read_le::<[u8; 3]>()?; }
132 if query.contains(Query::Status) { query_datas.push(QueryData::Status(Status::read_options(reader, endian, ())?)); }
133 if query.contains(Query::LeftScale) { query_datas.push(QueryData::LeftScale(i32::read_options(reader, endian, ())?)); }
134 if query.contains(Query::RightScale) { query_datas.push(QueryData::RightScale(i32::read_options(reader, endian, ())?)); }
135 if query.contains(Query::Link) { query_datas.push(QueryData::Link(i32::read_options(reader, endian, ())?, Linkmarkers::read_options(reader, endian, ())?)); }
136 Ok(QueryDatas(query_datas))
137 }
138}
139
140impl<'a> From<&'a QueryData> for Query {
141 fn from(value: &'a QueryData) -> Self {
142 match value {
143 QueryData::Clear => Query::empty(),
144 QueryData::Code(_) => Query::Code,
145 QueryData::Position(_) => Query::Position,
146 QueryData::Alias(_) => Query::Alias,
147 QueryData::Type(_) => Query::Type,
148 QueryData::Level(_) => Query::Level,
149 QueryData::Rank(_) => Query::Rank,
150 QueryData::Attribute(_) => Query::Attribute,
151 QueryData::Race(_) => Query::Race,
152 QueryData::Attack(_) => Query::Attack,
153 QueryData::Defense(_) => Query::Defense,
154 QueryData::BaseAttack(_) => Query::BaseAttack,
155 QueryData::BaseDefense(_) => Query::BaseDefense,
156 QueryData::Reason(_) => Query::Reason,
157 QueryData::ReasonCard(_) => Query::ReasonCard,
158 QueryData::EquipCard(_) => Query::EquipCard,
159 QueryData::TargetCard(_) => Query::TargetCard,
160 QueryData::OverlayCard(_) => Query::OverlayCard,
161 QueryData::Counters(_) => Query::Counters,
162 QueryData::Owner(_) => Query::Owner,
163 QueryData::Status(_) => Query::Status,
164 QueryData::LeftScale(_) => Query::LeftScale,
165 QueryData::RightScale(_) => Query::RightScale,
166 QueryData::Link(_, _) => Query::Link,
167 }
168 }
169}
170
171#[derive(Clone, Debug)]
172pub enum UpdateCardInfo {
173 Empty,
174 Data(Vec<QueryData>)
175}
176
177impl GameMessage for UpdateCardInfo {
178 fn mask(&mut self) {
179 if !self.should_mask(CorePlayer::None) { return }
180 if let UpdateCardInfo::Data(data) = self {
181 data.fill(QueryData::Clear);
182 }
183 }
184
185 fn should_mask(&self, _player: CorePlayer) -> bool {
186 let data = match self {
187 UpdateCardInfo::Data(data) => data,
188 _ => return false
189 };
190 data.iter().find_map(|q| if let QueryData::Position(p) = q {
191 Some(p.should_mask())
192 } else { None }).unwrap_or(false)
193 }
194}
195
196impl BinRead for UpdateCardInfo {
197 type Args<'a> = ();
198
199 fn read_options<R: Read + Seek>(reader: &mut R, endian: binrw::Endian, _: Self::Args<'_>) -> binrw::prelude::BinResult<Self> {
200 let len = u32::read_options(reader, endian, ())?;
201 if len == 4 { return Ok(UpdateCardInfo::Empty); }
202 let pos = reader.stream_position()?;
203 let datas = QueryDatas::read_options(reader, endian, ())?;
204 reader.seek(std::io::SeekFrom::Start(pos + len as u64 - 4))?;
205 Ok(UpdateCardInfo::Data(datas.0))
206 }
207}
208
209impl BinWrite for UpdateCardInfo {
210 type Args<'a> = ();
211
212 fn write_options<W: Write + Seek>(&self, writer: &mut W, endian: binrw::Endian, _: Self::Args<'_>) -> binrw::prelude::BinResult<()> {
213 let args = ();
214 let queries = match self {
215 UpdateCardInfo::Empty => return u32::write_options(&4, writer, endian, args),
216 UpdateCardInfo::Data(data) => data
217 };
218 let flag: u32 = queries.iter().map(|query| Query::from(query).bits()).sum();
219 let mut len = 0u32;
220 let pos = writer.stream_position()?;
221 len.write_options(writer, endian, ())?;
222 flag.write_options(writer, endian, ())?;
223 for query in queries {
224 match query {
225 QueryData::Clear => (),
226 QueryData::Code(code) => code.write_options(writer, endian, args)?,
227 QueryData::Position(info_location) => info_location.write_options(writer, endian, args)?,
228 QueryData::Alias(alias) => alias.write_options(writer, endian, args)?,
229 QueryData::Type(_type) => _type.write_options(writer, endian, args)?,
230 QueryData::Level(level) => level.write_options(writer, endian, args)?,
231 QueryData::Rank(rank) => rank.write_options(writer, endian, args)?,
232 QueryData::Attribute(attribute) => attribute.write_options(writer, endian, args)?,
233 QueryData::Race(race) => race.write_options(writer, endian, args)?,
234 QueryData::Attack(attack) => attack.write_options(writer, endian, args)?,
235 QueryData::Defense(defense) => defense.write_options(writer, endian, args)?,
236 QueryData::BaseAttack(attack) => attack.write_options(writer, endian, args)?,
237 QueryData::BaseDefense(defense) => defense.write_options(writer, endian, args)?,
238 QueryData::Reason(reason) => reason.write_options(writer, endian, args)?,
239 QueryData::ReasonCard(card) => card.write_options(writer, endian, args)?,
240 QueryData::EquipCard(card) => card.write_options(writer, endian, args)?,
241 QueryData::TargetCard(cards) => {
242 let len = cards.len() as u32;
243 len.write_options(writer, endian, args)?;
244 cards.write_options(writer, endian, args)?;
245 },
246 QueryData::OverlayCard(cards) => {
247 let len = cards.len() as u32;
248 len.write_options(writer, endian, args)?;
249 cards.write_options(writer, endian, args)?;
250 },
251 QueryData::Counters(counters) => {
252 let len = counters.len() as u32;
253 len.write_options(writer, endian, args)?;
254 counters.write_options(writer, endian, args)?;
255 },
256 QueryData::Owner(owner) => {
257 owner.write_options(writer, endian, args)?;
258 [0u8; 3].write_options(writer, endian, args)?;
259 },
260 QueryData::Status(status) => status.write_options(writer, endian, args)?,
261 QueryData::LeftScale(scale) => scale.write_options(writer, endian, args)?,
262 QueryData::RightScale(scale) => scale.write_options(writer, endian, args)?,
263 QueryData::Link(link, linkmarkers) => {
264 link.write_options(writer, endian, args)?;
265 linkmarkers.write_options(writer, endian, args)?
266 },
267 }
268 }
269 let current_pos = writer.stream_position()?;
270 len = u32::try_from(current_pos - pos).map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?;
271 writer.seek(std::io::SeekFrom::Current(-(len as i64)))?;
272 len.write_options(writer, endian, args)?;
273 writer.seek(std::io::SeekFrom::Current((len - 4) as i64))?;
274 Ok(())
275 }
276}
277
278mod test {
279 #![allow(unused_imports)]
280
281 use std::io::Cursor;
282 use binrw::{BinRead, BinWrite, VecArgs};
283 use crate::data::UpdateCardInfo;
284
285 #[test]
286 fn test_deserialize_query() {
287 let arr = vec![16, 0, 0, 0, 3, 0, 0, 0, 122, 178, 159, 1, 1, 2, 0, 10, 16, 0, 0, 0, 3, 0, 0, 0, 17, 231, 97, 3, 1, 2, 1, 10, 16, 0, 0, 0, 3, 0, 0, 0, 59, 73, 201, 5, 1, 2, 2, 10, 16, 0, 0, 0, 3, 0, 0, 0, 239, 39, 81, 0, 1, 2, 3, 10, 16, 0, 0, 0, 3, 0, 0, 0, 143, 77, 182, 3, 1, 2, 4, 1];
288 let re: Vec<u8> = vec![16, 0, 0, 0, 3, 0, 0, 0, 122, 178, 159, 1, 1, 2, 0, 10, 16, 0, 0, 0, 3, 0, 0, 0, 17, 231, 97, 3, 1, 2, 1, 10, 16, 0, 0, 0, 3, 0, 0, 0, 59, 73, 201, 5, 1, 2, 2, 10, 16, 0, 0, 0, 3, 0, 0, 0, 239, 39, 81, 0, 1, 2, 3, 10, 16, 0, 0, 0, 3, 0, 0, 0, 143, 77, 182, 3, 1, 2, 4, 1];
289 let mut reader = Cursor::new(arr);
290 let replay = Vec::<UpdateCardInfo>::read_le_args(&mut reader, VecArgs {count: 5, inner: {}}).unwrap();
291 let mut writer = Cursor::new(Vec::new());
292 replay.write_le(&mut writer).unwrap();
293 let result = writer.into_inner();
294 assert_eq!(result, re, "round-trip mismatch");
295 }
296}