mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-25 15:09:26 -07:00
168 lines
6.8 KiB
Python
168 lines
6.8 KiB
Python
"""Regenerate and audit levelup-rewards.json from the 2023 catalogue.
|
|
|
|
The server enforces two things over a level-up box: the deny-list in
|
|
Server/Utils/LevelUpRewardPool.cs, which can never be overridden, and the allow-list in
|
|
levelup-rewards.json, which is the reviewed set of items a box may contain. This script rebuilds
|
|
that allow-list and prints what it kept and what it refused, so a change to the catalogue or the
|
|
deny-list can be reviewed as a diff.
|
|
|
|
The patterns below mirror LevelUpRewardPool.DeniedPatterns and DeniedTags and MUST be kept in step
|
|
with them. The server's copy is the source of truth - the allow-list is already filtered by it at
|
|
pick time, so a pattern missing here only means a candidate that the server would still refuse;
|
|
it can never mean an item the server would allow. Run this from anywhere with the repo checked out:
|
|
|
|
python Server/RadicadeServer-Config/generate-levelup-rewards.py
|
|
|
|
Then read the audit, delete anything from the JSON that should not be there, and remember that an
|
|
item with no name, tooltip or tag to judge it by cannot be classified here at all.
|
|
"""
|
|
import json
|
|
import os
|
|
import re
|
|
|
|
# The script sits beside the files it reads, so it works from any working directory.
|
|
CONFIG = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
DENIED = [
|
|
"exclusive", "early access", "alpha", "art festival",
|
|
"rec con", "reccon", "rrcc", "raw data", "sfvrcc",
|
|
"contest", "trophy", "competition",
|
|
"moderator", "volunteer",
|
|
"video partner", "creator program", "partnered creator", "partner",
|
|
"bug bounty", "security", "ethical hackers", "gold notes",
|
|
"seller swag", "sponsored league",
|
|
"rro-", "rro specific",
|
|
"promo", "promotional", "sponsor", "collab", "licensed", "prom",
|
|
"mrbeast", "mr beast", "miraculous", "nba",
|
|
"class of", "graduation", "class)", "creator conference",
|
|
"for earning", "available until", "unlocked by visiting",
|
|
"unlocked during", "xbox", "launch reward", "launch exclusive",
|
|
"reward for", "given to", "space marine", "space visor",
|
|
"(gold)",
|
|
"limited", "never return", "founder", "founders",
|
|
"halloween", "holiday", "thanksgiving", "invasion", "elseware",
|
|
"new year", "carnivale", "reclympics", "rec rocks", "anniversary", "2020 glasses",
|
|
"developer", "dev only", "staff only", "admin only", "test item", "debug",
|
|
]
|
|
DENIED_TAGS = {"halloween", "holidays", "thanksgiving", "invasion", "elseware", "reccon", "reccon2021"}
|
|
|
|
|
|
def denied_name(text):
|
|
if not text:
|
|
return None
|
|
low = text.lower()
|
|
for p in DENIED:
|
|
if p in low:
|
|
return p
|
|
return None
|
|
|
|
|
|
def denied(item):
|
|
for field in ("FriendlyName", "Tooltip"):
|
|
hit = denied_name(item.get(field) or "")
|
|
if hit:
|
|
return field + ":" + hit
|
|
tags = (item.get("TagList") or "").lower()
|
|
for tag in re.split(r"[,\s]+", tags):
|
|
if tag.strip() in DENIED_TAGS:
|
|
return "tag:" + tag.strip()
|
|
return None
|
|
|
|
|
|
def main():
|
|
catalog = json.load(open(CONFIG + r"\2022-avatar.json", encoding="utf-8"))
|
|
resolvable = set(
|
|
d.strip().lower()
|
|
for d in json.load(open(CONFIG + r"\avatar-item-lookup.json", encoding="utf-8"))["descriptions"]
|
|
)
|
|
|
|
kept, refused = [], {}
|
|
for item in catalog:
|
|
desc = (item.get("AvatarItemDesc") or "").strip()
|
|
if not desc or item.get("IsBaseAvatarItem"):
|
|
continue
|
|
rarity = item.get("Rarity", 0)
|
|
if rarity not in (10, 20, 30, 50):
|
|
refused.setdefault("rarity", []).append(item.get("FriendlyName"))
|
|
continue
|
|
if desc.lower() not in resolvable:
|
|
refused.setdefault("unresolvable", []).append(item.get("FriendlyName"))
|
|
continue
|
|
why = denied(item)
|
|
if why:
|
|
refused.setdefault(why.split(":")[0], []).append(item.get("FriendlyName"))
|
|
continue
|
|
kept.append((rarity, item.get("FriendlyName") or "", desc))
|
|
|
|
kept.sort(key=lambda row: (row[0], row[1].lower()))
|
|
per_tier = {}
|
|
for rarity, _, _ in kept:
|
|
per_tier[rarity] = per_tier.get(rarity, 0) + 1
|
|
|
|
# ---- consumables: the shipped global list minus the deny-list, the premium and the seasonal
|
|
consumables = json.load(open(CONFIG + r"\consumables.json", encoding="utf-8"))
|
|
# Event, survey, licensed and paid-category consumables that no name pattern can identify.
|
|
extra_denied = [
|
|
"hair dye", "coupon", "snowman", "sparkler",
|
|
"dracula", "goblin king", "ghost beard", "witch film",
|
|
"surve", "survey", "forbidden", "forsaken", "premium", "creator bubbly",
|
|
]
|
|
consumable_kept, consumable_refused = [], {}
|
|
for item in consumables:
|
|
name = item.get("FriendlyName") or ""
|
|
why = denied_name(name)
|
|
if not why:
|
|
for pattern in extra_denied:
|
|
if pattern in name.lower():
|
|
why = pattern
|
|
break
|
|
if why:
|
|
consumable_refused.setdefault(why, []).append(name)
|
|
else:
|
|
consumable_kept.append((name, item["ConsumableItemDesc"]))
|
|
|
|
out = {
|
|
"AvatarItems": [desc for _, _, desc in kept],
|
|
"Consumables": [desc for _, desc in consumable_kept],
|
|
}
|
|
path = CONFIG + r"\levelup-rewards.json"
|
|
with open(path, "w", encoding="utf-8", newline="\r\n") as fh:
|
|
json.dump(out, fh, indent=2)
|
|
fh.write("\n")
|
|
|
|
print("wrote", path)
|
|
print("avatar allowed:", len(kept), "per rarity:", per_tier)
|
|
print("consumables allowed:", len(consumable_kept))
|
|
print()
|
|
print("== refused avatar items by reason ==")
|
|
for reason, names in sorted(refused.items(), key=lambda kv: -len(kv[1])):
|
|
print(f"{reason:20} {len(names):5} e.g. {names[:4]}")
|
|
print()
|
|
print("== refused consumables ==")
|
|
for reason, names in sorted(consumable_refused.items(), key=lambda kv: -len(kv[1])):
|
|
print(f"{reason:20} {len(names):5} {names[:6]}")
|
|
print()
|
|
print("== kept consumables ==")
|
|
for name, _ in consumable_kept:
|
|
print(" ", name)
|
|
print()
|
|
print("== sample of kept avatar items (first 2 per tier) ==")
|
|
seen = {}
|
|
for rarity, name, _ in kept:
|
|
if seen.get(rarity, 0) >= 2:
|
|
continue
|
|
seen[rarity] = seen.get(rarity, 0) + 1
|
|
print(f" {rarity}: {name}")
|
|
print(" ... a further", len(kept) - sum(seen.values()), "omitted")
|
|
print()
|
|
print("== denied check: items the brief names explicitly ==")
|
|
for probe in ["White Hat", "Winged Headphones", "Rec Con Hoodie", "Space Visor", "Royal Cape",
|
|
"Top Hat (Gold)", "Hallow's Blazer", "Prom", "MrBeast", "Early Access",
|
|
"Alpha Team", "Notes Headphones"]:
|
|
hits = [(i.get("FriendlyName"), denied(i)) for i in catalog
|
|
if probe.lower() in (i.get("FriendlyName") or "").lower()]
|
|
print(f"{probe!r}: " + (", ".join(f"{n}->{w}" for n, w in hits) if hits else "no match"))
|
|
|
|
|
|
main()
|