CustomIWMServer/customiwmserver/data_types.py

287 lines
8 KiB
Python
Raw Normal View History

2022-11-18 16:51:24 +00:00
from pydantic import BaseModel
from typing import List, Optional, Union
class User(BaseModel):
"""Pydantic model for user data.
Created from the user response (`/api/v1/user/x`),
some values might be unused."""
Admin: bool = True
Banned: bool = False
BulletSpr: int = 0
CapeColor: int = 0
Costume: int = 0
Country: int = 0
CreatedAt: str = "2020-02-14T10:03:40Z"
DeathEffect: int = 0
DeletedAt: Optional[str] = None
FacialExpression: int = 0
Followed: bool = False
FollowerColor: int = 0
FollowerSpr: int = 0
GunSpr: int = 0
HairColor: int = 0
HairSpr: int = 0
HatColor: int = 0
HatColorInv: int = 0
HatSpr: int = 0
ID: int = 0
NumMapsClear: int = 0
NumMapsCreated: int = 0
NumSpeedrunRecords: int = 0
PantsColor: int = 0
RecordEndurance0: int = 0
RecordEndurance1: int = 0
RecordEndurance2: int = 0
RecordEndurance3: int = 0
RecordExplorer: int = 0
RecordHardcore: int = 0
RecordRoulette: int = 0
RecordScribble0: int = 0
RecordScribble1: int = 0
RecordScribble2: int = 0
RecordScribble3: int = 0
SaveEffect: int = 0
ShirtColor: int = 0
ShoesColor: int = 0
SkinColor: int = 0
SwordSpr: int = 0
TextSnd: int = 0
Unlocks: str = ""
UpdatedAt: str = "2020-03-26T05:22:32Z"
Username: str = "magmaus3"
Email: str = "user@example.com"
class Notification(BaseModel):
"""Pydantic model for Notifications
Available notification types:
- 0: <user> took your record on <map> with time <time>
- NotifData seems to need following variables:
- `MapID`: `int`
- `MapName`: `str`, displayed map name
- `ByUserID`: `int`, who took the record
- `ByUserName`: `str`, who took the record (displayed name)
- `NewTime`: `int`, Convertable to seconds using the following code:
`seconds = ((NewTime % 60000) / 100) * 2`
2022-11-18 16:51:24 +00:00
- 1: Your time on <map> was removed
- Reason IDs:
- 0: no reason
- 1: empty reason (?)
- 2: Autofire/macros/scripting
- 3: Replay was broken
- Other reason IDs return the following message: `Unrecognized reason: <reason>`
- Other than `Reason`, NotifData requires following variables as well:
- MapID
- MapName
- 2: Your level <level> was removed
- Reason IDs:
- 0: no reason
- 1: empty reason (?)
- 2: Inappropriate name or description
- 3: Submitted using autofire/macros/scripting
- 4: Inappropriate content
- 5: Unreasonably long forced waiting
- 6: Intentionally lagging the game
- Like with type 1, other reason IDs show the "unrecognized reason" message
- Other than `Reason`, NotifData requires following variables as well:
- MapID
- MapName
- 3: You were temporarily banned.
- Reason IDs:
- 0: no reason
- 1: empty reason (?)
- 2: Inappropriate level name or description
- 3: Inappropriate user name
- 4: Inappropriate playlist name
- 5: Autofire/macros/scripting
- 6: Inappropriate level content
- 7: Level having unreasonably long forced waiting
- 8: Level intentionally lagging the game
- 9: Exploiting the game
- Like with types 1 and 2, other reason IDs return the "unrecognized reason" message
- 4: Message from an administrator:
- NotifData requires the following variables:
- Message: str
All other types are displayed as an empty notification, without any special handling.
Note: NotifData must be returned to the game as a string,
otherwise the game crashes (as of `Early Access Ver 0.786`)
"""
CreatedAt: str = "2008-01-18T00:00:00Z"
UpdatedAt: str = "2008-01-18T00:00:00Z"
DeletedAt: Optional[str] = None
ForUserID: int = 0
ID: int = 0
IsRead: bool = False
MapID: int = 0 # Might be optional for some notification types
# NotifData also accepts str for compatibility with the game (see docstring)
NotifData: Union[str, dict] = {
"MapID": 215884,
"MapName": "speedrun_tower.map",
"ByUserID": 1,
"ByUserName": "user",
"NewTime": 1172,
"Reason": 2,
}
Type: int = 0
2022-11-19 12:51:28 +00:00
2022-11-18 16:51:24 +00:00
class Map(BaseModel):
"""Pydantic model for maps.
It looks like a lot of variables are also included in the user
data.
"""
2022-11-19 12:51:28 +00:00
2022-11-18 16:51:24 +00:00
ID: int = 0
CreatorId: int = 0
# CreatorName might be also retrieved from the user data
# using the CreatorId
CreatorName: str = ""
Name: str = "Interesting level"
Description: str = ""
Version: int = 90
CreatedAt: str = "2022-06-18T15:10:02Z"
DeletedAt: Union[str, None] = None
MapCode: str = "AAABBAAA"
Listed: bool = True
HiddenInChallenges: bool = False
DragonCoins: bool = False
# Might be duplicates from the User data
2022-11-19 12:51:28 +00:00
2022-11-18 16:51:24 +00:00
ShoesColor: int = 0
PantsColor: int = 0
ShirtColor: int = 10897172
CapeColor: int = 0
SkinColor: int = 0
HairColor: int = 0
HatSpr: int = 1
Country: int = 143
HairSpr: int = 0
HatColor: int = 0
HatColorInv: int = 0
FacialExpression: int = 0
DeathEffect: int = 0
GunSpr: int = 0
BulletSpr: int = 0
SwordSpr: int = 0
Costume: int = 0
FollowerSpr: int = 0
FollowerColor: int = 0
SaveEffect: int = 0
TextSnd: int = 0
AverageUserDifficulty: float = 0
ComputedDifficulty: float = 0
# Variables below might be used when sorted
# by rating
AverageRating: float = 0
NumRatings: int = 0
NumThumbsUp: int = 0
NumThumbsDown: int = 0
TagIDs: str = ""
TagNames: str = ""
TagFreqs: str = ""
PlayCount: int = 0
ClearCount: int = 0
2022-11-19 12:51:28 +00:00
2022-11-18 16:51:24 +00:00
# I'm not sure how ClearRate is handled
2022-11-19 12:51:28 +00:00
# in the official server, but I assume it's
2022-11-18 16:51:24 +00:00
# calculated as ClearCount / PlayCount.
ClearRate: float = 0.0
FavoriteCount: int = 0
DeathCount: int = 0
PlayerCount: int = 0
BestTimeUserID: int = 0
BestTimeUsername: str = ""
BestTimePlaytime: int = 0
MyBestPlaytime: int = 0
FirstClearUserID: Union[int, None] = 0
# Propably not needed, because you can simply read the
# FirstClearUserID, and get the name from there
# It's still useful for requests though.
2022-11-19 12:51:28 +00:00
FirstClearUsername: Union[str, None] = "uwu"
2022-11-18 16:51:24 +00:00
MapData: str = ""
2022-11-19 12:51:28 +00:00
MapReplay: str = (
"" # Might be also stored in DB as a dict of user IDs and the replays
)
2022-11-18 16:51:24 +00:00
Played: bool = False
Clear: bool = False
FullClear: bool = False
# Leaderboard scores
Leaderboard: list = []
class MapLeaderboard(BaseModel):
"""Pydantic model for Map record leaderboards."""
2022-11-19 12:51:28 +00:00
2022-11-18 16:51:24 +00:00
BestPlaytime: int
BestPlaytimeTime: str
BestReplay: str
CreatorName: str
UserID: int
ShoesColor: int = 0
PantsColor: int = 0
ShirtColor: int = 10897172
CapeColor: int = 0
SkinColor: int = 0
HairColor: int = 0
HatSpr: int = 1
Country: int = 143
HairSpr: int = 0
HatColor: int = 0
HatColorInv: int = 0
FacialExpression: int = 0
DeathEffect: int = 0
GunSpr: int = 0
BulletSpr: int = 0
SwordSpr: int = 0
Costume: int = 0
FollowerSpr: int = 0
FollowerColor: int = 0
SaveEffect: int = 0
TextSnd: int = 0
2022-11-19 12:51:28 +00:00
2022-11-18 16:51:24 +00:00
ids_to_names = {
0: "Adventure/Variety",
6: "Gimmick",
7: "Trap/Troll",
3: "Joke/Meme",
2: "Needle",
5: "Puzzle",
1: "Boss/Avoidance",
9: "Art",
8: "Music",
4: "Auto",
}
2022-11-19 12:51:28 +00:00
2022-11-18 16:51:24 +00:00
def convertTagsToNames(tags):
"""Converts tag IDs to names"""
global ids_to_names
tagNames = []
2022-11-19 12:51:28 +00:00
for i in tags.split(","):
if i.isdecimal():
tagNames.append(ids_to_names[int(i)])
2022-11-18 16:51:24 +00:00
return tagNames