File size: 6,995 Bytes
044a37e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
"""Parser-free PyTorch tensor boundary for canonical Melee policy batches.

The nested records mirror ``slippi_ai.types`` at the repository-pinned
slippi-ai revision.  Every leaf is a :class:`torch.Tensor`; this module does
not import libmelee, Peppi, slippi-ai, or the earlier replay repository.

Component records use a shared leading shape ``S``.  ``S`` is normally
``[B, T]`` for training and full-sequence inference, and may be ``[B]`` for a
single cached inference step.  The one exception is :class:`ItemsBatch`,
whose leaves have shape ``[*S, 15]`` for upstream slots ``item_0`` through
``item_14``.

The earlier E000 representation is not sufficient to construct this boundary
without enrichment.  Preprocessing must retain the processed controller
button mask (not only ``buttons_physical``), follower/Nana state, item slots,
Randall and FoD inputs, and the configured player-name code.  It must also
resolve missing values into the exact slippi-ai categorical sentinels before
creating these tensors.  Replay parsing and enrichment belong upstream, not in
the model repository.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Final

import torch

MAX_ITEMS: Final[int] = 15
"""Number of ordered item slots in the pinned slippi-ai ``Items`` schema."""

BUTTON_ORDER: Final[tuple[str, ...]] = ("A", "B", "X", "Y", "Z", "L", "R", "D_UP")
"""Exact upstream controller-button field order."""


@dataclass(frozen=True, slots=True)
class ButtonsBatch:
    """Named digital controller inputs; every leaf is ``bool [*S]``.

    These values must be derived with the pinned slippi-ai controller
    semantics from the processed Slippi button mask.  E000's physical button
    bitset alone is not a lossless substitute.
    """

    A: torch.Tensor
    B: torch.Tensor
    X: torch.Tensor
    Y: torch.Tensor
    Z: torch.Tensor
    L: torch.Tensor
    R: torch.Tensor
    D_UP: torch.Tensor


@dataclass(frozen=True, slots=True)
class StickBatch:
    """One analog stick with ``float32 [*S]`` x and y axes."""

    x: torch.Tensor
    y: torch.Tensor


@dataclass(frozen=True, slots=True)
class ControllerBatch:
    """Raw slippi-ai controller representation over leading shape ``S``.

    ``main_stick`` and ``c_stick`` use the upstream logical coordinate range.
    ``shoulder`` is the shared logical shoulder value used by slippi-ai, with
    shape ``[*S]`` and floating dtype.  The custom_v1 codec consumes this raw
    structure and owns all bucketing and decoding.
    """

    main_stick: StickBatch
    c_stick: StickBatch
    shoulder: torch.Tensor
    buttons: ButtonsBatch


@dataclass(frozen=True, slots=True)
class NanaBatch:
    """Ice Climbers follower state, matching upstream field order.

    All leaves have shape ``[*S]``.  Boolean fields use ``torch.bool``;
    categorical/count fields use an integer dtype; positions and shield use a
    floating dtype.  When Nana is absent, ``exists`` is false and all other
    leaves still contain the exact upstream missing/default representation.
    """

    exists: torch.Tensor
    percent: torch.Tensor
    facing: torch.Tensor
    x: torch.Tensor
    y: torch.Tensor
    action: torch.Tensor
    invulnerable: torch.Tensor
    character: torch.Tensor
    jumps_left: torch.Tensor
    shield_strength: torch.Tensor
    on_ground: torch.Tensor


@dataclass(frozen=True, slots=True)
class PlayerBatch:
    """One player slot, matching pinned ``slippi_ai.types.Player``.

    Scalar leaves have shape ``[*S]``.  ``controller`` is retained for exact
    game-schema parity even though the policy's controlled previous/current
    action is supplied separately as :attr:`PolicyBatch.controller_t`.
    """

    percent: torch.Tensor
    facing: torch.Tensor
    x: torch.Tensor
    y: torch.Tensor
    action: torch.Tensor
    invulnerable: torch.Tensor
    character: torch.Tensor
    jumps_left: torch.Tensor
    shield_strength: torch.Tensor
    on_ground: torch.Tensor
    controller: ControllerBatch
    nana: NanaBatch


@dataclass(frozen=True, slots=True)
class RandallBatch:
    """Yoshi's Story Randall position, ``float32 [*S]`` per coordinate."""

    x: torch.Tensor
    y: torch.Tensor


@dataclass(frozen=True, slots=True)
class FoDPlatformsBatch:
    """Fountain of Dreams platform heights, ``float32 [*S]``."""

    left: torch.Tensor
    right: torch.Tensor


@dataclass(frozen=True, slots=True)
class ItemsBatch:
    """The 15 ordered upstream item slots in a stacked tensor layout.

    Each leaf has shape ``[*S, MAX_ITEMS]``.  The final dimension maps directly
    to ``item_0`` through ``item_14``.  ``exists`` uses ``torch.bool``;
    ``type`` and ``state`` use integer dtypes; x and y use floating dtypes.
    Values in unused slots must match the upstream defaults and are ignored
    when ``exists`` is false.
    """

    exists: torch.Tensor
    type: torch.Tensor
    state: torch.Tensor
    x: torch.Tensor
    y: torch.Tensor


@dataclass(frozen=True, slots=True)
class GameStateBatch:
    """Full slippi-ai game state over leading shape ``S``.

    Perspective preprocessing makes ``p0`` the controlled/self player and
    ``p1`` the opponent.  ``stage`` is an integer categorical tensor with
    shape ``[*S]``.  The remaining fields preserve the pinned upstream nesting.
    """

    p0: PlayerBatch
    p1: PlayerBatch
    stage: torch.Tensor
    randall: RandallBatch
    fod_platforms: FoDPlatformsBatch
    items: ItemsBatch


@dataclass(frozen=True, slots=True)
class PolicyBatch:
    """Aligned behavior-cloning batch consumed by the policy and its loss.

    Every temporal leaf has batch-major shape ``[B, T, ...]``.

    ``game_state_t`` and ``controller_t`` are inputs at frame ``t``.
    ``controller_t_plus_1`` is already aligned by preprocessing and is the
    target for that same tensor position.  Model code must not shift it again.

    ``reset_mask[b, t]`` means a new replay segment begins before position t.
    ``padding_mask[b, t]`` is true for a real, attention-valid frame.
    ``valid_position_mask[b, t]`` is true only when the aligned next-frame
    controller target is valid for loss.  It must be false at replay ends,
    across raw-frame gaps, and wherever required source or target fields are
    missing.  All three masks use ``torch.bool [B, T]``.

    ``player_name`` is the optional upstream categorical name code with shape
    ``[B, T]``.  It may be ``None`` when player-name conditioning is disabled.
    """

    game_state_t: GameStateBatch
    controller_t: ControllerBatch
    controller_t_plus_1: ControllerBatch
    reset_mask: torch.Tensor
    padding_mask: torch.Tensor
    valid_position_mask: torch.Tensor
    player_name: torch.Tensor | None = None


__all__ = [
    "BUTTON_ORDER",
    "MAX_ITEMS",
    "ButtonsBatch",
    "ControllerBatch",
    "FoDPlatformsBatch",
    "GameStateBatch",
    "ItemsBatch",
    "NanaBatch",
    "PlayerBatch",
    "PolicyBatch",
    "RandallBatch",
    "StickBatch",
]