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.
Files changed (178) hide show
  1. package/.eslintignore +4 -0
  2. package/.eslintrc.js +25 -0
  3. package/.prettierrc +4 -0
  4. package/AGENTS.md +12 -0
  5. package/CHANGES.md +270 -0
  6. package/CTOS_STOC_IMPLEMENTATION.md +279 -0
  7. package/FINAL_SUMMARY.md +357 -0
  8. package/FULL_PAYLOAD_SUMMARY.md +491 -0
  9. package/FULL_PAYLOAD_UPDATE.md +598 -0
  10. package/IMPLEMENTATION_SUMMARY.md +294 -0
  11. package/LICENSE +22 -0
  12. package/MSG_IMPLEMENTATION_SUMMARY.md +358 -0
  13. package/OPPONENT_VIEW_SUMMARY.md +387 -0
  14. package/PROJECT_COMPLETE.md +565 -0
  15. package/QUICK_REFERENCE.md +352 -0
  16. package/README.md +494 -0
  17. package/REAL_IP_STRING_UPDATE.md +289 -0
  18. package/TESTS_MIGRATION.md +342 -0
  19. package/VARIABLE_LENGTH_STRINGS.md +224 -0
  20. package/VARIABLE_LENGTH_UPDATE.md +229 -0
  21. package/dist/index.cjs +5131 -0
  22. package/dist/index.cjs.map +7 -0
  23. package/dist/index.d.ts +6 -0
  24. package/dist/index.mjs +5185 -0
  25. package/dist/index.mjs.map +7 -0
  26. package/dist/src/binary/binary-meta.d.ts +18 -0
  27. package/dist/src/binary/fill-binary-fields.d.ts +2 -0
  28. package/dist/src/metadata.d.ts +10 -0
  29. package/dist/src/proto-base/payload-base.d.ts +8 -0
  30. package/dist/src/proto-base/registry-base.d.ts +13 -0
  31. package/dist/src/protos/common/host-info.d.ts +12 -0
  32. package/dist/src/protos/common/index.d.ts +1 -0
  33. package/dist/src/protos/ctos/base.d.ts +17 -0
  34. package/dist/src/protos/ctos/index.d.ts +3 -0
  35. package/dist/src/protos/ctos/proto/chat.d.ts +9 -0
  36. package/dist/src/protos/ctos/proto/create-game.d.ts +8 -0
  37. package/dist/src/protos/ctos/proto/external-address.d.ts +12 -0
  38. package/dist/src/protos/ctos/proto/hand-result.d.ts +5 -0
  39. package/dist/src/protos/ctos/proto/hs-notready.d.ts +4 -0
  40. package/dist/src/protos/ctos/proto/hs-ready.d.ts +4 -0
  41. package/dist/src/protos/ctos/proto/hs-start.d.ts +4 -0
  42. package/dist/src/protos/ctos/proto/hs-toduelist.d.ts +4 -0
  43. package/dist/src/protos/ctos/proto/hs-toobserver.d.ts +4 -0
  44. package/dist/src/protos/ctos/proto/index.d.ts +19 -0
  45. package/dist/src/protos/ctos/proto/join-game.d.ts +7 -0
  46. package/dist/src/protos/ctos/proto/kick.d.ts +5 -0
  47. package/dist/src/protos/ctos/proto/leave-game.d.ts +4 -0
  48. package/dist/src/protos/ctos/proto/player-info.d.ts +5 -0
  49. package/dist/src/protos/ctos/proto/request-field.d.ts +4 -0
  50. package/dist/src/protos/ctos/proto/response.d.ts +7 -0
  51. package/dist/src/protos/ctos/proto/surrender.d.ts +4 -0
  52. package/dist/src/protos/ctos/proto/time-confirm.d.ts +4 -0
  53. package/dist/src/protos/ctos/proto/tp-result.d.ts +5 -0
  54. package/dist/src/protos/ctos/proto/update-deck.d.ts +11 -0
  55. package/dist/src/protos/ctos/registry.d.ts +3 -0
  56. package/dist/src/protos/msg/base.d.ts +9 -0
  57. package/dist/src/protos/msg/index.d.ts +3 -0
  58. package/dist/src/protos/msg/proto/add-counter.d.ts +9 -0
  59. package/dist/src/protos/msg/proto/announce-attrib.d.ts +7 -0
  60. package/dist/src/protos/msg/proto/announce-card.d.ts +7 -0
  61. package/dist/src/protos/msg/proto/announce-number.d.ts +7 -0
  62. package/dist/src/protos/msg/proto/announce-race.d.ts +7 -0
  63. package/dist/src/protos/msg/proto/attack-disabled.d.ts +4 -0
  64. package/dist/src/protos/msg/proto/attack.d.ts +12 -0
  65. package/dist/src/protos/msg/proto/battle.d.ts +18 -0
  66. package/dist/src/protos/msg/proto/become-target.d.ts +6 -0
  67. package/dist/src/protos/msg/proto/cancel-target.d.ts +11 -0
  68. package/dist/src/protos/msg/proto/card-hint.d.ts +10 -0
  69. package/dist/src/protos/msg/proto/card-query.d.ts +38 -0
  70. package/dist/src/protos/msg/proto/card-target.d.ts +11 -0
  71. package/dist/src/protos/msg/proto/chain-disabled.d.ts +5 -0
  72. package/dist/src/protos/msg/proto/chain-end.d.ts +4 -0
  73. package/dist/src/protos/msg/proto/chain-negated.d.ts +5 -0
  74. package/dist/src/protos/msg/proto/chain-solved.d.ts +5 -0
  75. package/dist/src/protos/msg/proto/chain-solving.d.ts +5 -0
  76. package/dist/src/protos/msg/proto/chained.d.ts +5 -0
  77. package/dist/src/protos/msg/proto/chaining.d.ts +12 -0
  78. package/dist/src/protos/msg/proto/confirm-cards.d.ts +16 -0
  79. package/dist/src/protos/msg/proto/confirm-decktop.d.ts +14 -0
  80. package/dist/src/protos/msg/proto/confirm-extratop.d.ts +14 -0
  81. package/dist/src/protos/msg/proto/damage-step-end.d.ts +4 -0
  82. package/dist/src/protos/msg/proto/damage-step-start.d.ts +4 -0
  83. package/dist/src/protos/msg/proto/damage.d.ts +6 -0
  84. package/dist/src/protos/msg/proto/deck-top.d.ts +8 -0
  85. package/dist/src/protos/msg/proto/draw.d.ts +8 -0
  86. package/dist/src/protos/msg/proto/equip.d.ts +12 -0
  87. package/dist/src/protos/msg/proto/field-disabled.d.ts +5 -0
  88. package/dist/src/protos/msg/proto/flipsummoned.d.ts +4 -0
  89. package/dist/src/protos/msg/proto/flipsummoning.d.ts +9 -0
  90. package/dist/src/protos/msg/proto/hand-res.d.ts +5 -0
  91. package/dist/src/protos/msg/proto/hint.d.ts +7 -0
  92. package/dist/src/protos/msg/proto/index.d.ts +85 -0
  93. package/dist/src/protos/msg/proto/lpupdate.d.ts +6 -0
  94. package/dist/src/protos/msg/proto/match-kill.d.ts +5 -0
  95. package/dist/src/protos/msg/proto/missed-effect.d.ts +7 -0
  96. package/dist/src/protos/msg/proto/move.d.ts +14 -0
  97. package/dist/src/protos/msg/proto/new-phase.d.ts +5 -0
  98. package/dist/src/protos/msg/proto/new-turn.d.ts +5 -0
  99. package/dist/src/protos/msg/proto/pay-lpcost.d.ts +6 -0
  100. package/dist/src/protos/msg/proto/player-hint.d.ts +7 -0
  101. package/dist/src/protos/msg/proto/pos-change.d.ts +12 -0
  102. package/dist/src/protos/msg/proto/random-selected.d.ts +7 -0
  103. package/dist/src/protos/msg/proto/recover.d.ts +6 -0
  104. package/dist/src/protos/msg/proto/reload-field.d.ts +36 -0
  105. package/dist/src/protos/msg/proto/remove-counter.d.ts +9 -0
  106. package/dist/src/protos/msg/proto/reset-time.d.ts +6 -0
  107. package/dist/src/protos/msg/proto/retry.d.ts +4 -0
  108. package/dist/src/protos/msg/proto/reverse-deck.d.ts +4 -0
  109. package/dist/src/protos/msg/proto/rock-paper-scissors.d.ts +5 -0
  110. package/dist/src/protos/msg/proto/select-battlecmd.d.ts +25 -0
  111. package/dist/src/protos/msg/proto/select-card.d.ts +17 -0
  112. package/dist/src/protos/msg/proto/select-chain.d.ts +19 -0
  113. package/dist/src/protos/msg/proto/select-counter.d.ts +17 -0
  114. package/dist/src/protos/msg/proto/select-disfield.d.ts +7 -0
  115. package/dist/src/protos/msg/proto/select-effectyn.d.ts +11 -0
  116. package/dist/src/protos/msg/proto/select-idlecmd.d.ts +37 -0
  117. package/dist/src/protos/msg/proto/select-option.d.ts +7 -0
  118. package/dist/src/protos/msg/proto/select-place.d.ts +7 -0
  119. package/dist/src/protos/msg/proto/select-position.d.ts +7 -0
  120. package/dist/src/protos/msg/proto/select-sum.d.ts +20 -0
  121. package/dist/src/protos/msg/proto/select-tribute.d.ts +18 -0
  122. package/dist/src/protos/msg/proto/select-unselect-card.d.ts +20 -0
  123. package/dist/src/protos/msg/proto/select-yesno.d.ts +6 -0
  124. package/dist/src/protos/msg/proto/set.d.ts +5 -0
  125. package/dist/src/protos/msg/proto/shuffle-deck.d.ts +5 -0
  126. package/dist/src/protos/msg/proto/shuffle-extra.d.ts +8 -0
  127. package/dist/src/protos/msg/proto/shuffle-hand.d.ts +8 -0
  128. package/dist/src/protos/msg/proto/shuffle-set-card.d.ts +17 -0
  129. package/dist/src/protos/msg/proto/sort-card.d.ts +13 -0
  130. package/dist/src/protos/msg/proto/spsummoned.d.ts +4 -0
  131. package/dist/src/protos/msg/proto/spsummoning.d.ts +9 -0
  132. package/dist/src/protos/msg/proto/start.d.ts +14 -0
  133. package/dist/src/protos/msg/proto/summoned.d.ts +4 -0
  134. package/dist/src/protos/msg/proto/summoning.d.ts +9 -0
  135. package/dist/src/protos/msg/proto/swap-grave-deck.d.ts +5 -0
  136. package/dist/src/protos/msg/proto/swap.d.ts +12 -0
  137. package/dist/src/protos/msg/proto/tag-swap.d.ts +14 -0
  138. package/dist/src/protos/msg/proto/toss-coin.d.ts +7 -0
  139. package/dist/src/protos/msg/proto/toss-dice.d.ts +7 -0
  140. package/dist/src/protos/msg/proto/update-card.d.ts +14 -0
  141. package/dist/src/protos/msg/proto/update-data.d.ts +12 -0
  142. package/dist/src/protos/msg/proto/waiting.d.ts +4 -0
  143. package/dist/src/protos/msg/proto/win.d.ts +6 -0
  144. package/dist/src/protos/msg/registry.d.ts +3 -0
  145. package/dist/src/protos/stoc/base.d.ts +17 -0
  146. package/dist/src/protos/stoc/index.d.ts +3 -0
  147. package/dist/src/protos/stoc/proto/change-side.d.ts +4 -0
  148. package/dist/src/protos/stoc/proto/chat.d.ts +10 -0
  149. package/dist/src/protos/stoc/proto/create-game.d.ts +5 -0
  150. package/dist/src/protos/stoc/proto/deck-count.d.ts +5 -0
  151. package/dist/src/protos/stoc/proto/duel-end.d.ts +4 -0
  152. package/dist/src/protos/stoc/proto/duel-start.d.ts +4 -0
  153. package/dist/src/protos/stoc/proto/error-msg.d.ts +6 -0
  154. package/dist/src/protos/stoc/proto/field-finish.d.ts +4 -0
  155. package/dist/src/protos/stoc/proto/game-msg.d.ts +9 -0
  156. package/dist/src/protos/stoc/proto/hand-result.d.ts +6 -0
  157. package/dist/src/protos/stoc/proto/hs-player-change.d.ts +5 -0
  158. package/dist/src/protos/stoc/proto/hs-player-enter.d.ts +6 -0
  159. package/dist/src/protos/stoc/proto/hs-watch-change.d.ts +5 -0
  160. package/dist/src/protos/stoc/proto/index.d.ts +24 -0
  161. package/dist/src/protos/stoc/proto/join-game.d.ts +6 -0
  162. package/dist/src/protos/stoc/proto/leave-game.d.ts +5 -0
  163. package/dist/src/protos/stoc/proto/replay.d.ts +11 -0
  164. package/dist/src/protos/stoc/proto/select-hand.d.ts +4 -0
  165. package/dist/src/protos/stoc/proto/select-tp.d.ts +4 -0
  166. package/dist/src/protos/stoc/proto/srvpro-roomlist.d.ts +18 -0
  167. package/dist/src/protos/stoc/proto/teammate-surrender.d.ts +4 -0
  168. package/dist/src/protos/stoc/proto/time-limit.d.ts +6 -0
  169. package/dist/src/protos/stoc/proto/tp-result.d.ts +4 -0
  170. package/dist/src/protos/stoc/proto/type-change.d.ts +5 -0
  171. package/dist/src/protos/stoc/proto/waiting-side.d.ts +4 -0
  172. package/dist/src/protos/stoc/registry.d.ts +3 -0
  173. package/dist/src/vendor/ocgcore-constants.d.ts +360 -0
  174. package/dist/src/vendor/script-constants.d.ts +836 -0
  175. package/index.ts +6 -0
  176. package/package.json +74 -0
  177. package/scripts/gen-constants.js +156 -0
  178. package/tsconfig.json +20 -0
@@ -0,0 +1,387 @@
1
+ # opponentView 实现总结
2
+
3
+ 本文档总结了所有实现 `opponentView`(对手视角)的 MSG 类及其隐藏逻辑。
4
+
5
+ ## 1. MSG_DRAW (90) - 抽卡
6
+
7
+ **字段**: `player`, `count`, `cards[]`
8
+
9
+ **逻辑**: 隐藏未公开的抽卡
10
+ ```typescript
11
+ opponentView(): this {
12
+ const view = this.copy();
13
+ view.cards = view.cards.map((card) => {
14
+ // 如果卡片的高位(0x80000000)未设置,对方看不到,返回 0
15
+ if (!(card & 0x80000000)) {
16
+ return 0;
17
+ }
18
+ return card;
19
+ });
20
+ return view;
21
+ }
22
+ ```
23
+
24
+ **说明**:
25
+ - 卡片代码高位 `0x80000000` 表示该卡是否公开
26
+ - 未公开的抽卡对对手显示为 0
27
+
28
+ ---
29
+
30
+ ## 2. MSG_DECK_TOP (38) - 卡组顶部
31
+
32
+ **字段**: `player`, `sequence`, `code`
33
+
34
+ **逻辑**: 隐藏未公开的卡组顶部卡片
35
+ ```typescript
36
+ opponentView(): this {
37
+ const view = this.copy();
38
+ if (!(view.code & 0x80000000)) {
39
+ view.code = 0;
40
+ }
41
+ return view;
42
+ }
43
+ ```
44
+
45
+ **说明**:
46
+ - 只有设置了公开标志的卡组顶部卡片对手才能看到
47
+ - 未公开的显示为 0
48
+
49
+ ---
50
+
51
+ ## 3. MSG_SHUFFLE_HAND (33) - 洗手牌
52
+
53
+ **字段**: `player`, `count`, `cards[]`
54
+
55
+ **逻辑**: 完全隐藏手牌信息
56
+ ```typescript
57
+ opponentView(): this {
58
+ const view = this.copy();
59
+ view.cards = view.cards.map(() => 0);
60
+ return view;
61
+ }
62
+ ```
63
+
64
+ **说明**:
65
+ - 洗手牌时,对手完全看不到任何手牌信息
66
+ - 所有卡片都显示为 0
67
+
68
+ ---
69
+
70
+ ## 4. MSG_SHUFFLE_EXTRA (39) - 洗额外卡组
71
+
72
+ **字段**: `player`, `count`, `cards[]`
73
+
74
+ **逻辑**: 隐藏未公开的额外卡组卡片
75
+ ```typescript
76
+ opponentView(): this {
77
+ const view = this.copy();
78
+ view.cards = view.cards.map((card) => {
79
+ if (!(card & 0x80000000)) {
80
+ return 0;
81
+ }
82
+ return card;
83
+ });
84
+ return view;
85
+ }
86
+ ```
87
+
88
+ **说明**:
89
+ - 类似 MSG_DRAW,使用 `0x80000000` 标志判断是否公开
90
+ - 未公开的额外卡组卡片显示为 0
91
+
92
+ ---
93
+
94
+ ## 5. MSG_TAG_SWAP (161) - TAG 决斗交换
95
+
96
+ **字段**: `player`, `mzoneCount`, `extraCount`, `pzoneCount`, `handCount`, `handCards[]`, `extraCards[]`, `mzoneFlags`
97
+
98
+ **逻辑**: 隐藏手牌和未公开的额外卡组
99
+ ```typescript
100
+ opponentView(): this {
101
+ const view = this.copy();
102
+ view.handCards = view.handCards.map(() => 0);
103
+ view.extraCards = view.extraCards.map((card) => {
104
+ if (!(card & 0x80000000)) {
105
+ return 0;
106
+ }
107
+ return card;
108
+ });
109
+ return view;
110
+ }
111
+
112
+ teammateView(): this {
113
+ return this.opponentView(); // 队友也看不到
114
+ }
115
+ ```
116
+
117
+ **说明**:
118
+ - TAG 交换时,手牌完全隐藏
119
+ - 额外卡组只显示公开的卡片
120
+ - **特殊**: 队友视角和对手视角相同(都看不到)
121
+
122
+ ---
123
+
124
+ ## 6. MSG_CONFIRM_DECKTOP (30) - 确认卡组顶部
125
+
126
+ **字段**: `player`, `count`, `cards[]` (每张卡包含 `code`, `controller`, `location`, `sequence`)
127
+
128
+ **逻辑**: 隐藏未公开的卡片代码
129
+ ```typescript
130
+ opponentView(): this {
131
+ const view = this.copy();
132
+ view.cards = view.cards.map((card) => {
133
+ const c = { ...card };
134
+ if (!(c.code & 0x80000000)) {
135
+ c.code = 0;
136
+ }
137
+ return c;
138
+ });
139
+ return view;
140
+ }
141
+ ```
142
+
143
+ **说明**:
144
+ - 保留卡片位置信息(controller, location, sequence)
145
+ - 只隐藏未公开的卡片代码
146
+
147
+ ---
148
+
149
+ ## 7. MSG_CONFIRM_EXTRATOP (42) - 确认额外卡组顶部
150
+
151
+ **字段**: `player`, `count`, `cards[]` (每张卡包含 `code`, `controller`, `location`, `sequence`)
152
+
153
+ **逻辑**: 同 MSG_CONFIRM_DECKTOP
154
+ ```typescript
155
+ opponentView(): this {
156
+ const view = this.copy();
157
+ view.cards = view.cards.map((card) => {
158
+ const c = { ...card };
159
+ if (!(c.code & 0x80000000)) {
160
+ c.code = 0;
161
+ }
162
+ return c;
163
+ });
164
+ return view;
165
+ }
166
+ ```
167
+
168
+ **说明**:
169
+ - 逻辑完全相同于 MSG_CONFIRM_DECKTOP
170
+ - 只是针对额外卡组
171
+
172
+ ---
173
+
174
+ ## 8. MSG_CONFIRM_CARDS (31) - 确认卡片
175
+
176
+ **字段**: `player`, `unused`, `count`, `cards[]` (每张卡包含 `code`, `controller`, `location`, `sequence`, `subsequence`)
177
+
178
+ **逻辑**: 同 MSG_CONFIRM_DECKTOP
179
+ ```typescript
180
+ opponentView(): this {
181
+ const view = this.copy();
182
+ view.cards = view.cards.map((card) => {
183
+ const c = { ...card };
184
+ if (!(c.code & 0x80000000)) {
185
+ c.code = 0;
186
+ }
187
+ return c;
188
+ });
189
+ return view;
190
+ }
191
+ ```
192
+
193
+ **说明**:
194
+ - 逻辑完全相同于 MSG_CONFIRM_DECKTOP
195
+ - 可以确认任意位置的卡片
196
+
197
+ ---
198
+
199
+ ## 9. MSG_UPDATE_CARD (7) - 更新单张卡片信息
200
+
201
+ **字段**: `controller`, `location`, `sequence`, `card: CardQuery`
202
+
203
+ **逻辑**: 隐藏盖放卡片的详细信息
204
+ ```typescript
205
+ opponentView(): this {
206
+ const copy = this.copy();
207
+ // 如果卡片是盖放的,清除查询数据(只保留 flags = QUERY_CODE,code = 0)
208
+ if (copy.card?.position && (copy.card.position & POS_FACEDOWN)) {
209
+ const clearedCard = new CardQuery();
210
+ clearedCard.flags = QUERY_CODE;
211
+ clearedCard.code = 0;
212
+ clearedCard.empty = false;
213
+ copy.card = clearedCard;
214
+ }
215
+ return copy;
216
+ }
217
+
218
+ teammateView(): this {
219
+ // TAG 决斗中,队友的视角规则:
220
+ // - 场上卡片 (LOCATION_ONFIELD):队友可以看到己方盖放的卡片
221
+ // - 其他位置:和对手视角相同
222
+ if (this.location & LOCATION_ONFIELD) {
223
+ return this.copy();
224
+ } else {
225
+ return this.opponentView();
226
+ }
227
+ }
228
+
229
+ playerView(playerId: number): this {
230
+ // 特殊实现:使用 controller 字段判断
231
+ if (this.controller === playerId) {
232
+ return this.copy();
233
+ }
234
+ return this.opponentView();
235
+ }
236
+ ```
237
+
238
+ **说明**:
239
+ - 根据卡片的 `position` 字段判断是否盖放(POS_FACEDOWN)
240
+ - 盖放的卡片只保留最基本的信息(flags 和 code = 0)
241
+ - **队友视角**: 场上盖放可见,非场上盖放隐藏
242
+ - **特殊**: 需要重写 playerView,因为字段名是 `controller` 不是 `player`
243
+
244
+ ---
245
+
246
+ ## 10. MSG_UPDATE_DATA (6) - 更新区域所有卡片信息
247
+
248
+ **字段**: `player`, `location`, `cards: CardQuery[]`
249
+
250
+ **逻辑**: 隐藏盖放卡片的详细信息
251
+ ```typescript
252
+ opponentView(): this {
253
+ const copy = this.copy();
254
+ if (copy.cards) {
255
+ copy.cards = copy.cards.map((card) => {
256
+ if (card.position && (card.position & POS_FACEDOWN)) {
257
+ // 盖放的卡片,清除所有查询数据
258
+ const clearedCard = new CardQuery();
259
+ clearedCard.flags = 0;
260
+ clearedCard.empty = true;
261
+ return clearedCard;
262
+ }
263
+ return card;
264
+ });
265
+ }
266
+ return copy;
267
+ }
268
+
269
+ teammateView(): this {
270
+ // TAG 决斗中,队友的视角规则:
271
+ // - MZONE/SZONE:队友可以看到己方盖放的卡片
272
+ // - HAND:队友也看不到非公开的手牌
273
+ // - 其他公开区域:队友可以看到
274
+
275
+ if (this.location === LOCATION_MZONE || this.location === LOCATION_SZONE) {
276
+ return this.copy(); // 场上盖放可见
277
+ } else if (this.location === LOCATION_HAND) {
278
+ // 手牌:只有公开的才能看到
279
+ const copy = this.copy();
280
+ if (copy.cards) {
281
+ copy.cards = copy.cards.map((card) => {
282
+ if (!card.position || !(card.position & POS_FACEUP)) {
283
+ const clearedCard = new CardQuery();
284
+ clearedCard.flags = 0;
285
+ clearedCard.empty = true;
286
+ return clearedCard;
287
+ }
288
+ return card;
289
+ });
290
+ }
291
+ return copy;
292
+ } else {
293
+ return this.copy(); // 其他区域可见
294
+ }
295
+ }
296
+ ```
297
+
298
+ **说明**:
299
+ - 对手视角:所有盖放的卡片都清除为空数据
300
+ - **队友视角(复杂)**:
301
+ - MZONE/SZONE(场上):可以看到盖放的卡片
302
+ - HAND(手牌):只能看到公开的手牌
303
+ - 其他区域(墓地、除外等):通常都能看到
304
+
305
+ ---
306
+
307
+ ## 隐藏逻辑分类
308
+
309
+ ### 1. 完全隐藏(显示为 0)
310
+ - MSG_SHUFFLE_HAND - 所有手牌
311
+ - MSG_TAG_SWAP - 所有手牌
312
+
313
+ ### 2. 条件隐藏(0x80000000 标志位)
314
+ - MSG_DRAW - 未公开的抽卡
315
+ - MSG_DECK_TOP - 未公开的卡组顶部
316
+ - MSG_SHUFFLE_EXTRA - 未公开的额外卡组
317
+ - MSG_TAG_SWAP - 未公开的额外卡组
318
+ - MSG_CONFIRM_DECKTOP - 未公开的卡片代码
319
+ - MSG_CONFIRM_EXTRATOP - 未公开的卡片代码
320
+ - MSG_CONFIRM_CARDS - 未公开的卡片代码
321
+
322
+ ### 3. 位置状态隐藏(POS_FACEDOWN)
323
+ - MSG_UPDATE_CARD - 盖放的卡片
324
+ - MSG_UPDATE_DATA - 盖放的卡片
325
+
326
+ ---
327
+
328
+ ## TAG 决斗队友视角特殊规则
329
+
330
+ ### 完全隐藏(队友也看不到)
331
+ - MSG_TAG_SWAP - 手牌和未公开额外卡组
332
+
333
+ ### 条件可见(根据位置和状态)
334
+ - MSG_UPDATE_CARD:
335
+ - ✅ 场上盖放卡片可见
336
+ - ❌ 非场上盖放卡片隐藏
337
+
338
+ - MSG_UPDATE_DATA:
339
+ - ✅ MZONE/SZONE 盖放卡片可见
340
+ - ❌ HAND 非公开手牌隐藏
341
+ - ✅ GRAVE/REMOVED 等区域可见
342
+
343
+ ---
344
+
345
+ ## playerView 特殊实现
346
+
347
+ ### 基类默认实现
348
+ 检查 `this['player']` 字段,匹配则返回完整数据,否则返回 opponentView()
349
+
350
+ ### 需要重写的 MSG
351
+ - **MSG_UPDATE_CARD**: 字段名是 `controller` 而非 `player`,需要重写判断逻辑
352
+
353
+ ---
354
+
355
+ ## 公开标志位说明
356
+
357
+ ### 0x80000000 - 公开标志
358
+ - 设置:卡片对所有人可见(包括对手)
359
+ - 未设置:卡片仅对控制者可见
360
+
361
+ ### POS_FACEDOWN (位置标志)
362
+ - POS_FACEDOWN = 10 (0x0A)
363
+ - POS_FACEDOWN_ATTACK = 2
364
+ - POS_FACEDOWN_DEFENSE = 8
365
+ - 用于判断卡片是否盖放
366
+
367
+ ### POS_FACEUP (位置标志)
368
+ - POS_FACEUP = 5
369
+ - POS_FACEUP_ATTACK = 1
370
+ - POS_FACEUP_DEFENSE = 4
371
+ - 用于判断卡片是否表侧
372
+
373
+ ---
374
+
375
+ ## 总结
376
+
377
+ 共有 **10 个 MSG 类**实现了 opponentView:
378
+
379
+ 1. **简单隐藏类**(4 个): DRAW, DECK_TOP, SHUFFLE_HAND, SHUFFLE_EXTRA
380
+ 2. **确认类**(3 个): CONFIRM_DECKTOP, CONFIRM_EXTRATOP, CONFIRM_CARDS
381
+ 3. **TAG 决斗类**(1 个): TAG_SWAP
382
+ 4. **查询数据类**(2 个): UPDATE_CARD, UPDATE_DATA
383
+
384
+ 其中,**UPDATE_CARD** 和 **UPDATE_DATA** 的实现最为复杂,包含:
385
+ - opponentView: 隐藏盖放卡片
386
+ - teammateView: 根据位置区分队友可见性
387
+ - playerView: 根据控制者/玩家 ID 判断