Skip to content

Commit

Permalink
Fix missing names for Franz and Solobattle local games.
Browse files Browse the repository at this point in the history
  • Loading branch information
vladfi1 committed Jan 20, 2025
1 parent 598b331 commit 73871a4
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 12 deletions.
9 changes: 5 additions & 4 deletions slippi_ai/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ class PlayerMeta(NamedTuple):
name: str

@classmethod
def from_metadata(cls, player_meta: dict) -> 'PlayerMeta':
def from_metadata(cls, player_meta: dict, raw: str) -> 'PlayerMeta':
return cls(
character=player_meta['character'],
name=nametags.name_from_metadata(player_meta))
name=nametags.name_from_metadata(player_meta, raw=raw))

class ReplayMeta(NamedTuple):
p0: PlayerMeta
Expand All @@ -39,9 +39,10 @@ class ReplayMeta(NamedTuple):

@classmethod
def from_metadata(cls, metadata: dict) -> 'ReplayMeta':
raw = metadata['raw']
return cls(
p0=PlayerMeta.from_metadata(metadata['players'][0]),
p1=PlayerMeta.from_metadata(metadata['players'][1]),
p0=PlayerMeta.from_metadata(metadata['players'][0], raw),
p1=PlayerMeta.from_metadata(metadata['players'][1], raw),
stage=metadata['stage'],
slp_md5=metadata['slp_md5'])

Expand Down
52 changes: 44 additions & 8 deletions slippi_ai/nametags.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,50 @@
"""Track known player nametags and connect codes."""

from typing import Optional

import melee

DEFAULT_NAME = 'Master Player'
NAME_UNKNOWN = ''

def get_player(raw: str) -> Optional[str]:
"""The convention for personal dumps is Players/NAME/..."""
if raw.startswith('Players/'):
return raw.split('/')[1]
return None

# Some player dumps have a lot of local games with no name or code.
# For such players, we assume any game with that player's main is them.
PLAYER_MAINS = {
('Solobattle', melee.Character.JIGGLYPUFF),
('Franz', melee.Character.DOC),
}

def name_from_metadata(player_meta: dict) -> str:
def name_from_metadata(player_meta: dict, raw: Optional[str] = None) -> str:
netplay = player_meta['netplay']

if netplay is not None:
# Player dumps will have netplay codes, while the ranked-anonymized dumps
# have an empty code and the name set to "Platinum/Diamond/Master Player".
if netplay['code']:
# Internally, connect codes use the Shift-JIS hash sign.
return netplay['code'].replace('#', '#')

if netplay['name']:
return netplay['name']

if raw:
player_name = get_player(raw)
if player_name:
char = melee.Character(player_meta['character'])
if (player_name, char) in PLAYER_MAINS:
return player_name

# Offline games (e.g. tournaments)
if netplay is None:
if player_meta['name_tag']:
return player_meta['name_tag']

# Player dumps will have netplay codes, while the ranked-anonymized dumps
# have an empty code and the name set to "Platinum/Diamond/Master Player".
if netplay['code']:
# Internally, connect codes use the Shift-JIS hash sign.
return netplay['code'].replace('#', '#')
return netplay['name']
return NAME_UNKNOWN

# TODO: we could scrape code -> ELO from the slippi website?

Expand All @@ -35,6 +65,9 @@ def name_from_metadata(player_meta: dict) -> str:
('SFAT', 'SFAT#9', 'OHMA#175', 'SFAT#99', 'SFAT#783'),
('Solobattle', '666#666', 'SOLO#735'), # TODO: many Solobattle games have no name
('Frenzy', 'FRNZ#141'),
('Gosu', 'WIZZ#310'),
# Most Franz games are local with no name; for those we assume any Doctor Mario is Franz.
('Franz', 'XELA#158', 'PLATO#0'),
]

name_map = {}
Expand Down Expand Up @@ -65,3 +98,6 @@ def encode_name(name: str) -> int:

def is_banned_name(name: str) -> bool:
return normalize_name(name) in BANNED_NAMES

for name, _ in PLAYER_MAINS:
assert name in name_map.values(), name

0 comments on commit 73871a4

Please sign in to comment.