ygopro-msg-encode 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +4 -0
- package/.eslintrc.js +25 -0
- package/.prettierrc +4 -0
- package/AGENTS.md +12 -0
- package/CHANGES.md +270 -0
- package/CTOS_STOC_IMPLEMENTATION.md +279 -0
- package/FINAL_SUMMARY.md +357 -0
- package/FULL_PAYLOAD_SUMMARY.md +491 -0
- package/FULL_PAYLOAD_UPDATE.md +598 -0
- package/IMPLEMENTATION_SUMMARY.md +294 -0
- package/LICENSE +22 -0
- package/MSG_IMPLEMENTATION_SUMMARY.md +358 -0
- package/OPPONENT_VIEW_SUMMARY.md +387 -0
- package/PROJECT_COMPLETE.md +565 -0
- package/QUICK_REFERENCE.md +352 -0
- package/README.md +494 -0
- package/REAL_IP_STRING_UPDATE.md +289 -0
- package/TESTS_MIGRATION.md +342 -0
- package/VARIABLE_LENGTH_STRINGS.md +224 -0
- package/VARIABLE_LENGTH_UPDATE.md +229 -0
- package/dist/index.cjs +5131 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.mjs +5185 -0
- package/dist/index.mjs.map +7 -0
- package/dist/src/binary/binary-meta.d.ts +18 -0
- package/dist/src/binary/fill-binary-fields.d.ts +2 -0
- package/dist/src/metadata.d.ts +10 -0
- package/dist/src/proto-base/payload-base.d.ts +8 -0
- package/dist/src/proto-base/registry-base.d.ts +13 -0
- package/dist/src/protos/common/host-info.d.ts +12 -0
- package/dist/src/protos/common/index.d.ts +1 -0
- package/dist/src/protos/ctos/base.d.ts +17 -0
- package/dist/src/protos/ctos/index.d.ts +3 -0
- package/dist/src/protos/ctos/proto/chat.d.ts +9 -0
- package/dist/src/protos/ctos/proto/create-game.d.ts +8 -0
- package/dist/src/protos/ctos/proto/external-address.d.ts +12 -0
- package/dist/src/protos/ctos/proto/hand-result.d.ts +5 -0
- package/dist/src/protos/ctos/proto/hs-notready.d.ts +4 -0
- package/dist/src/protos/ctos/proto/hs-ready.d.ts +4 -0
- package/dist/src/protos/ctos/proto/hs-start.d.ts +4 -0
- package/dist/src/protos/ctos/proto/hs-toduelist.d.ts +4 -0
- package/dist/src/protos/ctos/proto/hs-toobserver.d.ts +4 -0
- package/dist/src/protos/ctos/proto/index.d.ts +19 -0
- package/dist/src/protos/ctos/proto/join-game.d.ts +7 -0
- package/dist/src/protos/ctos/proto/kick.d.ts +5 -0
- package/dist/src/protos/ctos/proto/leave-game.d.ts +4 -0
- package/dist/src/protos/ctos/proto/player-info.d.ts +5 -0
- package/dist/src/protos/ctos/proto/request-field.d.ts +4 -0
- package/dist/src/protos/ctos/proto/response.d.ts +7 -0
- package/dist/src/protos/ctos/proto/surrender.d.ts +4 -0
- package/dist/src/protos/ctos/proto/time-confirm.d.ts +4 -0
- package/dist/src/protos/ctos/proto/tp-result.d.ts +5 -0
- package/dist/src/protos/ctos/proto/update-deck.d.ts +11 -0
- package/dist/src/protos/ctos/registry.d.ts +3 -0
- package/dist/src/protos/msg/base.d.ts +9 -0
- package/dist/src/protos/msg/index.d.ts +3 -0
- package/dist/src/protos/msg/proto/add-counter.d.ts +9 -0
- package/dist/src/protos/msg/proto/announce-attrib.d.ts +7 -0
- package/dist/src/protos/msg/proto/announce-card.d.ts +7 -0
- package/dist/src/protos/msg/proto/announce-number.d.ts +7 -0
- package/dist/src/protos/msg/proto/announce-race.d.ts +7 -0
- package/dist/src/protos/msg/proto/attack-disabled.d.ts +4 -0
- package/dist/src/protos/msg/proto/attack.d.ts +12 -0
- package/dist/src/protos/msg/proto/battle.d.ts +18 -0
- package/dist/src/protos/msg/proto/become-target.d.ts +6 -0
- package/dist/src/protos/msg/proto/cancel-target.d.ts +11 -0
- package/dist/src/protos/msg/proto/card-hint.d.ts +10 -0
- package/dist/src/protos/msg/proto/card-query.d.ts +38 -0
- package/dist/src/protos/msg/proto/card-target.d.ts +11 -0
- package/dist/src/protos/msg/proto/chain-disabled.d.ts +5 -0
- package/dist/src/protos/msg/proto/chain-end.d.ts +4 -0
- package/dist/src/protos/msg/proto/chain-negated.d.ts +5 -0
- package/dist/src/protos/msg/proto/chain-solved.d.ts +5 -0
- package/dist/src/protos/msg/proto/chain-solving.d.ts +5 -0
- package/dist/src/protos/msg/proto/chained.d.ts +5 -0
- package/dist/src/protos/msg/proto/chaining.d.ts +12 -0
- package/dist/src/protos/msg/proto/confirm-cards.d.ts +16 -0
- package/dist/src/protos/msg/proto/confirm-decktop.d.ts +14 -0
- package/dist/src/protos/msg/proto/confirm-extratop.d.ts +14 -0
- package/dist/src/protos/msg/proto/damage-step-end.d.ts +4 -0
- package/dist/src/protos/msg/proto/damage-step-start.d.ts +4 -0
- package/dist/src/protos/msg/proto/damage.d.ts +6 -0
- package/dist/src/protos/msg/proto/deck-top.d.ts +8 -0
- package/dist/src/protos/msg/proto/draw.d.ts +8 -0
- package/dist/src/protos/msg/proto/equip.d.ts +12 -0
- package/dist/src/protos/msg/proto/field-disabled.d.ts +5 -0
- package/dist/src/protos/msg/proto/flipsummoned.d.ts +4 -0
- package/dist/src/protos/msg/proto/flipsummoning.d.ts +9 -0
- package/dist/src/protos/msg/proto/hand-res.d.ts +5 -0
- package/dist/src/protos/msg/proto/hint.d.ts +7 -0
- package/dist/src/protos/msg/proto/index.d.ts +85 -0
- package/dist/src/protos/msg/proto/lpupdate.d.ts +6 -0
- package/dist/src/protos/msg/proto/match-kill.d.ts +5 -0
- package/dist/src/protos/msg/proto/missed-effect.d.ts +7 -0
- package/dist/src/protos/msg/proto/move.d.ts +14 -0
- package/dist/src/protos/msg/proto/new-phase.d.ts +5 -0
- package/dist/src/protos/msg/proto/new-turn.d.ts +5 -0
- package/dist/src/protos/msg/proto/pay-lpcost.d.ts +6 -0
- package/dist/src/protos/msg/proto/player-hint.d.ts +7 -0
- package/dist/src/protos/msg/proto/pos-change.d.ts +12 -0
- package/dist/src/protos/msg/proto/random-selected.d.ts +7 -0
- package/dist/src/protos/msg/proto/recover.d.ts +6 -0
- package/dist/src/protos/msg/proto/reload-field.d.ts +36 -0
- package/dist/src/protos/msg/proto/remove-counter.d.ts +9 -0
- package/dist/src/protos/msg/proto/reset-time.d.ts +6 -0
- package/dist/src/protos/msg/proto/retry.d.ts +4 -0
- package/dist/src/protos/msg/proto/reverse-deck.d.ts +4 -0
- package/dist/src/protos/msg/proto/rock-paper-scissors.d.ts +5 -0
- package/dist/src/protos/msg/proto/select-battlecmd.d.ts +25 -0
- package/dist/src/protos/msg/proto/select-card.d.ts +17 -0
- package/dist/src/protos/msg/proto/select-chain.d.ts +19 -0
- package/dist/src/protos/msg/proto/select-counter.d.ts +17 -0
- package/dist/src/protos/msg/proto/select-disfield.d.ts +7 -0
- package/dist/src/protos/msg/proto/select-effectyn.d.ts +11 -0
- package/dist/src/protos/msg/proto/select-idlecmd.d.ts +37 -0
- package/dist/src/protos/msg/proto/select-option.d.ts +7 -0
- package/dist/src/protos/msg/proto/select-place.d.ts +7 -0
- package/dist/src/protos/msg/proto/select-position.d.ts +7 -0
- package/dist/src/protos/msg/proto/select-sum.d.ts +20 -0
- package/dist/src/protos/msg/proto/select-tribute.d.ts +18 -0
- package/dist/src/protos/msg/proto/select-unselect-card.d.ts +20 -0
- package/dist/src/protos/msg/proto/select-yesno.d.ts +6 -0
- package/dist/src/protos/msg/proto/set.d.ts +5 -0
- package/dist/src/protos/msg/proto/shuffle-deck.d.ts +5 -0
- package/dist/src/protos/msg/proto/shuffle-extra.d.ts +8 -0
- package/dist/src/protos/msg/proto/shuffle-hand.d.ts +8 -0
- package/dist/src/protos/msg/proto/shuffle-set-card.d.ts +17 -0
- package/dist/src/protos/msg/proto/sort-card.d.ts +13 -0
- package/dist/src/protos/msg/proto/spsummoned.d.ts +4 -0
- package/dist/src/protos/msg/proto/spsummoning.d.ts +9 -0
- package/dist/src/protos/msg/proto/start.d.ts +14 -0
- package/dist/src/protos/msg/proto/summoned.d.ts +4 -0
- package/dist/src/protos/msg/proto/summoning.d.ts +9 -0
- package/dist/src/protos/msg/proto/swap-grave-deck.d.ts +5 -0
- package/dist/src/protos/msg/proto/swap.d.ts +12 -0
- package/dist/src/protos/msg/proto/tag-swap.d.ts +14 -0
- package/dist/src/protos/msg/proto/toss-coin.d.ts +7 -0
- package/dist/src/protos/msg/proto/toss-dice.d.ts +7 -0
- package/dist/src/protos/msg/proto/update-card.d.ts +14 -0
- package/dist/src/protos/msg/proto/update-data.d.ts +12 -0
- package/dist/src/protos/msg/proto/waiting.d.ts +4 -0
- package/dist/src/protos/msg/proto/win.d.ts +6 -0
- package/dist/src/protos/msg/registry.d.ts +3 -0
- package/dist/src/protos/stoc/base.d.ts +17 -0
- package/dist/src/protos/stoc/index.d.ts +3 -0
- package/dist/src/protos/stoc/proto/change-side.d.ts +4 -0
- package/dist/src/protos/stoc/proto/chat.d.ts +10 -0
- package/dist/src/protos/stoc/proto/create-game.d.ts +5 -0
- package/dist/src/protos/stoc/proto/deck-count.d.ts +5 -0
- package/dist/src/protos/stoc/proto/duel-end.d.ts +4 -0
- package/dist/src/protos/stoc/proto/duel-start.d.ts +4 -0
- package/dist/src/protos/stoc/proto/error-msg.d.ts +6 -0
- package/dist/src/protos/stoc/proto/field-finish.d.ts +4 -0
- package/dist/src/protos/stoc/proto/game-msg.d.ts +9 -0
- package/dist/src/protos/stoc/proto/hand-result.d.ts +6 -0
- package/dist/src/protos/stoc/proto/hs-player-change.d.ts +5 -0
- package/dist/src/protos/stoc/proto/hs-player-enter.d.ts +6 -0
- package/dist/src/protos/stoc/proto/hs-watch-change.d.ts +5 -0
- package/dist/src/protos/stoc/proto/index.d.ts +24 -0
- package/dist/src/protos/stoc/proto/join-game.d.ts +6 -0
- package/dist/src/protos/stoc/proto/leave-game.d.ts +5 -0
- package/dist/src/protos/stoc/proto/replay.d.ts +11 -0
- package/dist/src/protos/stoc/proto/select-hand.d.ts +4 -0
- package/dist/src/protos/stoc/proto/select-tp.d.ts +4 -0
- package/dist/src/protos/stoc/proto/srvpro-roomlist.d.ts +18 -0
- package/dist/src/protos/stoc/proto/teammate-surrender.d.ts +4 -0
- package/dist/src/protos/stoc/proto/time-limit.d.ts +6 -0
- package/dist/src/protos/stoc/proto/tp-result.d.ts +4 -0
- package/dist/src/protos/stoc/proto/type-change.d.ts +5 -0
- package/dist/src/protos/stoc/proto/waiting-side.d.ts +4 -0
- package/dist/src/protos/stoc/registry.d.ts +3 -0
- package/dist/src/vendor/ocgcore-constants.d.ts +360 -0
- package/dist/src/vendor/script-constants.d.ts +836 -0
- package/index.ts +6 -0
- package/package.json +74 -0
- package/scripts/gen-constants.js +156 -0
- package/tsconfig.json +20 -0
package/README.md
ADDED
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
# ygopro-msg-encode
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/ygopro-msg-encode)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
A TypeScript library for encoding and decoding YGOPro network protocols.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🎯 **Complete Protocol Support**: Implements all YGOPro network protocols (MSG, CTOS, STOC)
|
|
11
|
+
- 🔒 **Type-Safe**: Full TypeScript support with detailed type definitions
|
|
12
|
+
- ⚡ **High Performance**: Efficient binary serialization/deserialization
|
|
13
|
+
- 🎨 **Modern API**: Clean and intuitive API design with `toFullPayload()` / `fromFullPayload()`
|
|
14
|
+
- 📦 **Zero Config**: Works out of the box with sensible defaults
|
|
15
|
+
- 🧪 **Well Tested**: 100+ unit tests with comprehensive coverage
|
|
16
|
+
- 🌍 **Universal**: Supports both CommonJS and ES Modules
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install ygopro-msg-encode
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### CTOS (Client to Server) Protocols
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { YGOProCtosChat, YGOProCtos } from 'ygopro-msg-encode';
|
|
30
|
+
|
|
31
|
+
// Serialize a chat message
|
|
32
|
+
const chat = new YGOProCtosChat();
|
|
33
|
+
chat.msg = "Hello, YGOPro!";
|
|
34
|
+
const payload = chat.toFullPayload();
|
|
35
|
+
|
|
36
|
+
// Send to server
|
|
37
|
+
socket.send(payload);
|
|
38
|
+
|
|
39
|
+
// Deserialize received data
|
|
40
|
+
const received = new YGOProCtosChat();
|
|
41
|
+
received.fromFullPayload(payload);
|
|
42
|
+
console.log(received.msg); // "Hello, YGOPro!"
|
|
43
|
+
|
|
44
|
+
// Auto-detect protocol type using Registry
|
|
45
|
+
const parsed = YGOProCtos.getInstanceFromPayload(payload);
|
|
46
|
+
if (parsed instanceof YGOProCtosChat) {
|
|
47
|
+
console.log('Chat message:', parsed.msg);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### STOC (Server to Client) Protocols
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { YGOProStocChat, YGOProStoc } from 'ygopro-msg-encode';
|
|
55
|
+
|
|
56
|
+
// Serialize a server chat message
|
|
57
|
+
const chat = new YGOProStocChat();
|
|
58
|
+
chat.player_type = 0x10; // System message
|
|
59
|
+
chat.msg = "Welcome to the duel!";
|
|
60
|
+
const payload = chat.toFullPayload();
|
|
61
|
+
|
|
62
|
+
// Deserialize
|
|
63
|
+
const received = new YGOProStocChat();
|
|
64
|
+
received.fromFullPayload(payload);
|
|
65
|
+
console.log(`[${received.player_type}] ${received.msg}`);
|
|
66
|
+
|
|
67
|
+
// Auto-detect using Registry
|
|
68
|
+
const parsed = YGOProStoc.getInstanceFromPayload(payload);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### MSG (Game Messages) Protocols
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { YGOProMsgHint, YGOProMessages } from 'ygopro-msg-encode';
|
|
75
|
+
|
|
76
|
+
// Create a hint message
|
|
77
|
+
const hint = new YGOProMsgHint();
|
|
78
|
+
hint.type = 1;
|
|
79
|
+
hint.player = 0;
|
|
80
|
+
hint.desc = 0x1234;
|
|
81
|
+
|
|
82
|
+
// Serialize
|
|
83
|
+
const payload = hint.toPayload();
|
|
84
|
+
|
|
85
|
+
// Deserialize with auto-detection
|
|
86
|
+
const parsed = YGOProMessages.getInstanceFromPayload(payload);
|
|
87
|
+
if (parsed instanceof YGOProMsgHint) {
|
|
88
|
+
console.log('Hint type:', parsed.type);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Protocol Format
|
|
93
|
+
|
|
94
|
+
### CTOS/STOC Packet Structure
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
┌────────────┬────────────────┬──────────────┐
|
|
98
|
+
│ Length │ Identifier │ Body │
|
|
99
|
+
│ 2 bytes LE │ 1 byte │ Variable │
|
|
100
|
+
└────────────┴────────────────┴──────────────┘
|
|
101
|
+
|
|
102
|
+
Length = 1 (identifier) + body.length
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### MSG Packet Structure
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
┌────────────────┬──────────────┐
|
|
109
|
+
│ Identifier │ Body │
|
|
110
|
+
│ 1 byte │ Variable │
|
|
111
|
+
└────────────────┴──────────────┘
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## API Reference
|
|
115
|
+
|
|
116
|
+
### Base Classes
|
|
117
|
+
|
|
118
|
+
#### `toFullPayload(): Uint8Array`
|
|
119
|
+
|
|
120
|
+
Serializes the protocol instance to a complete packet including header.
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
const protocol = new YGOProCtosPlayerInfo();
|
|
124
|
+
protocol.name = [0x41, 0x42, 0x43, ...]; // "ABC"
|
|
125
|
+
const fullPayload = protocol.toFullPayload();
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### `fromFullPayload(data: Uint8Array): this`
|
|
129
|
+
|
|
130
|
+
Deserializes a complete packet including header.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const protocol = new YGOProCtosPlayerInfo();
|
|
134
|
+
protocol.fromFullPayload(fullPayload);
|
|
135
|
+
console.log(protocol.name);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Features:**
|
|
139
|
+
- Automatically validates packet length
|
|
140
|
+
- Automatically validates identifier
|
|
141
|
+
- Auto-truncates extra data if packet is longer than declared
|
|
142
|
+
- Throws clear errors if packet is invalid
|
|
143
|
+
|
|
144
|
+
**Error Handling:**
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
try {
|
|
148
|
+
protocol.fromFullPayload(data);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
if (error.message.includes('too short')) {
|
|
151
|
+
console.error('Incomplete packet');
|
|
152
|
+
} else if (error.message.includes('identifier mismatch')) {
|
|
153
|
+
console.error('Wrong protocol type');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### `toPayload(): Uint8Array`
|
|
159
|
+
|
|
160
|
+
Serializes only the body part (without header).
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
const body = protocol.toPayload();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### `fromPayload(data: Uint8Array): this`
|
|
167
|
+
|
|
168
|
+
Deserializes only the body part (without header).
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
protocol.fromPayload(bodyData);
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Registry System
|
|
175
|
+
|
|
176
|
+
#### Auto-Detection
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { YGOProCtos, YGOProStoc, YGOProMessages } from 'ygopro-msg-encode';
|
|
180
|
+
|
|
181
|
+
// CTOS protocols
|
|
182
|
+
const ctosProtocol = YGOProCtos.getInstanceFromPayload(fullPayload);
|
|
183
|
+
|
|
184
|
+
// STOC protocols
|
|
185
|
+
const stocProtocol = YGOProStoc.getInstanceFromPayload(fullPayload);
|
|
186
|
+
|
|
187
|
+
// MSG protocols
|
|
188
|
+
const msgProtocol = YGOProMessages.getInstanceFromPayload(bodyPayload);
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Supported Protocols
|
|
192
|
+
|
|
193
|
+
### CTOS Protocols (19)
|
|
194
|
+
|
|
195
|
+
| ID | Protocol | Description |
|
|
196
|
+
|----|----------|-------------|
|
|
197
|
+
| 0x01 | CTOS_RESPONSE | Response with data |
|
|
198
|
+
| 0x02 | CTOS_UPDATE_DECK | Update deck (using ygopro-deck-encode) |
|
|
199
|
+
| 0x03 | CTOS_HAND_RESULT | Hand result |
|
|
200
|
+
| 0x04 | CTOS_TP_RESULT | Turn player result |
|
|
201
|
+
| 0x10 | CTOS_PLAYER_INFO | Player information |
|
|
202
|
+
| 0x11 | CTOS_CREATE_GAME | Create game |
|
|
203
|
+
| 0x12 | CTOS_JOIN_GAME | Join game |
|
|
204
|
+
| 0x13 | CTOS_LEAVE_GAME | Leave game |
|
|
205
|
+
| 0x14 | CTOS_SURRENDER | Surrender |
|
|
206
|
+
| 0x15 | CTOS_TIME_CONFIRM | Time confirm |
|
|
207
|
+
| 0x16 | CTOS_CHAT | Chat message (variable length) |
|
|
208
|
+
| 0x17 | CTOS_EXTERNAL_ADDRESS | External address (variable length) |
|
|
209
|
+
| 0x20 | CTOS_HS_TODUELIST | Host: to duelist |
|
|
210
|
+
| 0x21 | CTOS_HS_TOOBSERVER | Host: to observer |
|
|
211
|
+
| 0x22 | CTOS_HS_READY | Host: ready |
|
|
212
|
+
| 0x23 | CTOS_HS_NOTREADY | Host: not ready |
|
|
213
|
+
| 0x24 | CTOS_HS_KICK | Host: kick player |
|
|
214
|
+
| 0x25 | CTOS_HS_START | Host: start duel |
|
|
215
|
+
| 0x30 | CTOS_REQUEST_FIELD | Request field |
|
|
216
|
+
|
|
217
|
+
### STOC Protocols (24)
|
|
218
|
+
|
|
219
|
+
| ID | Protocol | Description |
|
|
220
|
+
|----|----------|-------------|
|
|
221
|
+
| 0x01 | STOC_GAME_MSG | Game message (wraps MSG protocol) |
|
|
222
|
+
| 0x02 | STOC_ERROR_MSG | Error message |
|
|
223
|
+
| 0x03 | STOC_SELECT_HAND | Select hand |
|
|
224
|
+
| 0x04 | STOC_SELECT_TP | Select turn player |
|
|
225
|
+
| 0x05 | STOC_HAND_RESULT | Hand result |
|
|
226
|
+
| 0x06 | STOC_TP_RESULT | Turn player result |
|
|
227
|
+
| 0x07 | STOC_CHANGE_SIDE | Change side |
|
|
228
|
+
| 0x08 | STOC_WAITING_SIDE | Waiting for side deck |
|
|
229
|
+
| 0x09 | STOC_DECK_COUNT | Deck count |
|
|
230
|
+
| 0x11 | STOC_CREATE_GAME | Game created |
|
|
231
|
+
| 0x12 | STOC_JOIN_GAME | Join game |
|
|
232
|
+
| 0x13 | STOC_TYPE_CHANGE | Type change |
|
|
233
|
+
| 0x14 | STOC_LEAVE_GAME | Leave game |
|
|
234
|
+
| 0x15 | STOC_DUEL_START | Duel start |
|
|
235
|
+
| 0x16 | STOC_DUEL_END | Duel end |
|
|
236
|
+
| 0x17 | STOC_REPLAY | Replay data (using ygopro-yrp-encode) |
|
|
237
|
+
| 0x18 | STOC_TIME_LIMIT | Time limit |
|
|
238
|
+
| 0x19 | STOC_CHAT | Chat message (variable length) |
|
|
239
|
+
| 0x20 | STOC_HS_PLAYER_ENTER | Host: player enter |
|
|
240
|
+
| 0x21 | STOC_HS_PLAYER_CHANGE | Host: player change |
|
|
241
|
+
| 0x22 | STOC_HS_WATCH_CHANGE | Host: watch change |
|
|
242
|
+
| 0x23 | STOC_TEAMMATE_SURRENDER | Teammate surrender |
|
|
243
|
+
| 0x30 | STOC_FIELD_FINISH | Field finish |
|
|
244
|
+
| 0x31 | STOC_SRVPRO_ROOMLIST | SRVPro room list |
|
|
245
|
+
|
|
246
|
+
### MSG Protocols (100+)
|
|
247
|
+
|
|
248
|
+
All YGOPro game messages are supported. See [MSG Protocol List](./CTOS_STOC_IMPLEMENTATION.md) for details.
|
|
249
|
+
|
|
250
|
+
## Advanced Usage
|
|
251
|
+
|
|
252
|
+
### Special Protocols
|
|
253
|
+
|
|
254
|
+
#### CTOS_UPDATE_DECK
|
|
255
|
+
|
|
256
|
+
Uses `ygopro-deck-encode` library for deck encoding:
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import { YGOProCtosUpdateDeck } from 'ygopro-msg-encode';
|
|
260
|
+
import YGOProDeck from 'ygopro-deck-encode';
|
|
261
|
+
|
|
262
|
+
const updateDeck = new YGOProCtosUpdateDeck();
|
|
263
|
+
updateDeck.deck = new YGOProDeck({
|
|
264
|
+
main: [12345, 67890],
|
|
265
|
+
extra: [11111],
|
|
266
|
+
side: [22222],
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const payload = updateDeck.toFullPayload();
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
#### STOC_REPLAY
|
|
273
|
+
|
|
274
|
+
Uses `ygopro-yrp-encode` library for replay encoding:
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
import { YGOProStocReplay } from 'ygopro-msg-encode';
|
|
278
|
+
import { YGOProYrp } from 'ygopro-yrp-encode';
|
|
279
|
+
|
|
280
|
+
const replay = new YGOProStocReplay();
|
|
281
|
+
replay.replay = new YGOProYrp({
|
|
282
|
+
/* replay data */
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const payload = replay.toFullPayload();
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
#### STOC_GAME_MSG
|
|
289
|
+
|
|
290
|
+
Wraps MSG protocol messages:
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
import { YGOProStocGameMsg, YGOProMsgHint } from 'ygopro-msg-encode';
|
|
294
|
+
|
|
295
|
+
const gameMsg = new YGOProStocGameMsg();
|
|
296
|
+
const hint = new YGOProMsgHint();
|
|
297
|
+
hint.type = 1;
|
|
298
|
+
hint.player = 0;
|
|
299
|
+
hint.desc = 0x1234;
|
|
300
|
+
gameMsg.msg = hint;
|
|
301
|
+
|
|
302
|
+
const payload = gameMsg.toFullPayload();
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Variable-Length Strings
|
|
306
|
+
|
|
307
|
+
Three protocols use variable-length encoding for bandwidth optimization:
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
import { YGOProCtosChat } from 'ygopro-msg-encode';
|
|
311
|
+
|
|
312
|
+
const chat = new YGOProCtosChat();
|
|
313
|
+
chat.msg = "Hi"; // Only 6 bytes instead of fixed 512 bytes!
|
|
314
|
+
const payload = chat.toFullPayload();
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Protocols with variable-length strings:
|
|
318
|
+
- `CTOS_CHAT`
|
|
319
|
+
- `STOC_CHAT`
|
|
320
|
+
- `CTOS_EXTERNAL_ADDRESS`
|
|
321
|
+
|
|
322
|
+
### IPv4 Address Handling
|
|
323
|
+
|
|
324
|
+
`CTOS_EXTERNAL_ADDRESS` supports string-based IPv4 addresses:
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
import { YGOProCtosExternalAddress } from 'ygopro-msg-encode';
|
|
328
|
+
|
|
329
|
+
const ext = new YGOProCtosExternalAddress();
|
|
330
|
+
ext.real_ip = "192.168.1.1"; // Standard IPv4
|
|
331
|
+
ext.real_ip = "::ffff:192.168.1.1"; // IPv6-mapped IPv4 (auto-converted)
|
|
332
|
+
ext.hostname = "example.com";
|
|
333
|
+
|
|
334
|
+
const payload = ext.toFullPayload();
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
The IP address is automatically converted to/from network byte order (big-endian).
|
|
338
|
+
|
|
339
|
+
### Room List (SRVPro)
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
import { YGOProStocSrvproRoomlist, SrvproRoomInfo } from 'ygopro-msg-encode';
|
|
343
|
+
|
|
344
|
+
const roomlist = new YGOProStocSrvproRoomlist();
|
|
345
|
+
roomlist.count = 2;
|
|
346
|
+
|
|
347
|
+
const room1 = new SrvproRoomInfo();
|
|
348
|
+
room1.roomname = 'Room 1';
|
|
349
|
+
room1.room_status = 0; // Waiting
|
|
350
|
+
room1.player1 = 'Player A';
|
|
351
|
+
room1.player2 = 'Player B';
|
|
352
|
+
|
|
353
|
+
const room2 = new SrvproRoomInfo();
|
|
354
|
+
room2.roomname = 'Room 2';
|
|
355
|
+
room2.room_status = 1; // Dueling
|
|
356
|
+
room2.room_duel_count = 1;
|
|
357
|
+
|
|
358
|
+
roomlist.rooms = [room1, room2];
|
|
359
|
+
|
|
360
|
+
const payload = roomlist.toFullPayload();
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## Performance
|
|
364
|
+
|
|
365
|
+
### Optimization Tips
|
|
366
|
+
|
|
367
|
+
#### ✅ Good Practices
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
// 1. Reuse protocol instances
|
|
371
|
+
const protocol = new YGOProCtosChat();
|
|
372
|
+
for (const msg of messages) {
|
|
373
|
+
protocol.msg = msg;
|
|
374
|
+
send(protocol.toFullPayload());
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// 2. Use try-catch for error handling
|
|
378
|
+
try {
|
|
379
|
+
protocol.fromFullPayload(data);
|
|
380
|
+
} catch (error) {
|
|
381
|
+
handleError(error);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// 3. Batch processing
|
|
385
|
+
const payloads = messages.map(msg => {
|
|
386
|
+
const chat = new YGOProCtosChat();
|
|
387
|
+
chat.msg = msg;
|
|
388
|
+
return chat.toFullPayload();
|
|
389
|
+
});
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
#### ❌ Bad Practices
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
// 1. Don't create new instances in loops
|
|
396
|
+
for (const msg of messages) {
|
|
397
|
+
const protocol = new YGOProCtosChat(); // ❌ Wasteful
|
|
398
|
+
protocol.msg = msg;
|
|
399
|
+
send(protocol.toFullPayload());
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// 2. Don't ignore errors
|
|
403
|
+
protocol.fromFullPayload(data); // ❌ No error handling
|
|
404
|
+
|
|
405
|
+
// 3. Don't mix APIs unnecessarily
|
|
406
|
+
const body = protocol.toPayload(); // ❌
|
|
407
|
+
const fullPayload = new Uint8Array(3 + body.length);
|
|
408
|
+
// ... manual header construction
|
|
409
|
+
// Use toFullPayload() instead!
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Testing
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
# Run all tests
|
|
416
|
+
npm test
|
|
417
|
+
|
|
418
|
+
# Run tests with coverage
|
|
419
|
+
npm test -- --coverage
|
|
420
|
+
|
|
421
|
+
# Run specific test suite
|
|
422
|
+
npm test ctos-stoc
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
## Building
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
# Build everything
|
|
429
|
+
npm run build
|
|
430
|
+
|
|
431
|
+
# Build specific format
|
|
432
|
+
npm run build:cjs # CommonJS
|
|
433
|
+
npm run build:esm # ES Modules
|
|
434
|
+
npm run build:types # Type definitions
|
|
435
|
+
|
|
436
|
+
# Clean build output
|
|
437
|
+
npm run clean
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
## Documentation
|
|
441
|
+
|
|
442
|
+
- [CTOS/STOC Implementation](./CTOS_STOC_IMPLEMENTATION.md) - Detailed protocol implementation
|
|
443
|
+
- [MSG Implementation](./MSG_IMPLEMENTATION_SUMMARY.md) - MSG protocol details
|
|
444
|
+
- [Full Payload API](./FULL_PAYLOAD_UPDATE.md) - `toFullPayload()` / `fromFullPayload()` documentation
|
|
445
|
+
- [Quick Reference](./QUICK_REFERENCE.md) - Quick API reference
|
|
446
|
+
- [Tests Migration](./TESTS_MIGRATION.md) - Testing guide
|
|
447
|
+
|
|
448
|
+
## Dependencies
|
|
449
|
+
|
|
450
|
+
- **Runtime Dependencies**:
|
|
451
|
+
- `typed-reflector` - Decorator metadata support
|
|
452
|
+
- `ygopro-deck-encode` - Deck encoding/decoding
|
|
453
|
+
- `ygopro-yrp-encode` - Replay encoding/decoding
|
|
454
|
+
|
|
455
|
+
- **Development Dependencies**:
|
|
456
|
+
- TypeScript, ESLint, Prettier
|
|
457
|
+
- Jest for testing
|
|
458
|
+
- esbuild for bundling
|
|
459
|
+
|
|
460
|
+
## Contributing
|
|
461
|
+
|
|
462
|
+
Contributions are welcome! Please follow these guidelines:
|
|
463
|
+
|
|
464
|
+
1. Fork the repository
|
|
465
|
+
2. Create a feature branch
|
|
466
|
+
3. Write tests for your changes
|
|
467
|
+
4. Ensure all tests pass (`npm test`)
|
|
468
|
+
5. Ensure code is properly formatted (`npm run lint`)
|
|
469
|
+
6. Submit a pull request
|
|
470
|
+
|
|
471
|
+
## License
|
|
472
|
+
|
|
473
|
+
MIT © [Nanahira](https://github.com/purerosefallen)
|
|
474
|
+
|
|
475
|
+
## Credits
|
|
476
|
+
|
|
477
|
+
- Based on [YGOPro](https://github.com/Fluorohydride/ygopro) protocol specifications
|
|
478
|
+
- Implements protocols from `ocgcore/network.h` and `gframe/duelclient.cpp`
|
|
479
|
+
|
|
480
|
+
## Support
|
|
481
|
+
|
|
482
|
+
- 🐛 [Report Issues](https://github.com/purerosefallen/ygopro-msg-encode/issues)
|
|
483
|
+
- 💬 [Discussions](https://github.com/purerosefallen/ygopro-msg-encode/discussions)
|
|
484
|
+
- 📧 Email: nanahira@momobako.com
|
|
485
|
+
|
|
486
|
+
## Related Projects
|
|
487
|
+
|
|
488
|
+
- [ygopro-deck-encode](https://github.com/purerosefallen/ygopro-deck-encode) - YGOPro deck encoding
|
|
489
|
+
- [ygopro-yrp-encode](https://github.com/purerosefallen/ygopro-yrp-encode) - YGOPro replay encoding
|
|
490
|
+
- [YGOPro](https://github.com/Fluorohydride/ygopro) - The original YGOPro client
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
Made with ❤️ for the YGOPro community
|