1use std::ops::Deref;
11use std::ops::DerefMut;
12
13#[cfg(feature = "card")]
14use rusqlite::Connection;
15#[cfg(feature = "card")]
16use rusqlite::Row;
17
18use crate::constants::*;
19
20
21const SIZE_SETCODE: usize = 16;
22const SIZE_DESC: usize = 16;
23
24#[repr(C)]
31#[derive(Clone, Default, Debug)]
32pub struct CoreCard {
33 pub code: u32,
34 pub alias: u32,
35 pub setcode: [u16; SIZE_SETCODE],
36 pub card_type: Type,
37 pub level: u32,
38 pub attribute: Attribute,
39 pub race: Race,
40 pub attack: i32,
41 pub defense: i32,
42 pub left_scale: u32,
43 pub right_scale: u32,
44 pub link_marker: Linkmarkers,
45 pub rule_code: u32,
46}
47
48impl CoreCard {
49 pub fn original_code(&self) -> u32 {
51 if self.alias != 0 { self.alias } else { self.code }
52 }
53
54 pub fn duel_code(&self) -> u32 {
56 if self.rule_code != 0 { self.rule_code } else { self.original_code() }
57 }
58
59 pub fn is_setcodes(&self, value: u32) -> bool {
61 for x in &self.setcode {
62 if *x == 0 { return false; }
63 if check_setcode(*x as u32, value) {
64 return true;
65 }
66 }
67 false
68 }
69}
70
71pub fn check_setcode(setcode: u32, value: u32) -> bool {
73 setcode > 0 &&
74 (setcode & 0x0fffu32) == (value & 0x0fffu32) &&
75 (setcode & (value & 0xf000u32)) == (value & 0xf000u32)
76}
77
78#[derive(Clone, Default, Debug)]
80pub struct Card {
81 pub card: CoreCard,
83 pub ot: OT,
85 pub category: Category,
87 pub name: String,
89 pub text: String,
91 pub desc: [String; SIZE_DESC],
93}
94
95impl Deref for Card {
96 type Target = CoreCard;
97
98 fn deref(&self) -> &Self::Target {
99 &self.card
100 }
101}
102
103impl DerefMut for Card {
104 fn deref_mut(&mut self) -> &mut Self::Target {
105 &mut self.card
106 }
107}
108
109#[cfg(feature = "card")]
110impl<'row, 'stmt> TryFrom<&'row Row<'stmt>> for CoreCard {
111 type Error = rusqlite::Error;
112
113 fn try_from(row: &'row Row<'stmt>) -> Result<Self, Self::Error> {
114 let level_raw: u32 = row.get(7)?;
115 let defense_raw: i32 = row.get(6)?;
116 let setcode_raw: i64 = row.get(3)?;
117 let card_type: Type = Type::from_bits_retain(row.get(4)?);
118 let is_link = card_type.contains(Type::Link);
119 Ok(CoreCard {
120 code: row.get(0)?,
121 alias: row.get(2)?,
122 setcode: {
123 let mut sc = [0u16; SIZE_SETCODE];
124 sc[0] = (setcode_raw & 0xFFFF) as u16;
125 sc[1] = ((setcode_raw >> 16) & 0xFFFF) as u16;
126 sc[2] = ((setcode_raw >> 32) & 0xFFFF) as u16;
127 sc[3] = ((setcode_raw >> 48) & 0xFFFF) as u16;
128 sc
129 },
130 card_type,
131 level: level_raw & 0xFF,
132 attribute: Attribute::from_bits_retain(row.get(9)?),
133 race: Race::from_bits_retain(row.get(8)?),
134 attack: row.get(5)?,
135 defense: defense_raw,
136 left_scale: (level_raw >> 24) & 0xFF,
137 right_scale: (level_raw >> 16) & 0xFF,
138 link_marker: if is_link {
139 Linkmarkers::from_bits_retain(defense_raw as u32)
140 } else {
141 Linkmarkers::empty()
142 },
143 rule_code: 0,
144 })
145 }
146}
147
148#[cfg(feature = "card")]
149impl<'row, 'stmt> TryFrom<&'row Row<'stmt>> for Card {
150 type Error = rusqlite::Error;
151
152 fn try_from(row: &'row Row<'stmt>) -> Result<Self, Self::Error> {
153 Ok(Card {
154 card: CoreCard::try_from(row)?,
155 ot: OT::from_bits_retain(row.get::<_, i64>(1)? as u8),
156 category: Category::from_bits_retain(row.get::<_, i64>(10)? as u32),
157 name: row.get(11)?,
158 text: row.get(12)?,
159 desc: [
160 row.get(13)?,
161 row.get(14)?,
162 row.get(15)?,
163 row.get(16)?,
164 row.get(17)?,
165 row.get(18)?,
166 row.get(19)?,
167 row.get(20)?,
168 row.get(21)?,
169 row.get(22)?,
170 row.get(23)?,
171 row.get(24)?,
172 row.get(25)?,
173 row.get(26)?,
174 row.get(27)?,
175 row.get(28)?,
176 ],
177 })
178 }
179}
180
181#[cfg(feature = "card")]
183pub fn load_db<C>(connection: Connection) -> Result<Vec<C>, rusqlite::Error>
184where
185 C: for<'row, 'stmt> TryFrom<&'row Row<'stmt>, Error = rusqlite::Error>,
186{
187 let query = concat!(
188 "SELECT d.id, d.ot, d.alias, d.setcode, d.type, d.atk, d.def, d.level, d.race, d.attribute, d.category,",
189 " t.name, t.desc, t.str1, t.str2, t.str3, t.str4, t.str5, t.str6, t.str7, t.str8,",
190 " t.str9, t.str10, t.str11, t.str12, t.str13, t.str14, t.str15, t.str16",
191 " FROM datas d LEFT JOIN texts t ON d.id = t.id",
192 );
193 let mut stmt = connection.prepare(query)?;
194 let res = stmt.query_map([], |row| C::try_from(row))?
195 .collect::<Result<Vec<_>, _>>()?;
196 Ok(res)
197}
198
199#[cfg(feature = "card")]
201pub fn load_db_from_file<C>(file: &str) -> Result<Vec<C>, rusqlite::Error>
202where
203 C: for<'row, 'stmt> TryFrom<&'row Row<'stmt>, Error = rusqlite::Error>,
204{
205 let connection = Connection::open(file)?;
206 load_db(connection)
207}
208
209#[cfg(feature = "card")]
211pub fn load_db_from_bytes<C>(bytes: &[u8]) -> Result<Vec<C>, rusqlite::Error>
212where
213 C: for<'row, 'stmt> TryFrom<&'row Row<'stmt>, Error = rusqlite::Error>,
214{
215 let mut connection = Connection::open_in_memory()?;
216 let mut cursor = std::io::Cursor::new(bytes);
217 connection.deserialize_read_exact("main", &mut cursor, bytes.len(), true)?;
218 load_db(connection)
219}
220
221mod test {
222 #![allow(unused_imports)]
223
224 use crate::data::Card;
225 use crate::data::CoreCard;
226 use crate::constants::*;
227 use crate::data::card::SIZE_SETCODE;
228
229 #[test]
230 fn validate_core_card_raw_bytes() {
231 let card = CoreCard {
232 code: 0xAABBCCDD,
233 alias: 0x11223344,
234 setcode: {
235 let mut sc = [0u16; SIZE_SETCODE];
236 sc[0] = 0x5566;
237 sc[1] = 0x7788;
238 sc[2] = 0x99aa;
239 sc
240 },
241 card_type: Type::Monster | Type::Effect,
242 level: 8,
243 attribute: Attribute::Dark,
244 race: Race::Dragon,
245 attack: 3000,
246 defense: 2500,
247 left_scale: 4,
248 right_scale: 4,
249 link_marker: Linkmarkers::Bottom | Linkmarkers::Top,
250 rule_code: 0xDEADBEEF,
251 };
252 unsafe {
253 let p = &card as *const CoreCard as *const u8;
254 let n = std::mem::size_of::<CoreCard>();
255 let bytes = std::slice::from_raw_parts(p, n);
256 assert_eq!(
257 bytes,
258 &[
259 0xdd, 0xcc, 0xbb, 0xaa, 0x44, 0x33, 0x22, 0x11, 0x66, 0x55, 0x88, 0x77, 0xaa, 0x99, 0x00, 0x00,
263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 0x21, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xb8, 0x0b, 0x00, 0x00, 0xc4, 0x09, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0xef, 0xbe, 0xad, 0xde, ][..]
277 );
278 }
279 }
280}