mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-27 07:59:03 -07:00
Radicade Public Code
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user