Add entitlements

This commit is contained in:
fatsbrown
2024-09-11 18:12:35 -03:00
committed by GitHub
parent 235d090bf1
commit 364423f0fa
6 changed files with 602 additions and 9 deletions
+4
View File
@@ -377,6 +377,10 @@ To enable support for multiple users perform the steps below:
To enable all-time leaderboards (override 60 minutes live results and 90 days personal records), create a file ``all_time_leaderboards.txt`` in the ``storage`` directory.
### Entitlements
To unlock entitlements (special equipment), create a file ``unlock_entitlements.txt`` in the ``storage`` directory.
## Community Discord server and Strava club
Please join the community supported [Discord](https://discord.gg/GMdn8F8) server and [Strava](https://www.strava.com/clubs/zoffline) club.
+558
View File
@@ -0,0 +1,558 @@
[
{
"id": 1687,
"name": "ENTITLEMENT_CYCLING_HEADGEAR_ONBOARDINGHELMET"
},
{
"id": 1688,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_BACKPEDAL2023"
},
{
"id": 1689,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_EZR2023"
},
{
"id": 1690,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_NOVEMBERFONDO2023"
},
{
"id": 1691,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_DECEMBERFONDO2023"
},
{
"id": 1692,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_TEAMCASTELLI2023"
},
{
"id": 1693,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_ABUSSYNERGYMEN2023"
},
{
"id": 1694,
"name": "ENTITLEMENT_PAINTJOB_ZWIFTACADEMY2023"
},
{
"id": 1695,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_EINTRACHTFRANKFURT2023"
},
{
"id": 1696,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_ZIRT2023"
},
{
"id": 1697,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_BL13LADIES2023"
},
{
"id": 1698,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_ABUSSYNERGYLADIES2023"
},
{
"id": 1699,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_PRIMORRWBESPORTS2023"
},
{
"id": 1700,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_TWENTY242024"
},
{
"id": 1701,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_5W4T2023"
},
{
"id": 1702,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_BASEPERFORMANCE2023"
},
{
"id": 1703,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_WLBB2023"
},
{
"id": 1704,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_CHASINGRACING2023"
},
{
"id": 1705,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_TOYOTAELITE2023"
},
{
"id": 1706,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_ZTBR2023"
},
{
"id": 1707,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_PAINCAVEHEROES2023"
},
{
"id": 1708,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_SUNRISERACING2023"
},
{
"id": 1709,
"name": "ENTITLEMENT_RUNNING_OUTFIT_TOURDEZWIFT2024"
},
{
"id": 1710,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_JANUARYFONDO2023"
},
{
"id": 1711,
"name": "ENTITLEMENT_RUNNING_SHORTS_INNOVATIONRUNNING2023"
},
{
"id": 1712,
"name": "ENTITLEMENT_RUNNING_SHORTS_FILMMYRUN2023"
},
{
"id": 1713,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_COALITIONALPHAMEN2023"
},
{
"id": 1714,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_COALITIONALPHAWMN2023"
},
{
"id": 1715,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_METIER2023"
},
{
"id": 1716,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_AMANI2023"
},
{
"id": 1717,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_HPLCYCLING2023"
},
{
"id": 1718,
"name": "ENTITLEMENT_RUNNING_OUTFIT_ZLDR2023"
},
{
"id": 1719,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_RAPHA5002023"
},
{
"id": 1720,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_DODDIEAID2024"
},
{
"id": 1721,
"name": "ENTITLEMENT_RUNNING_SHIRT_TUGAZRUN2023"
},
{
"id": 1722,
"name": "ENTITLEMENT_CYCLING_JERSEY_COMPANIES_LETAPE2024"
},
{
"id": 1723,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_USAC_CHAMP2024"
},
{
"id": 1724,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_CYCLINGCANADA_CHAMP2024"
},
{
"id": 1725,
"name": "ENTITLEMENT_CYCLING_JERSEY_DCF_CHAMPS2024"
},
{
"id": 1726,
"name": "ENTITLEMENT_CYCLING_JERSEY_FFC_CHAMPS2024"
},
{
"id": 1727,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_FDJSUEZ2024"
},
{
"id": 1728,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_MOVISTAR2024"
},
{
"id": 1729,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_INEOS2024"
},
{
"id": 1730,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_CANYONSRAMRACING2024"
},
{
"id": 1731,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_PROJECTECHELON2024"
},
{
"id": 1732,
"name": "ENTITLEMENT_SOCKS_SOCKS_ZWIFTGAMES2024"
},
{
"id": 1733,
"name": "ENTITLEMENT_CYCLING_GLOVES_ZWIFTGAMES2024"
},
{
"id": 1734,
"name": "ENTITLEMENT_CYCLING_HEADGEAR_CYCLINGCAPZWIFTGAMESGOLDCAP2024"
},
{
"id": 1735,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_ZWIFTGAMESKIT2024"
},
{
"id": 1736,
"name": "ENTITLEMENT_CYCLING_SHOES_ADIDASTEMPOBOA2024L"
},
{
"id": 1737,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_TOUROFMARCH2024"
},
{
"id": 1738,
"name": "ENTITLEMENT_CYCLING_HEADGEAR_BIGSPIN2024"
},
{
"id": 1739,
"name": "ENTITLEMENT_WHEELS_ZWIFTBIGSPIN2024"
},
{
"id": 1740,
"name": "ENTITLEMENT_CYCLING_HEADGEAR_HEADPHONESBIGSPIN2024"
},
{
"id": 1741,
"name": "ENTITLEMENT_CYCLING_SHOES_BIGSPIN2024L"
},
{
"id": 1742,
"name": "ENTITLEMENT_SOCKS_SOCKS_BIGSPIN"
},
{
"id": 1743,
"name": "ENTITLEMENT_CYCLING_HEADGEAR_BUCKETHAT_BIGSPINUNIONFLAG2024"
},
{
"id": 1744,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_SUNFLOWERKIT2024"
},
{
"id": 1745,
"name": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_BIGSPIN2024MAKURIKIT"
},
{
"id": 1746,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_TOMUNDERGROUNDMAP2024"
},
{
"id": 1747,
"name": "ENTITLEMENT_GLASSES_BIGSPINGLASSES2024"
},
{
"id": 1748,
"name": "ENTITLEMENT_RUNNING_HEADGEAR_BACKWARDSBASEBALLCAP2024"
},
{
"id": 1749,
"name": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_BASEBALLKIT2024"
},
{
"id": 1750,
"name": "ENTITLEMENT_BIKE_ZWIFTCONCEPTGOLD"
},
{
"id": 1751,
"name": "ENTITLEMENT_RUNNING_HEADGEAR_CYCLINGCAP_BIGSPINBERET2024"
},
{
"id": 1752,
"name": "ENTITLEMENT_BIKE_ZWIFTBIGSPINCRUISER2024"
},
{
"id": 1753,
"name": "ENTITLEMENT_GLASSES_OAKLEYSPHAERA"
},
{
"id": 1754,
"name": "ENTITLEMENT_CYCLING_HEADGEAR_CYCLINGCAPSPRINGTRAININGHAT2024"
},
{
"id": 1755,
"name": "ENTITLEMENT_GLASSES_SPRINGTRAININGSUNGLASSES2024"
},
{
"id": 1756,
"name": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_SPRINGTRAINING2024"
},
{
"id": 1757,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_SCFCHAMP2024"
},
{
"id": 1758,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_AUSCYCLINGCHAMP2024"
},
{
"id": 1759,
"name": "ENTITLEMENT_SOCKS_SOCKS_CONFETTITRAILS"
},
{
"id": 1760,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_SLT2024BLUE"
},
{
"id": 1761,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_SLT2024GREEN"
},
{
"id": 1762,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_SLT2024GREY"
},
{
"id": 1763,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_SLT2024ORANGE"
},
{
"id": 1764,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_SLT2024PALEBLUE"
},
{
"id": 1765,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_SLT2024PALEGREEN"
},
{
"id": 1766,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_SLT2024PALEORANGE"
},
{
"id": 1767,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_SLT2024PINK"
},
{
"id": 1768,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_SLT2024PURPLE"
},
{
"id": 1769,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_SLT2024RED"
},
{
"id": 1770,
"name": "ENTITLEMENT_RUNNING_SHIRT_SLT2024BLUE"
},
{
"id": 1771,
"name": "ENTITLEMENT_RUNNING_SHIRT_SLT2024GREEN"
},
{
"id": 1772,
"name": "ENTITLEMENT_RUNNING_SHIRT_SLT2024GREY"
},
{
"id": 1773,
"name": "ENTITLEMENT_RUNNING_SHIRT_SLT2024ORANGE"
},
{
"id": 1774,
"name": "ENTITLEMENT_RUNNING_SHIRT_SLT2024PALEBLUE"
},
{
"id": 1775,
"name": "ENTITLEMENT_RUNNING_SHIRT_SLT2024PALEGREEN"
},
{
"id": 1776,
"name": "ENTITLEMENT_RUNNING_SHIRT_SLT2024PALEORANGE"
},
{
"id": 1777,
"name": "ENTITLEMENT_RUNNING_SHIRT_SLT2024PINK"
},
{
"id": 1778,
"name": "ENTITLEMENT_RUNNING_SHIRT_SLT2024PURPLE"
},
{
"id": 1779,
"name": "ENTITLEMENT_RUNNING_SHIRT_SLT2024RED"
},
{
"id": 1780,
"name": "ENTITLEMENT_RUNNING_SHORTS_SLT2024"
},
{
"id": 1781,
"name": "ENTITLEMENT_BIKE_PINARELLODOGMAX2024"
},
{
"id": 1782,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_RIDELIKEKING2024"
},
{
"id": 1783,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_ALPECINDECEUNINCK2024"
},
{
"id": 1784,
"name": "ENTITLEMENT_GLASSES_OAKLEYSUTROGLASSES"
},
{
"id": 1785,
"name": "ENTITLEMENT_GLASSES_OAKLEYENCODERGLASSES"
},
{
"id": 1786,
"name": "ENTITLEMENT_BIKE_PINARELLOESPADA"
},
{
"id": 1787,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_PRIDEON2024"
},
{
"id": 1788,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_TDF2024"
},
{
"id": 1789,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_ROYALAIRFORCE2024"
},
{
"id": 1790,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_LEVELVELO2024"
},
{
"id": 1791,
"name": "ENTITLEMENT_PAINTJOB_ZWIFTRIDE2024"
},
{
"id": 1792,
"name": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_ZWIFTACADEMY2024"
},
{
"id": 1793,
"name": "ENTITLEMENT_RUNNING_OUTFIT_WAHOO_RUN2024"
},
{
"id": 1794,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_TDFFAZ2024"
},
{
"id": 1795,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_ATTACUSCYCLESQUAD2024"
},
{
"id": 1796,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_LGBTQZWIFTERS2024"
},
{
"id": 1797,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_ZWIFTNL2024"
},
{
"id": 1798,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_RELENTLESS2024"
},
{
"id": 1799,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_FRENCHYFUZION2024"
},
{
"id": 1800,
"name": "ENTITLEMENT_RUNNING_OUTFIT_HISP2024"
},
{
"id": 1801,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_NVDMCOACHING2024"
},
{
"id": 1802,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_LIVALULA2024"
},
{
"id": 1803,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_ABSOLUTEMOTION2024"
},
{
"id": 1804,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_FENIXDECEUNINCK2024"
},
{
"id": 1805,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_HPH2024"
},
{
"id": 1806,
"name": "ENTITLEMENT_CYCLING_JERSEY_COMPANIES_GCN2024"
},
{
"id": 1807,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_BIKEALICIOUS2024"
},
{
"id": 1808,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_INTERMARCHEWANTY2024"
},
{
"id": 1809,
"name": "ENTITLEMENT_BIKE_CANYONAEROAD2024"
},
{
"id": 1810,
"name": "ENTITLEMENT_PAINTJOB_CANYONAEROADALPECIN2024"
},
{
"id": 1811,
"name": "ENTITLEMENT_PAINTJOB_CANYONAEROADZA2024"
},
{
"id": 1812,
"name": "ENTITLEMENT_PAINTJOB_CANYONAEROADSRAM2024"
},
{
"id": 1813,
"name": "ENTITLEMENT_CYCLING_JERSEY_CLUBS_ROCACORBACOLLECTIVE2024"
},
{
"id": 1814,
"name": "ENTITLEMENT_CYCLING_JERSEY_PRO_TEAMS_FREDDYOVETT2024"
},
{
"id": 1815,
"name": "ENTITLEMENT_RUNNING_HEADGEAR_RUNNINGCAPTOUROFWATOPIA2024"
},
{
"id": 1816,
"name": "ENTITLEMENT_CYCLING_HEADGEAR_RUNNINGCAPTOUROFWATOPIA2024"
},
{
"id": 1817,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_ZWIFTWORLDSERIESELITE2024"
},
{
"id": 1818,
"name": "ENTITLEMENT_CYCLING_JERSEY_ZWIFTWORLDSERIESCOMMUNITY2024"
},
{
"id": 1819,
"name": "ENTITLEMENT_RUNNING_SHOES_RUNNINGSHOES_TOUROFWATOPIA2024"
},
{
"id": 1820,
"name": "ENTITLEMENT_CYCLING_SHOES_CYCLINGSHOES_TOUROFWATOPIA2024L"
},
{
"id": 1821,
"name": "ENTITLEMENT_RUNNING_OUTFIT_TOUROFWATOPIA2024"
},
{
"id": 1822,
"name": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_TOUROFWATOPIA2024"
},
{
"id": 1823,
"name": "ENTITLEMENT_SOCKS_SOCKS_TOUROFWATOPIA2024"
},
{
"id": 1824,
"name": "ENTITLEMENT_BIKE_PINARELLODOGMAF2024"
},
{
"id": 1825,
"name": "ENTITLEMENT_PAINTJOB_PINARELLODOGMAFZWIFT2024"
}
]
+1 -1
View File
@@ -211,7 +211,7 @@ message ProfileEntitlement {
USE = 4;
}
optional int64 f2 = 2; // always -1 when "RIDE"; increasing small value when "USE" (437, 438, 911, ..., 1229)
optional int64 id = 2; // always -1 when "RIDE"; increasing small value when "USE" (437, 438, 911, ..., 1229)
optional ProfileEntitlementStatus status = 3;
enum ProfileEntitlementStatus {
File diff suppressed because one or more lines are too long
+21
View File
@@ -0,0 +1,21 @@
import os
import xml.etree.ElementTree as ET
import json
import subprocess
data = []
try:
if not os.path.isdir('global'):
os.makedirs('global')
except IOError as e:
print("failed to create dir 'global': %s" % str(e))
os.chdir('global')
subprocess.run(['wad_unpack.exe', 'C:\\Program Files (x86)\\Zwift\\assets\\global.wad'])
tree = ET.parse('Entitlements.xml')
root = tree.getroot()
for entitlement in root.iter('Entitlement'):
data.append({'id': int(entitlement.get('id')), 'name': entitlement.get('name')})
with open('../../data/entitlements.txt', 'w') as f:
json.dump(data, f, indent=2)
+17 -7
View File
@@ -1752,13 +1752,23 @@ def do_api_profiles(profile_id, is_json):
else:
with open(profile_file, 'rb') as fd:
profile.ParseFromString(fd.read())
profile.id = profile_id
if not profile.email:
profile.email = 'user@email.com'
if profile.entitlements:
del profile.entitlements[:]
if not profile.mix_panel_distinct_id:
profile.mix_panel_distinct_id = str(uuid.uuid4())
profile.id = profile_id
if not profile.email:
profile.email = 'user@email.com'
for entitlement in list(profile.entitlements):
if entitlement.type == profile_pb2.ProfileEntitlement.EntitlementType.RIDE:
profile.entitlements.remove(entitlement)
if os.path.isfile('%s/unlock_entitlements.txt' % STORAGE_DIR):
with open('%s/data/entitlements.txt' % SCRIPT_DIR) as f:
entitlements = json.load(f)
for entitlement in entitlements:
if not any(e.id == entitlement['id'] for e in profile.entitlements):
e = profile.entitlements.add()
e.type = profile_pb2.ProfileEntitlement.EntitlementType.USE
e.id = entitlement['id']
e.status = profile_pb2.ProfileEntitlement.ProfileEntitlementStatus.ACTIVE
if not profile.mix_panel_distinct_id:
profile.mix_panel_distinct_id = str(uuid.uuid4())
if is_json: #todo: publicId, bodyType, totalRunCalories != total_watt_hours, totalRunTimeInMinutes != time_ridden_in_minutes etc
if profile.dob != "":
profile.age = age(datetime.datetime.strptime(profile.dob, "%m/%d/%Y"))