Commit daa6eb35 authored by nanahira's avatar nanahira

add toUpdateDeckPayload

parent 80a9cdc5
import { countItems } from './src/utils'; import { BufferWriter, countItems } from './src/utils';
import { Base64 } from 'js-base64'; import { Base64 } from 'js-base64';
export default class YGOProDeck { export default class YGOProDeck {
...@@ -13,14 +13,9 @@ export default class YGOProDeck { ...@@ -13,14 +13,9 @@ export default class YGOProDeck {
toUint8Array() { toUint8Array() {
const counted = [this.main, this.extra, this.side].map(countItems); const counted = [this.main, this.extra, this.side].map(countItems);
const buf = new Uint8Array(counted.reduce((a, b) => a + b.size * 4, 0)); const writer = new BufferWriter(
let pointer = 0; counted.reduce((a, b) => a + b.size * 4, 0),
const writeUint32LE = (value: number) => { );
buf[pointer++] = value & 0xff;
buf[pointer++] = (value >> 8) & 0xff;
buf[pointer++] = (value >> 16) & 0xff;
buf[pointer++] = (value >> 24) & 0xff;
};
const writeCards = (countMap: Map<number, number>, type: number) => { const writeCards = (countMap: Map<number, number>, type: number) => {
// each card: 28 bits for id, 2 bits(0, 1, 2, 3) for type(0: main, 1: extra, 2: side, 3: unknown), 2 bits for count (0: 1, 1: 2, 2: 3, 3: 4) // each card: 28 bits for id, 2 bits(0, 1, 2, 3) for type(0: main, 1: extra, 2: side, 3: unknown), 2 bits for count (0: 1, 1: 2, 2: 3, 3: 4)
for (const [id, count] of countMap.entries()) { for (const [id, count] of countMap.entries()) {
...@@ -28,11 +23,11 @@ export default class YGOProDeck { ...@@ -28,11 +23,11 @@ export default class YGOProDeck {
throw new Error(`Too many cards: ${id}`); throw new Error(`Too many cards: ${id}`);
} }
const value = (id & 0xfffffff) | (type << 28) | ((count - 1) << 30); const value = (id & 0xfffffff) | (type << 28) | ((count - 1) << 30);
writeUint32LE(value); writer.writeUint32LE(value);
} }
}; };
counted.forEach(writeCards); counted.forEach(writeCards);
return buf; return writer.buffer;
} }
toEncodedString() { toEncodedString() {
...@@ -66,7 +61,7 @@ export default class YGOProDeck { ...@@ -66,7 +61,7 @@ export default class YGOProDeck {
return this.fromUint8Array(Base64.toUint8Array(str)); return this.fromUint8Array(Base64.toUint8Array(str));
} }
static fromEncodedString(str: string) { static fromEncodedString(str: string) {
return new YGOProDeck().fromEncodedString(str); return new YGOProDeck().fromEncodedString(str);
} }
...@@ -106,4 +101,13 @@ export default class YGOProDeck { ...@@ -106,4 +101,13 @@ export default class YGOProDeck {
static fromYdkString(str: string) { static fromYdkString(str: string) {
return new YGOProDeck().fromYdkString(str); return new YGOProDeck().fromYdkString(str);
} }
toUpdateDeckPayload() {
const cards = [...this.main, ...this.extra, ...this.side];
const writer = new BufferWriter(cards.length * 4 + 8)
.writeUint32LE(this.main.length + this.extra.length)
.writeUint32LE(this.side.length);
cards.forEach((id) => writer.writeUint32LE(id));
return writer.buffer;
}
} }
...@@ -5,3 +5,50 @@ export function countItems<T>(arr: T[]) { ...@@ -5,3 +5,50 @@ export function countItems<T>(arr: T[]) {
} }
return map; return map;
} }
export class BufferWriter {
buffer: Uint8Array;
pointer = 0;
constructor(length: number) {
this.buffer = new Uint8Array(length);
}
writeUint32LE(value: number) {
this.buffer[this.pointer++] = value & 0xff;
this.buffer[this.pointer++] = (value >> 8) & 0xff;
this.buffer[this.pointer++] = (value >> 16) & 0xff;
this.buffer[this.pointer++] = (value >> 24) & 0xff;
return this;
}
writeUint32BE(value: number) {
this.buffer[this.pointer++] = (value >> 24) & 0xff;
this.buffer[this.pointer++] = (value >> 16) & 0xff;
this.buffer[this.pointer++] = (value >> 8) & 0xff;
this.buffer[this.pointer++] = value & 0xff;
return this;
}
writeUint16LE(value: number) {
this.buffer[this.pointer++] = value & 0xff;
this.buffer[this.pointer++] = (value >> 8) & 0xff;
return this;
}
writeUint16BE(value: number) {
this.buffer[this.pointer++] = (value >> 8) & 0xff;
this.buffer[this.pointer++] = value & 0xff;
return this;
}
writeUint8(value: number) {
this.buffer[this.pointer++] = value & 0xff;
return this;
}
writeString(str: string) {
for (let i = 0; i < str.length; i++) {
this.buffer[this.pointer++] = str.charCodeAt(i);
}
return this;
}
}
...@@ -18,6 +18,24 @@ describe('Sample test.', () => { ...@@ -18,6 +18,24 @@ describe('Sample test.', () => {
encoded.replace(/[-_]/g, (m0) => (m0 == '-' ? '+' : '/')), encoded.replace(/[-_]/g, (m0) => (m0 == '-' ? '+' : '/')),
'base64', 'base64',
); );
expect(buf.readUInt32LE(0) & 0xfffffff).toBe(123);
expect((buf.readUInt32LE(0) >> 28) & 0x3).toBe(0);
expect(((buf.readUInt32LE(0) >> 30) & 0x3) + 1).toBe(3);
expect(buf.readUInt32LE(4) & 0xfffffff).toBe(456);
expect((buf.readUInt32LE(4) >> 28) & 0x3).toBe(0);
expect(((buf.readUInt32LE(4) >> 30) & 0x3) + 1).toBe(2);
expect(buf.readUInt32LE(8) & 0xfffffff).toBe(789);
expect((buf.readUInt32LE(8) >> 28) & 0x3).toBe(0);
expect(((buf.readUInt32LE(8) >> 30) & 0x3) + 1).toBe(1);
expect(buf.readUInt32LE(12) & 0xfffffff).toBe(1234);
expect((buf.readUInt32LE(12) >> 28) & 0x3).toBe(1);
expect(((buf.readUInt32LE(12) >> 30) & 0x3) + 1).toBe(1);
expect(buf.readUInt32LE(16) & 0xfffffff).toBe(5678);
expect((buf.readUInt32LE(16) >> 28) & 0x3).toBe(1);
expect(((buf.readUInt32LE(16) >> 30) & 0x3) + 1).toBe(1);
expect(buf.readUInt32LE(20) & 0xfffffff).toBe(12345);
expect((buf.readUInt32LE(20) >> 28) & 0x3).toBe(2);
expect(((buf.readUInt32LE(20) >> 30) & 0x3) + 1).toBe(1);
expect(buf.length).toBe(24); expect(buf.length).toBe(24);
const decoded = new YGOProDeck().fromEncodedString(encoded); const decoded = new YGOProDeck().fromEncodedString(encoded);
expect(decoded.main).toStrictEqual(deck.main); expect(decoded.main).toStrictEqual(deck.main);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment