trucks and addons
This commit is contained in:
parent
1780362b90
commit
fe6e55a891
64
constants.py
Normal file
64
constants.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
COUNTRYS = {}
|
||||||
|
|
||||||
|
DLC_NAMES = {
|
||||||
|
None: "Base Game",
|
||||||
|
"dlc_1_1": "Season 1: Search & Recover<br>Kola Peninsula, Russia",
|
||||||
|
"dlc_1_2": "Clasico Pack",
|
||||||
|
"dlc_2_1": "Season 2: Explore & Expand<br>Yukon, Canada",
|
||||||
|
"dlc_2_2": "Season 2: Explore & Expand",
|
||||||
|
"dlc_3": "Season 3: Locate & Deliver<br>Wisconsin, USA",
|
||||||
|
"DLC_trial_6": "GMC Brigadier",
|
||||||
|
"dlc_4": "Season 4: New Frontiers<br>Amur, Russia",
|
||||||
|
"dlc_4_1": "Anniversary DLC",
|
||||||
|
"dlc_5": "Season 5: Build & Dispatch<br>Don, Russia",
|
||||||
|
"dlc_6": "Season 6: Haul & Hustle<br>Maine, USA",
|
||||||
|
"dlc_7": "Season 7: Compete & Conquer<br>Tennessee, USA",
|
||||||
|
"dlc_8": "Season 8: Grand Harvest<br>Belozersk Glades, Central Asia",
|
||||||
|
"dlc_9": "Season 9: Renew & Rebuild<br>Ontario, Canada",
|
||||||
|
"dlc_10": "Season 10: Fix & Connect<br>British Columbia, Canada",
|
||||||
|
"dlc_11": "Season 11: Light & Cameras<br>Scandinavia, Northern Europe",
|
||||||
|
"dlc_12": "Season 12: Public Energy<br>North Carolina, USA",
|
||||||
|
"dlc_12_5": "The Atom",
|
||||||
|
"dlc_13": "Season 13: Dig & Drill<br>Almaty Region, Central Asia",
|
||||||
|
"dlc_13_5": "Rezvani Tank",
|
||||||
|
"dlc_14": "Season 14: Reap & Sow<br>Austria, Central Europe",
|
||||||
|
"dlc_14_1": "Kenworth Dual Pack",
|
||||||
|
"dlc_14_2": "Mack Dual Pack",
|
||||||
|
"dlc_15": "Season 15: Oil & Dirt<br>Quebec, Canada",
|
||||||
|
"dlc_15_5": "Freightliner & Western Star Dual Pack",
|
||||||
|
"dlc_16": "Season 16: High Voltage<br>Washington, USA",
|
||||||
|
"dlc_16_5": "Dragon Wagons Dual Pack",
|
||||||
|
"dlc_17": "Season 17: Repair & Rescue<br>Zurdania, Western Asia",
|
||||||
|
"dlc_17_5": "Mercedes-Benz Trucks Dual Pack 1",
|
||||||
|
"dlc_18": "Season 18: Patch & Power<br>Chiapas, Mexico",
|
||||||
|
"dlc_navistar": "Navistart 5000-MV Tractor",
|
||||||
|
"dlc_high_roller": "High Roller Pack",
|
||||||
|
"dlc_ws_49x": "Western Star 49X",
|
||||||
|
"dlc_tatra": "TATRA Dual Pack",
|
||||||
|
"dlc_jeep": "Jeep Dual Pack",
|
||||||
|
"dlc_crocodile": "Crocodile Pack",
|
||||||
|
"dlc_land_rover": "Land Rover Dual Pack",
|
||||||
|
"dlc_ws_wolf": "Western Star Wolf Pack",
|
||||||
|
"dlc_rezvani": "Rezvani Hercules",
|
||||||
|
"dlc_mastodon": "The Mastodon",
|
||||||
|
"dlc_w990": "Kenworth W990",
|
||||||
|
}
|
||||||
|
|
||||||
|
DLC_OVERRIDES = {
|
||||||
|
"UI_VEHICLE_NAVISTAR_5000_NAME": "dlc_navistar",
|
||||||
|
"UI_VEHICLE_KHAN_39_MARSHALL_NAME": "dlc_high_roller",
|
||||||
|
"UI_VEHICLE_WESTERN_STAR_49X_NAME": "dlc_ws_49x",
|
||||||
|
"UI_VEHICLE_TATRA_805_NAME": "dlc_tatra",
|
||||||
|
"UI_VEHICLE_TATRA_T813_NAME": "dlc_tatra",
|
||||||
|
"UI_VEHICLE_JEEP_CJ7_RENEGADE_NAME": "dlc_jeep",
|
||||||
|
"UI_VEHICLE_JEEP_WRANGLER_NAME": "dlc_jeep",
|
||||||
|
"UI_VEHICLE_STEP_3364_CROCODILE_NAME": "dlc_crocodile",
|
||||||
|
"UI_VEHICLE_LAND_ROVER_DEFENDER_110_NAME": "dlc_land_rover",
|
||||||
|
"UI_VEHICLE_LAND_ROVER_DEFENDER_90_NAME": "dlc_land_rover",
|
||||||
|
"UI_VEHICLE_WESTERN_STAR_57X_NAME": "dlc_ws_wolf",
|
||||||
|
"UI_VEHICLE_WESTERN_STAR_NF1424_NAME": "dlc_ws_wolf",
|
||||||
|
"UI_VEHICLE_WESTERN_STAR_NF1430_NAME": "dlc_ws_wolf",
|
||||||
|
"UI_VEHICLE_REZVANI_NAME": "dlc_rezvani",
|
||||||
|
"UI_VEHICLE_ZIKZ_612H_MASTODONT_NAME": "dlc_mastodon",
|
||||||
|
"UI_VEHICLE_KENWORTH_W990_NAME": "dlc_w990",
|
||||||
|
}
|
||||||
399
loader.py
399
loader.py
@ -1,4 +1,5 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
from constants import DLC_OVERRIDES
|
||||||
from decimal import Decimal, ROUND_HALF_UP
|
from decimal import Decimal, ROUND_HALF_UP
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from html import parser as html_parser
|
from html import parser as html_parser
|
||||||
@ -58,6 +59,37 @@ locatestarttagend_tolerant = re.compile(
|
|||||||
endtagfind = re.compile(r"</\s*([a-zA-Z_][-.a-zA-Z0-9:_]*)\s*>")
|
endtagfind = re.compile(r"</\s*([a-zA-Z_][-.a-zA-Z0-9:_]*)\s*>")
|
||||||
|
|
||||||
|
|
||||||
|
class TruckInfo(str, Enum):
|
||||||
|
ALWAYS = "UI_TRUCK_INFO_ALWAYS"
|
||||||
|
CAPABLE = "UI_TRUCK_INFO_CAPABLE"
|
||||||
|
NOT_AVAILABLE = "UI_TRUCK_INFO_NA"
|
||||||
|
SWITCHABLE = "UI_TRUCK_INFO_ON_OFF"
|
||||||
|
|
||||||
|
|
||||||
|
class TruckAddonCategory(str, Enum):
|
||||||
|
ALL_WHEEL_DRIVE = "awd"
|
||||||
|
BUBBLE_HEAD = "bubble_head"
|
||||||
|
BUMPER = "bumper"
|
||||||
|
CURTAIN = "curtain"
|
||||||
|
DIFF_LOCK = "diff_lock"
|
||||||
|
EXHAUST = "exhaust"
|
||||||
|
FRAME_ADDON = "frame_addons"
|
||||||
|
FENDERS = "fenders"
|
||||||
|
FENDER_FRONT = "fender_front"
|
||||||
|
FENDER_REAR = "fender_rear"
|
||||||
|
GRILL = "grill"
|
||||||
|
HOOD_ORNAMENT = "hood_ornament"
|
||||||
|
MIRROR_MOUNT = "mirror_mount"
|
||||||
|
MISCELLANEOUS = "miscellenious"
|
||||||
|
REAR = "rear"
|
||||||
|
SNORKEL = "snorkel"
|
||||||
|
STICKER = "sticker"
|
||||||
|
STICKER_EXTERIOR = "sticker_exterior"
|
||||||
|
STICKER_WINDSHIELD = "sticker_windshield"
|
||||||
|
TOP = "top"
|
||||||
|
WHEEL_ADDON = "wheel_addon"
|
||||||
|
|
||||||
|
|
||||||
def get_initial_pak_path():
|
def get_initial_pak_path():
|
||||||
return os.path.join(
|
return os.path.join(
|
||||||
str(os.path.expanduser("~")),
|
str(os.path.expanduser("~")),
|
||||||
@ -157,11 +189,12 @@ class SnowrunnerClass:
|
|||||||
self.pak = pak_loader
|
self.pak = pak_loader
|
||||||
self.UiDesc = ""
|
self.UiDesc = ""
|
||||||
self.UiName = ""
|
self.UiName = ""
|
||||||
self.Price = -1
|
self.Price = 0
|
||||||
self.UnlockByExploration = False
|
self.UnlockByExploration = False
|
||||||
self.UnlockByObjective = False
|
self.UnlockByObjective = False
|
||||||
self.UnlockByRank = -1
|
self.UnlockByRank = -1
|
||||||
self.GameData = None
|
self.GameData = None
|
||||||
|
self.DLC = None
|
||||||
|
|
||||||
def load_desc(self, data: SnowRunnerXNLNode):
|
def load_desc(self, data: SnowRunnerXNLNode):
|
||||||
if "region:default" in data.children:
|
if "region:default" in data.children:
|
||||||
@ -174,7 +207,10 @@ class SnowrunnerClass:
|
|||||||
self.UiName = data.get_attr("uiname")
|
self.UiName = data.get_attr("uiname")
|
||||||
|
|
||||||
def load_game_data(self, data: SnowRunnerXNLNode):
|
def load_game_data(self, data: SnowRunnerXNLNode):
|
||||||
self.GameData = self.pak.load_class(SnowrunnerGameObjectType.GAME_DATA, data)
|
if self.GameData is None:
|
||||||
|
self.GameData = self.pak.load_class(SnowrunnerGameObjectType.GAME_DATA, data, dlc_name=self.DLC)
|
||||||
|
else:
|
||||||
|
self.GameData.update_data(data)
|
||||||
self.Price = self.GameData.Price
|
self.Price = self.GameData.Price
|
||||||
self.UnlockByExploration = self.GameData.UnlockByExploration
|
self.UnlockByExploration = self.GameData.UnlockByExploration
|
||||||
self.UnlockByObjective = self.GameData.UnlockByObjective
|
self.UnlockByObjective = self.GameData.UnlockByObjective
|
||||||
@ -201,7 +237,11 @@ class SnowrunnerClass:
|
|||||||
self.__children_handled.add(name.lower())
|
self.__children_handled.add(name.lower())
|
||||||
|
|
||||||
def load_child(
|
def load_child(
|
||||||
self, data: SnowRunnerXNLNode, name: str, object_type_override: SnowrunnerGameObjectType | None = None
|
self,
|
||||||
|
data: SnowRunnerXNLNode,
|
||||||
|
name: str,
|
||||||
|
object_type_override: SnowrunnerGameObjectType | None = None,
|
||||||
|
always_as_list: bool = False,
|
||||||
):
|
):
|
||||||
self.__children_handled.add(name.lower())
|
self.__children_handled.add(name.lower())
|
||||||
|
|
||||||
@ -216,11 +256,22 @@ class SnowrunnerClass:
|
|||||||
self.load_game_data(data.children[name.lower()])
|
self.load_game_data(data.children[name.lower()])
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if always_as_list and not isinstance(data.children[name.lower()], list):
|
||||||
|
data.children[name.lower()] = [data.children[name.lower()]]
|
||||||
|
|
||||||
object_type = SnowrunnerGameObjectType(name.lower()) if object_type_override is None else object_type_override
|
object_type = SnowrunnerGameObjectType(name.lower()) if object_type_override is None else object_type_override
|
||||||
if isinstance(data.children[name.lower()], list):
|
if isinstance(data.children[name.lower()], list):
|
||||||
setattr(self, name, [self.pak.load_class(object_type, x) for x in data.children[name.lower()]])
|
setattr(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
[self.pak.load_class(object_type, x, dlc_name=self.DLC) for x in data.children[name.lower()]],
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
setattr(self, name, self.pak.load_class(object_type, data.children[name.lower()]))
|
setattr(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
self.pak.load_class(object_type, data.children[name.lower()], dlc_name=self.DLC),
|
||||||
|
)
|
||||||
|
|
||||||
def loading_finished(self, data: SnowRunnerXNLNode):
|
def loading_finished(self, data: SnowRunnerXNLNode):
|
||||||
attr_set = set(data.attrs.keys())
|
attr_set = set(data.attrs.keys())
|
||||||
@ -239,6 +290,9 @@ class SnowrunnerClass:
|
|||||||
)
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
if self.UiName in DLC_OVERRIDES:
|
||||||
|
self.DLC = DLC_OVERRIDES[self.UiName]
|
||||||
|
|
||||||
def get_translated_ui_desc(self, language: LanguageLoader) -> str:
|
def get_translated_ui_desc(self, language: LanguageLoader) -> str:
|
||||||
if self.UiDesc in language:
|
if self.UiDesc in language:
|
||||||
return language[self.UiDesc]
|
return language[self.UiDesc]
|
||||||
@ -305,22 +359,30 @@ class AddonSlots(SnowrunnerClass):
|
|||||||
super().__init__(pak_loader=pak_loader)
|
super().__init__(pak_loader=pak_loader)
|
||||||
self.InitialOffset = "(0;0;0)"
|
self.InitialOffset = "(0;0;0)"
|
||||||
self.Quantity = 0
|
self.Quantity = 0
|
||||||
|
self.UseTrailerFrame = False
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_attr(data, "InitialOffset")
|
self.load_attr(data, "InitialOffset")
|
||||||
self.load_attr(data, "Quantity")
|
self.load_attr(data, "Quantity")
|
||||||
|
self.load_attr(data, "UseTrailerFrame")
|
||||||
|
self.ignore_attr("OffsetStep")
|
||||||
|
self.ignore_attr("ParentFrames")
|
||||||
self.loading_finished(data)
|
self.loading_finished(data)
|
||||||
|
|
||||||
|
|
||||||
class AddonSockets(SnowrunnerClass):
|
class AddonSockets(SnowrunnerClass):
|
||||||
def __init__(self, pak_loader: InitialPakLoader):
|
def __init__(self, pak_loader: InitialPakLoader):
|
||||||
super().__init__(pak_loader=pak_loader)
|
super().__init__(pak_loader=pak_loader)
|
||||||
self.DefaultAddon = ""
|
self.DefaultAddon = None
|
||||||
self.Socket = None
|
self.Socket = None
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_attr(data, "DefaultAddon")
|
if "defaultaddon" in data.attrs:
|
||||||
self.load_child(data, "Socket")
|
self.DefaultAddon = self.pak.get_object(
|
||||||
|
object_type=SnowrunnerGameObjectType.TRUCK_ADDON, name=data.attrs["defaultaddon"], lazy=True
|
||||||
|
)
|
||||||
|
self.ignore_attr("defaultaddon")
|
||||||
|
self.load_child(data, "Socket", always_as_list=True)
|
||||||
self.ignore_attr("ParentFrame")
|
self.ignore_attr("ParentFrame")
|
||||||
self.ignore_attr("RequiredAddonIfNoConflicts")
|
self.ignore_attr("RequiredAddonIfNoConflicts")
|
||||||
self.loading_finished(data)
|
self.loading_finished(data)
|
||||||
@ -364,6 +426,10 @@ class Body(SnowrunnerClass):
|
|||||||
self.ModelFrame = None
|
self.ModelFrame = None
|
||||||
self.Body = []
|
self.Body = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Weight(self) -> int:
|
||||||
|
return self.Mass + sum(x.Weight for x in self.Body)
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_attr(data, "AllowedPenetrationDepth")
|
self.load_attr(data, "AllowedPenetrationDepth")
|
||||||
self.load_attr(data, "NoSoftContacts")
|
self.load_attr(data, "NoSoftContacts")
|
||||||
@ -397,8 +463,7 @@ class Body(SnowrunnerClass):
|
|||||||
self.ignore_attr("ExplicitParentFrame")
|
self.ignore_attr("ExplicitParentFrame")
|
||||||
self.ignore_attr("NetSync")
|
self.ignore_attr("NetSync")
|
||||||
self.ignore_attr("ParentFrame")
|
self.ignore_attr("ParentFrame")
|
||||||
|
self.load_child(data, "Body", always_as_list=True)
|
||||||
self.load_child(data, "Body")
|
|
||||||
self.ignore_child("Constraint")
|
self.ignore_child("Constraint")
|
||||||
self.ignore_child("Motor")
|
self.ignore_child("Motor")
|
||||||
self.ignore_child("SideMirror")
|
self.ignore_child("SideMirror")
|
||||||
@ -489,18 +554,17 @@ class Engine(SnowrunnerClass):
|
|||||||
class EngineVariants(SnowrunnerClass):
|
class EngineVariants(SnowrunnerClass):
|
||||||
def __init__(self, pak_loader: InitialPakLoader):
|
def __init__(self, pak_loader: InitialPakLoader):
|
||||||
super().__init__(pak_loader=pak_loader)
|
super().__init__(pak_loader=pak_loader)
|
||||||
self.Engines = []
|
self.Engine = []
|
||||||
|
|
||||||
|
def get_engine(self, name: str) -> Engine | None:
|
||||||
|
for e in self.Engine:
|
||||||
|
if e.Name == name:
|
||||||
|
return e
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
if "engine" in data.children:
|
self.load_child(data, "Engine", always_as_list=True)
|
||||||
if isinstance(data.children["engine"], list):
|
|
||||||
self.Engines = [
|
|
||||||
self.pak.load_class(SnowrunnerGameObjectType.ENGINE, x) for x in data.children["engine"]
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
self.Engines = [self.pak.load_class(SnowrunnerGameObjectType.ENGINE, data.children["engine"])]
|
|
||||||
self.ignore_child("Engine")
|
|
||||||
|
|
||||||
self.loading_finished(data)
|
self.loading_finished(data)
|
||||||
|
|
||||||
|
|
||||||
@ -523,10 +587,11 @@ class GameData(SnowrunnerClass):
|
|||||||
self.Country = ""
|
self.Country = ""
|
||||||
self.ExcludeAddons = ""
|
self.ExcludeAddons = ""
|
||||||
self.ExcludedCargoTypes = ""
|
self.ExcludedCargoTypes = ""
|
||||||
|
self.InstallSocket = None
|
||||||
self.IsCustomizable = False
|
self.IsCustomizable = False
|
||||||
self.IsDoubleTrailer = False
|
self.IsDoubleTrailer = False
|
||||||
self.IsQuest = False
|
self.IsQuest = False
|
||||||
self.Price = -1
|
self.Price = 0
|
||||||
self.UnlockByRank = -1
|
self.UnlockByRank = -1
|
||||||
self.UnlockByExploration = False
|
self.UnlockByExploration = False
|
||||||
self.UnlockByObjective = False
|
self.UnlockByObjective = False
|
||||||
@ -544,7 +609,9 @@ class GameData(SnowrunnerClass):
|
|||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_attr(data, "CameraPreset")
|
self.load_attr(data, "CameraPreset")
|
||||||
self.load_attr(data, "Category")
|
if "category" in data.attrs:
|
||||||
|
self.Category = TruckAddonCategory(data.attrs["category"])
|
||||||
|
self.ignore_attr("Category")
|
||||||
self.load_attr(data, "Country")
|
self.load_attr(data, "Country")
|
||||||
self.load_attr(data, "ExcludeAddons")
|
self.load_attr(data, "ExcludeAddons")
|
||||||
self.load_attr(data, "ExcludedCargoTypes")
|
self.load_attr(data, "ExcludedCargoTypes")
|
||||||
@ -577,8 +644,12 @@ class GameData(SnowrunnerClass):
|
|||||||
self.ignore_attr("ResetTruckAfterGateway")
|
self.ignore_attr("ResetTruckAfterGateway")
|
||||||
|
|
||||||
self.children = data.children
|
self.children = data.children
|
||||||
self.load_child(data, "AddonSockets")
|
self.load_child(data, "AddonSockets", always_as_list=True)
|
||||||
self.load_child(data, "UiDesc")
|
self.load_child(data, "UiDesc")
|
||||||
|
if "installsocket" in data.children:
|
||||||
|
self.InstallSocket = data.children["installsocket"].attrs.get("type", self.InstallSocket)
|
||||||
|
self.ignore_child("InstallSocket")
|
||||||
|
|
||||||
self.ignore_child("AddonSlots")
|
self.ignore_child("AddonSlots")
|
||||||
self.ignore_child("AddonType")
|
self.ignore_child("AddonType")
|
||||||
self.ignore_child("CenteringAngularVelocity")
|
self.ignore_child("CenteringAngularVelocity")
|
||||||
@ -586,7 +657,6 @@ class GameData(SnowrunnerClass):
|
|||||||
self.ignore_child("CustomizationCameras")
|
self.ignore_child("CustomizationCameras")
|
||||||
self.ignore_child("GearboxParams")
|
self.ignore_child("GearboxParams")
|
||||||
self.ignore_child("InstallSlot")
|
self.ignore_child("InstallSlot")
|
||||||
self.ignore_child("InstallSocket")
|
|
||||||
self.ignore_child("LoadArea")
|
self.ignore_child("LoadArea")
|
||||||
self.ignore_child("LongLogsAlignTarget")
|
self.ignore_child("LongLogsAlignTarget")
|
||||||
self.ignore_child("RequiredAddon")
|
self.ignore_child("RequiredAddon")
|
||||||
@ -617,6 +687,9 @@ class GameData(SnowrunnerClass):
|
|||||||
self.ignore_child("longlogsaligndata")
|
self.ignore_child("longlogsaligndata")
|
||||||
self.loading_finished(data)
|
self.loading_finished(data)
|
||||||
|
|
||||||
|
def update_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
|
self.load_data(data)
|
||||||
|
|
||||||
|
|
||||||
class Gear(SnowrunnerClass):
|
class Gear(SnowrunnerClass):
|
||||||
def __init__(self, pak_loader: InitialPakLoader):
|
def __init__(self, pak_loader: InitialPakLoader):
|
||||||
@ -645,7 +718,7 @@ class Gearbox(SnowrunnerClass):
|
|||||||
self.GearboxParams = None
|
self.GearboxParams = None
|
||||||
self.ReverseGear = None
|
self.ReverseGear = None
|
||||||
self.HighGear = None
|
self.HighGear = None
|
||||||
self.Gears = []
|
self.Gear = []
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_attr(data, "AWDConsumptionModifier")
|
self.load_attr(data, "AWDConsumptionModifier")
|
||||||
@ -660,10 +733,12 @@ class Gearbox(SnowrunnerClass):
|
|||||||
self.load_child(data, "GameData")
|
self.load_child(data, "GameData")
|
||||||
if "gamedata" in data.children:
|
if "gamedata" in data.children:
|
||||||
self.load_child(data.children["gamedata"], "GearboxParams")
|
self.load_child(data.children["gamedata"], "GearboxParams")
|
||||||
self.load_child(data, "Gear")
|
self.load_child(data, "Gear", always_as_list=True)
|
||||||
self.load_child(data, "ReverseGear", object_type_override=SnowrunnerGameObjectType.GEAR)
|
self.load_child(data, "ReverseGear", object_type_override=SnowrunnerGameObjectType.GEAR)
|
||||||
self.load_child(data, "HighGear", object_type_override=SnowrunnerGameObjectType.GEAR)
|
self.load_child(data, "HighGear", object_type_override=SnowrunnerGameObjectType.GEAR)
|
||||||
|
|
||||||
|
self.Gear = list(sorted(self.Gear, key=lambda gear: gear.AngVel))
|
||||||
|
|
||||||
self.loading_finished(data)
|
self.loading_finished(data)
|
||||||
|
|
||||||
|
|
||||||
@ -690,8 +765,15 @@ class GearboxVariants(SnowrunnerClass):
|
|||||||
super().__init__(pak_loader=pak_loader)
|
super().__init__(pak_loader=pak_loader)
|
||||||
self.Gearbox = []
|
self.Gearbox = []
|
||||||
|
|
||||||
|
def get_gearbox(self, name: str) -> Gearbox | None:
|
||||||
|
for e in self.Gearbox:
|
||||||
|
if e.Name == name:
|
||||||
|
return e
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_child(data, "Gearbox")
|
self.load_child(data, "Gearbox", always_as_list=True)
|
||||||
self.loading_finished(data)
|
self.loading_finished(data)
|
||||||
|
|
||||||
def update_data(self, data: SnowRunnerXNLNode) -> None:
|
def update_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
@ -700,7 +782,7 @@ class GearboxVariants(SnowrunnerClass):
|
|||||||
|
|
||||||
for orig, upd in zip_longest(self.Gearbox, data.children["gearbox"]):
|
for orig, upd in zip_longest(self.Gearbox, data.children["gearbox"]):
|
||||||
if orig is None:
|
if orig is None:
|
||||||
self.Gearbox.append(self.pak.load_class(SnowrunnerGameObjectType.GEARBOX, upd))
|
self.Gearbox.append(self.pak.load_class(SnowrunnerGameObjectType.GEARBOX, upd, dlc_name=self.DLC))
|
||||||
elif upd is None:
|
elif upd is None:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
@ -766,6 +848,15 @@ class PhysicsModel(SnowrunnerClass):
|
|||||||
self.Mesh = ""
|
self.Mesh = ""
|
||||||
self.Body = None
|
self.Body = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Weight(self) -> int:
|
||||||
|
if not self.Body:
|
||||||
|
return 0
|
||||||
|
if isinstance(self.Body, list):
|
||||||
|
return sum(x.Weight for x in self.Body)
|
||||||
|
else:
|
||||||
|
return self.Body.Weight
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_attr(data, "_noinherit")
|
self.load_attr(data, "_noinherit")
|
||||||
self.load_attr(data, "Mesh")
|
self.load_attr(data, "Mesh")
|
||||||
@ -871,8 +962,15 @@ class SuspensionSetVariants(SnowrunnerClass):
|
|||||||
super().__init__(pak_loader=pak_loader)
|
super().__init__(pak_loader=pak_loader)
|
||||||
self.SuspensionSet = []
|
self.SuspensionSet = []
|
||||||
|
|
||||||
|
def get_suspension_set(self, name: str) -> SuspensionSet | None:
|
||||||
|
for e in self.SuspensionSet:
|
||||||
|
if e.Name == name:
|
||||||
|
return e
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_child(data, "SuspensionSet")
|
self.load_child(data, "SuspensionSet", always_as_list=True)
|
||||||
self.loading_finished(data)
|
self.loading_finished(data)
|
||||||
|
|
||||||
|
|
||||||
@ -891,6 +989,98 @@ class Truck(SnowrunnerClass):
|
|||||||
self.Type = "Truck"
|
self.Type = "Truck"
|
||||||
self.WaterMass = None
|
self.WaterMass = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def TireCount(self) -> int:
|
||||||
|
return len(self.TruckData.Wheels.Wheel)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def TireCountFront(self) -> int:
|
||||||
|
return len([x for x in self.TruckData.Wheels.Wheel if x.Location == "front"])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def TireCountRear(self) -> int:
|
||||||
|
return len([x for x in self.TruckData.Wheels.Wheel if x.Location == "rear"])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DriveTrain(self) -> str:
|
||||||
|
undriven_axles = len([x for x in self.TruckData.Wheels.Wheel if x.Torque == "none"])
|
||||||
|
return f"{self.TireCount}x{self.TireCount - undriven_axles}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Weight(self) -> int:
|
||||||
|
wheel_mass = (
|
||||||
|
self.TruckData.Wheels.DefaultTire.Mass * self.TireCountFront
|
||||||
|
+ self.TruckData.Wheels.DefaultTire.Mass
|
||||||
|
* self.TruckData.Wheels.DefaultTire.RearMassScale
|
||||||
|
* self.TireCountRear
|
||||||
|
)
|
||||||
|
default_addon_mass = sum(x.PhysicsModel.Weight for x in self.get_default_truck_addons())
|
||||||
|
|
||||||
|
return int(self.PhysicsModel.Weight + wheel_mass + default_addon_mass)
|
||||||
|
|
||||||
|
def get_shop_price(self) -> int:
|
||||||
|
return (
|
||||||
|
self.Price
|
||||||
|
+ self.TruckData.DefaultEngine.Price
|
||||||
|
+ self.TruckData.DefaultGearbox.Price
|
||||||
|
+ self.TruckData.DefaultSuspension.Price
|
||||||
|
+ self.TruckData.DefaultWinch.Price
|
||||||
|
+ self.TruckData.Wheels.DefaultTire.Price
|
||||||
|
+ sum(x.DefaultAddon.Price for x in self.GameData.AddonSockets if x.DefaultAddon is not None)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_addon_socket_names(self) -> list[str]:
|
||||||
|
return [s.Names for s in [y for x in self.GameData.AddonSockets for y in x.Socket]]
|
||||||
|
|
||||||
|
def get_available_truck_addons(self, category: TruckAddonCategory) -> list[TruckAddon]:
|
||||||
|
return [
|
||||||
|
ta
|
||||||
|
for ta in self.pak.get_object_list(SnowrunnerGameObjectType.TRUCK_ADDON)
|
||||||
|
if ta.GameData.InstallSocket in self.get_addon_socket_names() and ta.GameData.Category == category
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_default_truck_addons(self) -> list[TruckAddon]:
|
||||||
|
return [x.DefaultAddon for x in self.GameData.AddonSockets if x.DefaultAddon is not None]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def AWDInfo(self) -> TruckInfo:
|
||||||
|
torques = {x.Torque.lower() for x in self.TruckData.Wheels.Wheel}
|
||||||
|
if len(torques) == 1 and "default" in torques:
|
||||||
|
return TruckInfo.ALWAYS
|
||||||
|
elif "connectable" in torques:
|
||||||
|
return TruckInfo.CAPABLE
|
||||||
|
elif "full" in torques:
|
||||||
|
return TruckInfo.SWITCHABLE
|
||||||
|
elif "none" in torques:
|
||||||
|
return TruckInfo.NOT_AVAILABLE
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Truck {self.UiName} AWD Wheel Torques {torques} is not supported")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DiffLockInfo(self) -> TruckInfo:
|
||||||
|
if self.TruckData.DiffLockType == "Always":
|
||||||
|
return TruckInfo.ALWAYS
|
||||||
|
elif (
|
||||||
|
self.TruckData.DiffLockType == "Installed"
|
||||||
|
or self.TruckData.DiffLockType == "Switchable"
|
||||||
|
or self.TruckData.DiffLockType == "Connected"
|
||||||
|
or self.TruckData.DiffLockType == "Uninstalled"
|
||||||
|
or self.TruckData.DiffLockType == "None"
|
||||||
|
): # DiffLockType seems to have no meaning. At all. We have to figure it out ourselfs.
|
||||||
|
diff_lock_addons = self.get_available_truck_addons(TruckAddonCategory.DIFF_LOCK)
|
||||||
|
if len(diff_lock_addons) == 0:
|
||||||
|
return TruckInfo.NOT_AVAILABLE
|
||||||
|
elif len(diff_lock_addons) == 1:
|
||||||
|
return TruckInfo.SWITCHABLE
|
||||||
|
else:
|
||||||
|
installed_addon = list(set(diff_lock_addons) & set(self.get_default_truck_addons()))
|
||||||
|
if installed_addon[0].TruckData.DiffLockInstalled:
|
||||||
|
return TruckInfo.SWITCHABLE
|
||||||
|
else:
|
||||||
|
return TruckInfo.CAPABLE
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Truck {self.UiName} DiffLockType {self.TruckData.DiffLockType} is not supported")
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_attr(data, "AttachType")
|
self.load_attr(data, "AttachType")
|
||||||
self.load_attr(data, "IsDeprecated")
|
self.load_attr(data, "IsDeprecated")
|
||||||
@ -944,6 +1134,7 @@ class TruckAddon(SnowrunnerClass):
|
|||||||
self.PhysicsModel = None
|
self.PhysicsModel = None
|
||||||
self.TruckData = None
|
self.TruckData = None
|
||||||
self.AddonType = None
|
self.AddonType = None
|
||||||
|
self.AddonSlots = None
|
||||||
self.RequiredAddonType = None
|
self.RequiredAddonType = None
|
||||||
self.IsChassisFullOcclusion = False
|
self.IsChassisFullOcclusion = False
|
||||||
self.FuelMass = None
|
self.FuelMass = None
|
||||||
@ -966,7 +1157,7 @@ class TruckAddon(SnowrunnerClass):
|
|||||||
if "installsocket" in data.children["gamedata"].children:
|
if "installsocket" in data.children["gamedata"].children:
|
||||||
self.load_child(data.children["gamedata"], "InstallSocket")
|
self.load_child(data.children["gamedata"], "InstallSocket")
|
||||||
if "addonslots" in data.children["gamedata"].children:
|
if "addonslots" in data.children["gamedata"].children:
|
||||||
self.load_child(data.children["gamedata"], "AddonType")
|
self.load_child(data.children["gamedata"], "AddonSlots")
|
||||||
if "addontype" in data.children["gamedata"].children:
|
if "addontype" in data.children["gamedata"].children:
|
||||||
self.load_child(data.children["gamedata"], "AddonType")
|
self.load_child(data.children["gamedata"], "AddonType")
|
||||||
if "requiredaddon" in data.children["gamedata"].children:
|
if "requiredaddon" in data.children["gamedata"].children:
|
||||||
@ -1007,12 +1198,25 @@ class TruckAddon(SnowrunnerClass):
|
|||||||
|
|
||||||
|
|
||||||
class TruckData(SnowrunnerClass):
|
class TruckData(SnowrunnerClass):
|
||||||
|
truck_types = {
|
||||||
|
"HEAVY": "CODEX_TYPE_TRUCK_6_HEADER",
|
||||||
|
"HEAVY_DUTY": "CODEX_TYPE_TRUCK_4_HEADER",
|
||||||
|
"SCOUT": "CODEX_TYPE_TRUCK_3_HEADER",
|
||||||
|
"HIGHWAY": "CODEX_TYPE_TRUCK_2_HEADER",
|
||||||
|
"OFFROAD": "CODEX_TYPE_TRUCK_5_HEADER",
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, pak_loader: InitialPakLoader):
|
def __init__(self, pak_loader: InitialPakLoader):
|
||||||
super().__init__(pak_loader=pak_loader)
|
super().__init__(pak_loader=pak_loader)
|
||||||
self.AllWheelDriveInstalled = False
|
self.AllWheelDriveInstalled = False
|
||||||
self.BackSteerSpeed = 0.0
|
self.BackSteerSpeed = 0.0
|
||||||
self.CompatibleWheels = []
|
self.CompatibleWheels = []
|
||||||
self.Damage = None
|
self.Damage = None
|
||||||
|
self.DefaultEngine = None
|
||||||
|
self.DefaultGearbox = None
|
||||||
|
self.DefaultSuspension = None
|
||||||
|
self.DefaultTire = None
|
||||||
|
self.DefaultWinch = None
|
||||||
self.DiffLockInstalled = False
|
self.DiffLockInstalled = False
|
||||||
self.DiffLockType = ""
|
self.DiffLockType = ""
|
||||||
self.Engines = []
|
self.Engines = []
|
||||||
@ -1041,12 +1245,12 @@ class TruckData(SnowrunnerClass):
|
|||||||
self.load_attr(data, "Responsiveness")
|
self.load_attr(data, "Responsiveness")
|
||||||
self.load_attr(data, "SetHandbrakeOnWinchRelease")
|
self.load_attr(data, "SetHandbrakeOnWinchRelease")
|
||||||
self.load_attr(data, "SteerSpeed")
|
self.load_attr(data, "SteerSpeed")
|
||||||
self.load_attr(data, "TruckType")
|
if "trucktype" in data.attrs:
|
||||||
|
self.TruckType = self.truck_types[data.attrs["trucktype"]]
|
||||||
|
self.ignore_attr("trucktype")
|
||||||
self.load_attr(data, "WaterCapacity")
|
self.load_attr(data, "WaterCapacity")
|
||||||
self.load_attr(data, "WheelRepairsCapacity")
|
self.load_attr(data, "WheelRepairsCapacity")
|
||||||
self.load_child(data, "CompatibleWheels")
|
self.load_child(data, "CompatibleWheels", always_as_list=True)
|
||||||
if self.CompatibleWheels and not isinstance(self.CompatibleWheels, list):
|
|
||||||
self.CompatibleWheels = [self.CompatibleWheels]
|
|
||||||
self.load_child(data, "Damage")
|
self.load_child(data, "Damage")
|
||||||
self.load_child(data, "Wheels")
|
self.load_child(data, "Wheels")
|
||||||
|
|
||||||
@ -1058,6 +1262,9 @@ class TruckData(SnowrunnerClass):
|
|||||||
self.pak.get_object(object_type=SnowrunnerGameObjectType.ENGINE_VARIANTS, name=n.strip())
|
self.pak.get_object(object_type=SnowrunnerGameObjectType.ENGINE_VARIANTS, name=n.strip())
|
||||||
for n in data.children["enginesocket"].attrs["type"].split(",")
|
for n in data.children["enginesocket"].attrs["type"].split(",")
|
||||||
]
|
]
|
||||||
|
self.DefaultEngine = list(
|
||||||
|
{x.get_engine(data.children["enginesocket"].attrs["default"]) for x in self.Engines} - {None}
|
||||||
|
)[0]
|
||||||
self.ignore_child("EngineSocket")
|
self.ignore_child("EngineSocket")
|
||||||
|
|
||||||
if "gearboxsocket" in data.children:
|
if "gearboxsocket" in data.children:
|
||||||
@ -1065,6 +1272,9 @@ class TruckData(SnowrunnerClass):
|
|||||||
self.pak.get_object(object_type=SnowrunnerGameObjectType.GEARBOX_VARIANTS, name=n.strip())
|
self.pak.get_object(object_type=SnowrunnerGameObjectType.GEARBOX_VARIANTS, name=n.strip())
|
||||||
for n in data.children["gearboxsocket"].attrs["type"].split(",")
|
for n in data.children["gearboxsocket"].attrs["type"].split(",")
|
||||||
]
|
]
|
||||||
|
self.DefaultGearbox = list(
|
||||||
|
{x.get_gearbox(data.children["gearboxsocket"].attrs["default"]) for x in self.Gearboxes} - {None}
|
||||||
|
)[0]
|
||||||
self.ignore_child("GearboxSocket")
|
self.ignore_child("GearboxSocket")
|
||||||
|
|
||||||
if "suspensionsocket" in data.children:
|
if "suspensionsocket" in data.children:
|
||||||
@ -1072,6 +1282,10 @@ class TruckData(SnowrunnerClass):
|
|||||||
self.pak.get_object(object_type=SnowrunnerGameObjectType.SUSPENSION_SET_VARIANTS, name=n.strip())
|
self.pak.get_object(object_type=SnowrunnerGameObjectType.SUSPENSION_SET_VARIANTS, name=n.strip())
|
||||||
for n in data.children["suspensionsocket"].attrs["type"].split(",")
|
for n in data.children["suspensionsocket"].attrs["type"].split(",")
|
||||||
]
|
]
|
||||||
|
self.DefaultSuspension = list(
|
||||||
|
{x.get_suspension_set(data.children["suspensionsocket"].attrs["default"]) for x in self.Suspensions}
|
||||||
|
- {None}
|
||||||
|
)[0]
|
||||||
self.ignore_child("SuspensionSocket")
|
self.ignore_child("SuspensionSocket")
|
||||||
|
|
||||||
if "winchupgradesocket" in data.children:
|
if "winchupgradesocket" in data.children:
|
||||||
@ -1079,6 +1293,9 @@ class TruckData(SnowrunnerClass):
|
|||||||
self.pak.get_object(object_type=SnowrunnerGameObjectType.WINCH_VARIANTS, name=n.strip())
|
self.pak.get_object(object_type=SnowrunnerGameObjectType.WINCH_VARIANTS, name=n.strip())
|
||||||
for n in data.children["winchupgradesocket"].attrs["type"].split(",")
|
for n in data.children["winchupgradesocket"].attrs["type"].split(",")
|
||||||
]
|
]
|
||||||
|
self.DefaultWinch = list(
|
||||||
|
{x.get_winch(data.children["winchupgradesocket"].attrs["default"]) for x in self.Winches} - {None}
|
||||||
|
)[0]
|
||||||
self.ignore_child("WinchUpgradeSocket")
|
self.ignore_child("WinchUpgradeSocket")
|
||||||
|
|
||||||
self.ignore_attr("_noinherit")
|
self.ignore_attr("_noinherit")
|
||||||
@ -1150,9 +1367,7 @@ class TruckTires(SnowrunnerClass):
|
|||||||
self.TruckTire = None
|
self.TruckTire = None
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_child(data, "TruckTire")
|
self.load_child(data, "TruckTire", always_as_list=True)
|
||||||
if self.TruckTire and not isinstance(self.TruckTire, list):
|
|
||||||
self.TruckTire = [self.TruckTire]
|
|
||||||
self.loading_finished(data)
|
self.loading_finished(data)
|
||||||
|
|
||||||
def update_data(self, data: SnowRunnerXNLNode) -> None:
|
def update_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
@ -1161,7 +1376,7 @@ class TruckTires(SnowrunnerClass):
|
|||||||
|
|
||||||
for orig, upd in zip_longest(self.TruckTire, data.children["trucktire"]):
|
for orig, upd in zip_longest(self.TruckTire, data.children["trucktire"]):
|
||||||
if orig is None:
|
if orig is None:
|
||||||
self.TruckTire.append(self.pak.load_class(SnowrunnerGameObjectType.TRUCK_TIRE, upd))
|
self.TruckTire.append(self.pak.load_class(SnowrunnerGameObjectType.TRUCK_TIRE, upd, dlc_name=self.DLC))
|
||||||
elif upd is None:
|
elif upd is None:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
@ -1202,6 +1417,13 @@ class TruckWheels(SnowrunnerClass):
|
|||||||
self.WidthRear = -1.0
|
self.WidthRear = -1.0
|
||||||
self.TruckTires = None
|
self.TruckTires = None
|
||||||
|
|
||||||
|
def get_truck_tire(self, name: str) -> TruckTire | None:
|
||||||
|
for x in self.TruckTires.TruckTire:
|
||||||
|
if x.Name == name:
|
||||||
|
return x
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_attr(data, "DamageCapacity")
|
self.load_attr(data, "DamageCapacity")
|
||||||
self.load_attr(data, "Mass")
|
self.load_attr(data, "Mass")
|
||||||
@ -1276,12 +1498,21 @@ class Wheels(SnowrunnerClass):
|
|||||||
def __init__(self, pak_loader: InitialPakLoader):
|
def __init__(self, pak_loader: InitialPakLoader):
|
||||||
super().__init__(pak_loader=pak_loader)
|
super().__init__(pak_loader=pak_loader)
|
||||||
self.Wheel = None
|
self.Wheel = None
|
||||||
|
self.DefaultTire = None
|
||||||
|
self.DefaultWheelType = None
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.ignore_attr("DefaultWheelType")
|
if "defaultwheeltype" in data.attrs:
|
||||||
|
self.DefaultWheelType = self.pak.get_object(
|
||||||
|
SnowrunnerGameObjectType.TRUCK_WHEELS, name=data.attrs["defaultwheeltype"]
|
||||||
|
)
|
||||||
|
self.ignore_attr("DefaultWheelType")
|
||||||
|
if "defaulttire" in data.attrs:
|
||||||
|
self.DefaultTire = self.DefaultWheelType.get_truck_tire(data.attrs["defaulttire"])
|
||||||
|
self.ignore_attr("DefaultTire")
|
||||||
|
|
||||||
self.ignore_attr("DefaultRim")
|
self.ignore_attr("DefaultRim")
|
||||||
self.ignore_attr("DefaultTire")
|
self.load_child(data, "Wheel", always_as_list=True)
|
||||||
self.load_child(data, "Wheel")
|
|
||||||
self.loading_finished(data)
|
self.loading_finished(data)
|
||||||
|
|
||||||
|
|
||||||
@ -1349,8 +1580,15 @@ class WinchVariants(SnowrunnerClass):
|
|||||||
super().__init__(pak_loader=pak_loader)
|
super().__init__(pak_loader=pak_loader)
|
||||||
self.Winch = []
|
self.Winch = []
|
||||||
|
|
||||||
|
def get_winch(self, name: str) -> Winch | None:
|
||||||
|
for e in self.Winch:
|
||||||
|
if e.Name == name:
|
||||||
|
return e
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
def load_data(self, data: SnowRunnerXNLNode) -> None:
|
||||||
self.load_child(data, "Winch")
|
self.load_child(data, "Winch", always_as_list=True)
|
||||||
self.load_child(data, "WinchParams")
|
self.load_child(data, "WinchParams")
|
||||||
self.loading_finished(data)
|
self.loading_finished(data)
|
||||||
|
|
||||||
@ -1366,6 +1604,15 @@ class LanguageLoader(dict):
|
|||||||
value = parts[-1].replace('"', "").replace("\\", '"')
|
value = parts[-1].replace('"', "").replace("\\", '"')
|
||||||
self[key] = value
|
self[key] = value
|
||||||
|
|
||||||
|
def get_sanitized(self, key: str, default: str | None = None) -> str:
|
||||||
|
if key not in self:
|
||||||
|
if default is not None:
|
||||||
|
return default
|
||||||
|
else:
|
||||||
|
raise KeyError(key)
|
||||||
|
|
||||||
|
return " ".join(x[0] + x[1:].lower() for x in re.split(r"[-_ ]+", self[key]))
|
||||||
|
|
||||||
|
|
||||||
TYPE_CLASS_MATRIX = {
|
TYPE_CLASS_MATRIX = {
|
||||||
"addonslots": AddonSlots,
|
"addonslots": AddonSlots,
|
||||||
@ -1449,6 +1696,7 @@ class SnowrunnerGameObjectType(str, Enum):
|
|||||||
WINCH_PARAMS = "winchparams"
|
WINCH_PARAMS = "winchparams"
|
||||||
WINCH_VARIANTS = "winchvariants"
|
WINCH_VARIANTS = "winchvariants"
|
||||||
|
|
||||||
|
@property
|
||||||
def snowrunner_class(self):
|
def snowrunner_class(self):
|
||||||
return TYPE_CLASS_MATRIX[self.value]
|
return TYPE_CLASS_MATRIX[self.value]
|
||||||
|
|
||||||
@ -1532,6 +1780,7 @@ class InitialPakLoader:
|
|||||||
self.pak_zip = get_initial_pak_zipfile(get_initial_pak_path())
|
self.pak_zip = get_initial_pak_zipfile(get_initial_pak_path())
|
||||||
self.is_loaded = False
|
self.is_loaded = False
|
||||||
self.languages = {}
|
self.languages = {}
|
||||||
|
self.dlc_names = {x: {} for x in SnowrunnerGameObjectType}
|
||||||
self.raw_data = {x: {} for x in SnowrunnerGameObjectType}
|
self.raw_data = {x: {} for x in SnowrunnerGameObjectType}
|
||||||
self.game_data = {x: {} for x in SnowrunnerGameObjectType}
|
self.game_data = {x: {} for x in SnowrunnerGameObjectType}
|
||||||
self.templates = {x: {} for x in SnowrunnerGameObjectType}
|
self.templates = {x: {} for x in SnowrunnerGameObjectType}
|
||||||
@ -1550,6 +1799,7 @@ class InitialPakLoader:
|
|||||||
self,
|
self,
|
||||||
object_type: SnowrunnerGameObjectType,
|
object_type: SnowrunnerGameObjectType,
|
||||||
data: SnowRunnerXNLNode,
|
data: SnowRunnerXNLNode,
|
||||||
|
dlc_name: str,
|
||||||
parent: str | None = None,
|
parent: str | None = None,
|
||||||
lazy: bool = False,
|
lazy: bool = False,
|
||||||
) -> SnowrunnerClass | list[SnowrunnerClass] | None:
|
) -> SnowrunnerClass | list[SnowrunnerClass] | None:
|
||||||
@ -1557,37 +1807,40 @@ class InitialPakLoader:
|
|||||||
template = self.get_object(object_type=object_type, name=parent, lazy=lazy)
|
template = self.get_object(object_type=object_type, name=parent, lazy=lazy)
|
||||||
if template is None:
|
if template is None:
|
||||||
return None
|
return None
|
||||||
ret = object_type.snowrunner_class().from_template(pak_loader=self, template=template)
|
ret = object_type.snowrunner_class.from_template(pak_loader=self, template=template)
|
||||||
|
ret.DLC = dlc_name
|
||||||
ret.update_data(data)
|
ret.update_data(data)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
if not isinstance(data, list):
|
if not isinstance(data, list):
|
||||||
if "_template" not in data.attrs:
|
if "_template" not in data.attrs:
|
||||||
ret = object_type.snowrunner_class()(pak_loader=self)
|
ret = object_type.snowrunner_class(pak_loader=self)
|
||||||
else:
|
else:
|
||||||
ret = object_type.snowrunner_class().from_template(
|
ret = object_type.snowrunner_class.from_template(
|
||||||
pak_loader=self, template=self.get_template(object_type=object_type, name=data.attrs["_template"])
|
pak_loader=self, template=self.get_template(object_type=object_type, name=data.attrs["_template"])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ret.DLC = dlc_name
|
||||||
ret.load_data(data)
|
ret.load_data(data)
|
||||||
else:
|
else:
|
||||||
ret = []
|
ret = []
|
||||||
for sub_data in data:
|
for sub_data in data:
|
||||||
if "_template" not in sub_data.attrs:
|
if "_template" not in sub_data.attrs:
|
||||||
ret.append(object_type.snowrunner_class()(pak_loader=self))
|
ret.append(object_type.snowrunner_class(pak_loader=self))
|
||||||
else:
|
else:
|
||||||
ret.append(
|
ret.append(
|
||||||
object_type.snowrunner_class().from_template(
|
object_type.snowrunner_class.from_template(
|
||||||
pak_loader=self,
|
pak_loader=self,
|
||||||
template=self.get_template(object_type=object_type, name=sub_data.attrs["_template"]),
|
template=self.get_template(object_type=object_type, name=sub_data.attrs["_template"]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ret[-1].DLC = dlc_name
|
||||||
ret[-1].load_data(sub_data)
|
ret[-1].load_data(sub_data)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def load_templates(self, data: dict, local: bool = False) -> None:
|
def load_templates(self, data: dict, dlc_name: str, local: bool = False) -> None:
|
||||||
if local:
|
if local:
|
||||||
self.templates_local = {x: {} for x in SnowrunnerGameObjectType}
|
self.templates_local = {x: {} for x in SnowrunnerGameObjectType}
|
||||||
|
|
||||||
@ -1610,18 +1863,26 @@ class InitialPakLoader:
|
|||||||
continue
|
continue
|
||||||
if local:
|
if local:
|
||||||
self.templates_local[category][tp_name] = self.load_class(
|
self.templates_local[category][tp_name] = self.load_class(
|
||||||
object_type=object_type, data=sub_data
|
object_type=object_type,
|
||||||
|
data=sub_data,
|
||||||
|
dlc_name=dlc_name,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.templates[category][tp_name] = self.load_class(object_type=object_type, data=sub_data)
|
self.templates[category][tp_name] = self.load_class(
|
||||||
|
object_type=object_type, data=sub_data, dlc_name=dlc_name
|
||||||
|
)
|
||||||
if defer:
|
if defer:
|
||||||
for tp_name, sub_data in defer:
|
for tp_name, sub_data in defer:
|
||||||
if local:
|
if local:
|
||||||
self.templates_local[category][tp_name] = self.load_class(
|
self.templates_local[category][tp_name] = self.load_class(
|
||||||
object_type=object_type, data=sub_data
|
object_type=object_type,
|
||||||
|
data=sub_data,
|
||||||
|
dlc_name=dlc_name,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.templates[category][tp_name] = self.load_class(object_type=object_type, data=sub_data)
|
self.templates[category][tp_name] = self.load_class(
|
||||||
|
object_type=object_type, data=sub_data, dlc_name=dlc_name
|
||||||
|
)
|
||||||
|
|
||||||
elif category in self.ignore_categories:
|
elif category in self.ignore_categories:
|
||||||
pass # Ignore for now
|
pass # Ignore for now
|
||||||
@ -1657,6 +1918,9 @@ class InitialPakLoader:
|
|||||||
logger.error(f"Unknown Game Data Object requested: {name} in {object_type.name}")
|
logger.error(f"Unknown Game Data Object requested: {name} in {object_type.name}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
def get_object_list(self, object_type: SnowrunnerGameObjectType) -> list:
|
||||||
|
return list(self.game_data[object_type].values())
|
||||||
|
|
||||||
def get_sorted_object_list(
|
def get_sorted_object_list(
|
||||||
self, object_type: SnowrunnerGameObjectType, language: LanguageLoader
|
self, object_type: SnowrunnerGameObjectType, language: LanguageLoader
|
||||||
) -> list[tuple[str, SnowrunnerClass]]:
|
) -> list[tuple[str, SnowrunnerClass]]:
|
||||||
@ -1664,12 +1928,13 @@ class InitialPakLoader:
|
|||||||
sorted(self.game_data[object_type].items(), key=lambda v: v[1].get_translated_ui_name(language)),
|
sorted(self.game_data[object_type].items(), key=lambda v: v[1].get_translated_ui_name(language)),
|
||||||
)
|
)
|
||||||
|
|
||||||
def store_raw(self, ref: str, data: dict):
|
def store_raw(self, ref: str, dlc_name: str, data: dict):
|
||||||
cat_in_matrix = set(data.keys()) & set(SnowrunnerGameObjectType.values())
|
cat_in_matrix = set(data.keys()) & set(SnowrunnerGameObjectType.values())
|
||||||
cat_in_ignore = set(data.keys()) & self.ignore_categories
|
cat_in_ignore = set(data.keys()) & self.ignore_categories
|
||||||
|
|
||||||
if cat_in_matrix:
|
if cat_in_matrix:
|
||||||
self.raw_data[SnowrunnerGameObjectType(list(cat_in_matrix)[0])][ref] = data
|
self.raw_data[SnowrunnerGameObjectType(list(cat_in_matrix)[0])][ref] = data
|
||||||
|
self.dlc_names[SnowrunnerGameObjectType(list(cat_in_matrix)[0])][ref] = dlc_name
|
||||||
elif cat_in_ignore:
|
elif cat_in_ignore:
|
||||||
pass # not sure what to do with this, yet
|
pass # not sure what to do with this, yet
|
||||||
else:
|
else:
|
||||||
@ -1686,6 +1951,8 @@ class InitialPakLoader:
|
|||||||
for member in self.pak_zip.infolist():
|
for member in self.pak_zip.infolist():
|
||||||
if not member.filename.endswith(".xml"):
|
if not member.filename.endswith(".xml"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
dlc_name = member.filename.split("\\")[2] if "_dlc" in member.filename else None
|
||||||
filename_ref = member.filename.split("\\")[-1].replace(".xml", "")
|
filename_ref = member.filename.split("\\")[-1].replace(".xml", "")
|
||||||
logger.info(f" - {member.filename}")
|
logger.info(f" - {member.filename}")
|
||||||
with self.pak_zip.open(member) as d_file:
|
with self.pak_zip.open(member) as d_file:
|
||||||
@ -1695,13 +1962,13 @@ class InitialPakLoader:
|
|||||||
|
|
||||||
if len(data) == 1 and "_templates" in data:
|
if len(data) == 1 and "_templates" in data:
|
||||||
logger.info(f" - -> Loading templates from {member.filename}")
|
logger.info(f" - -> Loading templates from {member.filename}")
|
||||||
self.load_templates(data["_templates"].children)
|
self.load_templates(data["_templates"].children, dlc_name=dlc_name)
|
||||||
continue
|
continue
|
||||||
elif len(data) > 3:
|
elif len(data) > 3:
|
||||||
logger.error(f"Multiple keys?! ({list(data.keys())}")
|
logger.error(f"Multiple keys?! ({list(data.keys())}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
self.store_raw(filename_ref, data)
|
self.store_raw(filename_ref, dlc_name, data)
|
||||||
|
|
||||||
deferred_loads = []
|
deferred_loads = []
|
||||||
logger.info("Loading GameData")
|
logger.info("Loading GameData")
|
||||||
@ -1715,9 +1982,13 @@ class InitialPakLoader:
|
|||||||
|
|
||||||
logger.info(f" - {ref}")
|
logger.info(f" - {ref}")
|
||||||
if "_templates" in data:
|
if "_templates" in data:
|
||||||
self.load_templates(data["_templates"].children, local=True)
|
self.load_templates(
|
||||||
|
data["_templates"].children, local=True, dlc_name=self.dlc_names[object_type][ref]
|
||||||
|
)
|
||||||
|
|
||||||
self.game_data[object_type][ref] = self.load_class(object_type, data[category])
|
self.game_data[object_type][ref] = self.load_class(
|
||||||
|
object_type, data[category], dlc_name=self.dlc_names[object_type][ref]
|
||||||
|
)
|
||||||
|
|
||||||
del self.raw_data[object_type]
|
del self.raw_data[object_type]
|
||||||
|
|
||||||
@ -1726,9 +1997,15 @@ class InitialPakLoader:
|
|||||||
for object_type, ref, data in deferred_loads:
|
for object_type, ref, data in deferred_loads:
|
||||||
logger.info(f" - {ref}")
|
logger.info(f" - {ref}")
|
||||||
if "_templates" in data:
|
if "_templates" in data:
|
||||||
self.load_templates(data["_templates"].children, local=True)
|
self.load_templates(
|
||||||
|
data["_templates"].children, local=True, dlc_name=self.dlc_names[object_type][ref]
|
||||||
|
)
|
||||||
sr_class = self.load_class(
|
sr_class = self.load_class(
|
||||||
object_type, data[category], parent=data["_parent"].get_attr("file"), lazy=True
|
object_type,
|
||||||
|
data[category],
|
||||||
|
parent=data["_parent"].get_attr("file"),
|
||||||
|
lazy=True,
|
||||||
|
dlc_name=self.dlc_names[object_type][ref],
|
||||||
)
|
)
|
||||||
if sr_class is None:
|
if sr_class is None:
|
||||||
still_deferred_loads.append((object_type, ref, data))
|
still_deferred_loads.append((object_type, ref, data))
|
||||||
@ -1743,7 +2020,9 @@ class InitialPakLoader:
|
|||||||
logger.info(f" - {object_type.name}, {ref}")
|
logger.info(f" - {object_type.name}, {ref}")
|
||||||
if "_templates" in data:
|
if "_templates" in data:
|
||||||
self.load_templates(data["_templates"].children, local=True)
|
self.load_templates(data["_templates"].children, local=True)
|
||||||
self.game_data[object_type][ref] = self.load_class(object_type, data[category])
|
self.game_data[object_type][ref] = self.load_class(
|
||||||
|
object_type, data[category], dlc_name=self.dlc_names[object_type][ref]
|
||||||
|
)
|
||||||
deferred_loads = []
|
deferred_loads = []
|
||||||
|
|
||||||
for cat, v in self.raw_data.items():
|
for cat, v in self.raw_data.items():
|
||||||
|
|||||||
383
output.py
383
output.py
@ -1,6 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import os
|
import os
|
||||||
from loader import InitialPakLoader, LanguageLoader, SnowrunnerGameObjectType, SnowrunnerClass, GameData
|
from constants import DLC_NAMES
|
||||||
|
from loader import (
|
||||||
|
InitialPakLoader,
|
||||||
|
LanguageLoader,
|
||||||
|
SnowrunnerGameObjectType,
|
||||||
|
TruckAddonCategory,
|
||||||
|
GameData,
|
||||||
|
SnowrunnerClass,
|
||||||
|
)
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
@ -13,13 +21,17 @@ def get_head(language: LanguageLoader, category: str, name: str | None = None) -
|
|||||||
<title>SnowRunnerDB - {category}"""
|
<title>SnowRunnerDB - {category}"""
|
||||||
+ (f""" - {name}""" if name is not None else "")
|
+ (f""" - {name}""" if name is not None else "")
|
||||||
+ f"""</title>
|
+ f"""</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<link href="https://cdn.datatables.net/v/dt/dt-3.0.1/datatables.min.css" rel="stylesheet">
|
||||||
|
<script src="https://cdn.datatables.net/v/dt/dt-3.0.1/datatables.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id='navi_lang'></div>
|
<div id='navi_lang'></div>
|
||||||
<div id='categories'>
|
<div id='categories'>
|
||||||
<ul id='navi_cat'>
|
<ul id='navi_cat'>
|
||||||
<li><a href="/{language.Name}/trucks/">Trucks</a></li>
|
<li><a href="/{language.Name}/trucks/">Trucks</a></li>
|
||||||
|
<li><a href="/{language.Name}/frame_addons/">Frame Addons</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div id='content'>
|
<div id='content'>
|
||||||
@ -44,50 +56,154 @@ def write_html(
|
|||||||
|
|
||||||
|
|
||||||
def write_trucks(pak: InitialPakLoader, destination_directory: str, language: LanguageLoader):
|
def write_trucks(pak: InitialPakLoader, destination_directory: str, language: LanguageLoader):
|
||||||
index_table = ""
|
index_content = " <h1>Trucks</h1>\n"
|
||||||
|
index_content += f" <table id='truck_index' class='display'>\n"
|
||||||
truck_types = {}
|
index_content += (
|
||||||
|
f" <thead><tr>\n"
|
||||||
|
f" <th>Name</th>\n"
|
||||||
|
f" <th>Class</th>\n"
|
||||||
|
f" <th>DLC</th>\n"
|
||||||
|
f" <th>Unlock by</th>\n"
|
||||||
|
f" <th>Region</th>\n"
|
||||||
|
f" <th>Price</th>\n"
|
||||||
|
f" <th>Weight</th>\n"
|
||||||
|
f" <th>Drivetrain</th>\n"
|
||||||
|
f" <th>AWD</th>\n"
|
||||||
|
f" <th>DiffLock</th>\n"
|
||||||
|
f" </tr></thead>\n"
|
||||||
|
)
|
||||||
|
index_content += f" <tbody>\n"
|
||||||
|
|
||||||
for reference, truck in pak.get_sorted_object_list(SnowrunnerGameObjectType.TRUCK, language):
|
for reference, truck in pak.get_sorted_object_list(SnowrunnerGameObjectType.TRUCK, language):
|
||||||
if truck.Type != "Truck":
|
if truck.Type != "Truck":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if truck.TruckData.TruckType not in truck_types:
|
|
||||||
truck_types[truck.TruckData.TruckType] = [(reference, truck)]
|
|
||||||
else:
|
|
||||||
truck_types[truck.TruckData.TruckType].append((reference, truck))
|
|
||||||
|
|
||||||
truck_file = os.path.join(destination_directory, reference + ".html")
|
truck_file = os.path.join(destination_directory, reference + ".html")
|
||||||
truck_content = f" <h1>{truck.get_translated_ui_name(language)}</h1>"
|
truck_content = f" <h1>{truck.get_translated_ui_name(language)}</h1>"
|
||||||
|
truck_content += f" <table>\n"
|
||||||
|
try:
|
||||||
|
truck_content += f" <tr><td>DLC</td><td>{DLC_NAMES[truck.DLC]}</td></tr>\n"
|
||||||
|
except KeyError:
|
||||||
|
print(f"DEBUG: DLC {truck.DLC} for Truck {truck.get_translated_ui_name(language)}")
|
||||||
|
exit(1)
|
||||||
|
truck_content += f" <tr><td>Weight</td><td>{truck.Weight}kg</td></tr>\n"
|
||||||
|
truck_content += f" <tr><td>AWD</td><td>{language[truck.AWDInfo.value]}</td></tr>\n"
|
||||||
|
truck_content += f" <tr><td>DiffLock</td><td>{language[truck.DiffLockInfo.value]}</td></tr>\n"
|
||||||
|
truck_content += f" <tr><td>Def Engine</td><td>{truck.TruckData.DefaultEngine.get_translated_ui_name(language)}</td></tr>\n"
|
||||||
|
truck_content += f" <tr><td>Def Gearbox</td><td>{truck.TruckData.DefaultGearbox.get_translated_ui_name(language)}</td></tr>\n"
|
||||||
|
truck_content += f" <tr><td>Def Suspension</td><td>{truck.TruckData.DefaultSuspension.get_translated_ui_name(language)}</td></tr>\n"
|
||||||
|
truck_content += f" <tr><td>Def Winch</td><td>{truck.TruckData.DefaultWinch.get_translated_ui_name(language)}</td></tr>\n"
|
||||||
|
truck_content += f" <tr><td>Def Tire</td><td>{truck.TruckData.Wheels.DefaultTire.get_translated_ui_name(language)}</td></tr>\n"
|
||||||
|
truck_content += f" </table>\n"
|
||||||
|
|
||||||
# Engines
|
# Engines
|
||||||
truck_content += f" <h2>Engines</h2>\n"
|
truck_content += f" <h2>Engines</h2>\n"
|
||||||
engines = [x for y in truck.TruckData.Engines for x in y.Engines]
|
engines = [x for y in truck.TruckData.Engines for x in y.Engine]
|
||||||
truck_content += f" <table>\n"
|
truck_content += f" <table id='engines' data-order='[[2, \"asc\"]]'>\n"
|
||||||
truck_content += f" <tr><th>Name</th><th>Price</th><th>Torque</th><th>Base Fuel Consumption</th><th>Unlock By</th></tr>\n"
|
truck_content += (
|
||||||
|
f" <thead><tr>\n"
|
||||||
|
f" <th>Name</th>\n"
|
||||||
|
f" <th>Price</th>\n"
|
||||||
|
f" <th>Unlock By</th>\n"
|
||||||
|
f" <th>Base Fuel Consumption</th>\n"
|
||||||
|
f" <th>Torque</th>\n"
|
||||||
|
f" <th>Power-to-Weight</th>\n"
|
||||||
|
f" </tr></thead>\n"
|
||||||
|
)
|
||||||
|
truck_content += f" <tbody>\n"
|
||||||
# Power2Weight
|
# Power2Weight
|
||||||
# Power2Fuel
|
# Power2Fuel
|
||||||
for engine in sorted(engines, key=lambda x: x.Torque):
|
for engine in sorted(engines, key=lambda x: x.Torque):
|
||||||
truck_content += (
|
truck_content += (
|
||||||
f" <tr>"
|
f" <tr>"
|
||||||
f"<td>{engine.get_translated_ui_name(language)}</td>"
|
f" <td>{engine.get_translated_ui_name(language)}</td>"
|
||||||
f"<td>{engine.GameData.Price}</th>"
|
f" <td>{engine.GameData.Price}</th>"
|
||||||
f"<td>{engine.Torque}</td>"
|
f" <td>{engine.GameData.get_unlock_str()}</td>"
|
||||||
f"<td>{engine.FuelConsumption}</td>"
|
f" <td>{engine.FuelConsumption}</td>"
|
||||||
f"<td>{engine.GameData.get_unlock_str()}</td>"
|
f" <td>{engine.Torque}</td>"
|
||||||
f"</tr>\n"
|
f" <td>{engine.Torque / truck.Weight:.2f}</td>"
|
||||||
|
f" </tr>\n"
|
||||||
)
|
)
|
||||||
truck_content += f" </table>\n"
|
truck_content += f" </tbody></table>\n"
|
||||||
|
|
||||||
# Gearboxes
|
# Gearboxes
|
||||||
|
gearboxes = [y for x in truck.TruckData.Gearboxes for y in x.Gearbox]
|
||||||
|
max_gear_count = max(len(x.Gear) for x in gearboxes)
|
||||||
|
|
||||||
truck_content += f" <h2>Gearboxes</h2>\n"
|
truck_content += f" <h2>Gearboxes</h2>\n"
|
||||||
|
truck_content += f" <h3>General</h3>\n"
|
||||||
|
truck_content += f" <table id='gearboxes_general'>\n"
|
||||||
|
truck_content += (
|
||||||
|
f" <thead><tr>\n"
|
||||||
|
f" <th>Name</th>\n"
|
||||||
|
f" <th>Price</th>\n"
|
||||||
|
f" <th>Unlock By</th>\n"
|
||||||
|
f" <th>Fine-Tunable</th>\n"
|
||||||
|
f" <th>L-</th>\n"
|
||||||
|
f" <th>L</th>\n"
|
||||||
|
f" <th>L+</th>\n"
|
||||||
|
f" <th>H</th>\n"
|
||||||
|
f" <th>Gears</th>\n"
|
||||||
|
f" </tr></thead>\n"
|
||||||
|
)
|
||||||
|
truck_content += f" <tbody>\n"
|
||||||
|
for gearbox in sorted(gearboxes, key=lambda x: x.get_translated_ui_name(language)):
|
||||||
|
truck_content += f" <tr>\n"
|
||||||
|
truck_content += f" <td>{gearbox.get_translated_ui_name(language)}</td>\n"
|
||||||
|
truck_content += f" <td>{gearbox.Price}</td>\n"
|
||||||
|
truck_content += f" <td>{gearbox.GameData.get_unlock_str()}</td>\n"
|
||||||
|
truck_content += (
|
||||||
|
f" <td>{'✓' if gearbox.GearboxParams.IsManualLowGear else '˙'}</td>\n"
|
||||||
|
)
|
||||||
|
truck_content += (
|
||||||
|
f" <td>{'✓' if gearbox.GearboxParams.IsLowerMinusGearExists else '˙'}</td>\n"
|
||||||
|
)
|
||||||
|
truck_content += (
|
||||||
|
f" <td>{'✓' if gearbox.GearboxParams.IsLowerGearExists else '˙'}</td>\n"
|
||||||
|
)
|
||||||
|
truck_content += (
|
||||||
|
f" <td>{'✓' if gearbox.GearboxParams.IsLowerPlusGearExists else '˙'}</td>\n"
|
||||||
|
)
|
||||||
|
truck_content += (
|
||||||
|
f" <td>{'✓' if gearbox.GearboxParams.IsHighGearExists else '˙'}</td>\n"
|
||||||
|
)
|
||||||
|
truck_content += f" <td>{len(gearbox.Gear)}</td>\n"
|
||||||
|
truck_content += f" </tr>\n"
|
||||||
|
truck_content += f" </tbody></table>\n"
|
||||||
|
|
||||||
|
truck_content += f" <h3>Fuel Consumption</h3>\n"
|
||||||
|
truck_content += f" <table id='gearboxes_fuel'>\n"
|
||||||
|
truck_content += (
|
||||||
|
f" <thead><tr>\n"
|
||||||
|
f" <th>Name</th>\n"
|
||||||
|
f" <th>Fuel Consumption</th>\n"
|
||||||
|
f" <th>AWD Fuel Modifier</th>\n"
|
||||||
|
)
|
||||||
|
for i in range(max_gear_count):
|
||||||
|
gear_num = str(i + 1) if i > 0 else "L+/1"
|
||||||
|
truck_content += f" <th>{gear_num}</th>\n"
|
||||||
|
truck_content += f" </tr></thead>\n"
|
||||||
|
truck_content += f" <tbody>\n"
|
||||||
|
|
||||||
|
for gearbox in sorted(gearboxes, key=lambda x: x.get_translated_ui_name(language)):
|
||||||
|
truck_content += f" <tr>\n"
|
||||||
|
truck_content += f" <td>{gearbox.get_translated_ui_name(language)}</td>\n"
|
||||||
|
truck_content += f" <td>{gearbox.FuelConsumption}</td>\n"
|
||||||
|
truck_content += f" <td>{gearbox.AWDConsumptionModifier}</td>\n"
|
||||||
|
for i in range(max_gear_count):
|
||||||
|
if i >= len(gearbox.Gear):
|
||||||
|
truck_content += f" <td>-</td>\n"
|
||||||
|
else:
|
||||||
|
truck_content += f" <td>{gearbox.Gear[i].FuelModifier}</td>\n"
|
||||||
|
truck_content += f" </tr>\n"
|
||||||
|
|
||||||
|
truck_content += f" </tbody></table>\n"
|
||||||
|
|
||||||
# Suspensions
|
# Suspensions
|
||||||
truck_content += f" <h2>Suspensions</h2>\n"
|
truck_content += f" <h2>Suspensions</h2>\n"
|
||||||
# Winches
|
|
||||||
truck_content += f" <h2>Winches</h2>\n"
|
|
||||||
|
|
||||||
# Wheels
|
# Wheels
|
||||||
truck_content += f" <h2>Wheels</h2>\n"
|
truck_content += f" <h2>Tires</h2>\n"
|
||||||
wheel_cat = {}
|
wheel_cat = {}
|
||||||
scales = set()
|
scales = set()
|
||||||
for cw in truck.TruckData.CompatibleWheels:
|
for cw in truck.TruckData.CompatibleWheels:
|
||||||
@ -124,6 +240,124 @@ def write_trucks(pak: InitialPakLoader, destination_directory: str, language: La
|
|||||||
scales = ", ".join(['%d"' % x for x in sorted(scales)])
|
scales = ", ".join(['%d"' % x for x in sorted(scales)])
|
||||||
truck_content += f" <h4>Available Tire Sizes: {scales}</h4>\n"
|
truck_content += f" <h4>Available Tire Sizes: {scales}</h4>\n"
|
||||||
|
|
||||||
|
# Winches
|
||||||
|
truck_content += f" <h2>Winches</h2>\n"
|
||||||
|
|
||||||
|
# Diff. Lock
|
||||||
|
diff_lock_addons = truck.get_available_truck_addons(TruckAddonCategory.DIFF_LOCK)
|
||||||
|
if diff_lock_addons:
|
||||||
|
truck_content += f" <h2>Diff. Lock</h2>\n"
|
||||||
|
truck_content += f" <table id='diff_lock'>\n"
|
||||||
|
truck_content += (
|
||||||
|
f" <thead><tr>\n"
|
||||||
|
f" <th>Name</th>\n"
|
||||||
|
f" <th>Price</th>\n"
|
||||||
|
f" <th>Unlock By</th>\n"
|
||||||
|
f" </tr></thead><tbody>\n"
|
||||||
|
)
|
||||||
|
for addon in sorted(diff_lock_addons, key=lambda v: v.get_translated_ui_name(language)):
|
||||||
|
truck_content += (
|
||||||
|
f" <tr>\n"
|
||||||
|
f" <td>{addon.get_translated_ui_name(language)}</td>\n"
|
||||||
|
f" <td>{addon.Price}</td>\n"
|
||||||
|
f" <td>{addon.GameData.get_unlock_str()}</td>\n"
|
||||||
|
f" </tr>\n"
|
||||||
|
)
|
||||||
|
truck_content += f" </tbody></table>\n"
|
||||||
|
|
||||||
|
# Spare Wheel (if any)
|
||||||
|
# Snorkel (if any)
|
||||||
|
snorkel_addons = truck.get_available_truck_addons(TruckAddonCategory.SNORKEL)
|
||||||
|
if snorkel_addons:
|
||||||
|
truck_content += f" <h2>Snorkel</h2>\n"
|
||||||
|
truck_content += f" <table id='snorkel'>\n"
|
||||||
|
truck_content += (
|
||||||
|
f" <thead><tr>\n"
|
||||||
|
f" <th>Name</th>\n"
|
||||||
|
f" <th>Price</th>\n"
|
||||||
|
f" <th>Unlock By</th>\n"
|
||||||
|
f" <th>Mass</th>\n"
|
||||||
|
f" </tr></thead><tbody>\n"
|
||||||
|
)
|
||||||
|
for addon in sorted(snorkel_addons, key=lambda v: v.get_translated_ui_name(language)):
|
||||||
|
truck_content += (
|
||||||
|
f" <tr>\n"
|
||||||
|
f" <td>{addon.get_translated_ui_name(language)}</td>\n"
|
||||||
|
f" <td>{addon.Price}</td>\n"
|
||||||
|
f" <td>{addon.GameData.get_unlock_str()}</td>\n"
|
||||||
|
f" <td>{addon.PhysicsModel.Weight}kg</td>\n"
|
||||||
|
f" </tr>\n"
|
||||||
|
)
|
||||||
|
truck_content += f" </tbody></table>\n"
|
||||||
|
|
||||||
|
# AWD
|
||||||
|
awd_addons = truck.get_available_truck_addons(TruckAddonCategory.ALL_WHEEL_DRIVE)
|
||||||
|
if awd_addons:
|
||||||
|
truck_content += f" <h2>AWD</h2>\n"
|
||||||
|
truck_content += f" <table id='awd'>\n"
|
||||||
|
truck_content += (
|
||||||
|
f" <thead><tr>\n"
|
||||||
|
f" <th>Name</th>\n"
|
||||||
|
f" <th>Price</th>\n"
|
||||||
|
f" <th>Unlock By</th>\n"
|
||||||
|
f" <th>Mass</th>\n"
|
||||||
|
f" </tr></thead><tbody>\n"
|
||||||
|
)
|
||||||
|
for addon in sorted(awd_addons, key=lambda v: v.get_translated_ui_name(language)):
|
||||||
|
truck_content += (
|
||||||
|
f" <tr>\n"
|
||||||
|
f" <td>{addon.get_translated_ui_name(language)}</td>\n"
|
||||||
|
f" <td>{addon.Price}</td>\n"
|
||||||
|
f" <td>{addon.GameData.get_unlock_str()}</td>\n"
|
||||||
|
f" <td>{addon.PhysicsModel.Weight}kg</td>\n"
|
||||||
|
f" </tr>\n"
|
||||||
|
)
|
||||||
|
truck_content += f" </tbody></table>\n"
|
||||||
|
|
||||||
|
# Frame Addons
|
||||||
|
|
||||||
|
truck_content += f" <h2>Frame Addons</h2>\n"
|
||||||
|
truck_content += f" <table id='frame_addons'>\n"
|
||||||
|
truck_content += (
|
||||||
|
f" <thead><tr>\n"
|
||||||
|
f" <th>Name</th>\n"
|
||||||
|
f" <th>Price</th>\n"
|
||||||
|
f" <th>Unlock By</th>\n"
|
||||||
|
f" <th>Mass</th>\n"
|
||||||
|
f" <th>Cargo Slots</th>\n"
|
||||||
|
f" <th>Repair Points</th>\n"
|
||||||
|
f" <th>Spare Wheels</th>\n"
|
||||||
|
f" <th>Fuel Capacity</th>\n"
|
||||||
|
f" <th>Water Capacity</th>\n"
|
||||||
|
f" </tr></thead><tbody>\n"
|
||||||
|
)
|
||||||
|
for truck_addon in sorted(
|
||||||
|
truck.get_available_truck_addons(TruckAddonCategory.FRAME_ADDON),
|
||||||
|
key=lambda v: v.get_translated_ui_name(language),
|
||||||
|
):
|
||||||
|
truck_content += f" <tr>\n"
|
||||||
|
truck_content += f" <td>{truck_addon.get_translated_ui_name(language)}</td>\n"
|
||||||
|
truck_content += f" <td>{truck_addon.Price}</td>\n"
|
||||||
|
truck_content += f" <td>{truck_addon.GameData.get_unlock_str()}</td>\n"
|
||||||
|
truck_content += f" <td>{truck_addon.PhysicsModel.Weight}kg</td>\n"
|
||||||
|
truck_content += f" <td>{truck_addon.AddonSlots.Quantity if truck_addon.AddonSlots is not None else ' '}</td>\n"
|
||||||
|
truck_content += f" <td>{truck_addon.TruckData.RepairsCapacity if truck_addon.TruckData is not None and truck_addon.TruckData.RepairsCapacity > 0 else ' '}</td>\n"
|
||||||
|
truck_content += f" <td>{truck_addon.TruckData.WheelRepairsCapacity if truck_addon.TruckData is not None and truck_addon.TruckData.WheelRepairsCapacity > 0 else ' '}</td>\n"
|
||||||
|
truck_content += f" <td>{truck_addon.TruckData.FuelCapacity if truck_addon.TruckData is not None and truck_addon.TruckData.FuelCapacity > 0 else ' '}</td>\n"
|
||||||
|
truck_content += f" <td>{truck_addon.TruckData.WaterCapacity if truck_addon.TruckData is not None and truck_addon.TruckData.WaterCapacity > 0 else ' '}</td>\n"
|
||||||
|
truck_content += f" </tr>\n"
|
||||||
|
truck_content += f" </tbody></table>\n"
|
||||||
|
|
||||||
|
truck_content += f" <script>\n"
|
||||||
|
truck_content += " document.addEventListener('DOMContentLoaded', function() {new DataTable('#engines', {info: false, paging: false, searching: false});});\n"
|
||||||
|
truck_content += " document.addEventListener('DOMContentLoaded', function() {new DataTable('#gearboxes_general', {info: false, paging: false, searching: false});});\n"
|
||||||
|
truck_content += " document.addEventListener('DOMContentLoaded', function() {new DataTable('#gearboxes_fuel', {info: false, paging: false, searching: false});});\n"
|
||||||
|
truck_content += " document.addEventListener('DOMContentLoaded', function() {new DataTable('#diff_lock', {info: false, paging: false, searching: false});});\n"
|
||||||
|
truck_content += " document.addEventListener('DOMContentLoaded', function() {new DataTable('#snorkel', {info: false, paging: false, searching: false});});\n"
|
||||||
|
truck_content += " document.addEventListener('DOMContentLoaded', function() {new DataTable('#awd', {info: false, paging: false, searching: false});});\n"
|
||||||
|
truck_content += " document.addEventListener('DOMContentLoaded', function() {new DataTable('#frame_addons', {info: false, paging: false, searching: false});});\n"
|
||||||
|
truck_content += f" </script>\n"
|
||||||
|
|
||||||
write_html(
|
write_html(
|
||||||
truck_file,
|
truck_file,
|
||||||
language=language,
|
language=language,
|
||||||
@ -132,20 +366,99 @@ def write_trucks(pak: InitialPakLoader, destination_directory: str, language: La
|
|||||||
name=truck.get_translated_ui_name(language),
|
name=truck.get_translated_ui_name(language),
|
||||||
)
|
)
|
||||||
|
|
||||||
index_content = " <h1>Trucks</h1>\n"
|
index_content += (
|
||||||
for truck_type in sorted(truck_types):
|
f" <tr>\n"
|
||||||
index_content += f" <h2>{truck_type}</h2>\n"
|
f" <td><a href='{reference}.html'>{truck.get_translated_ui_name(language)}</a></td>\n"
|
||||||
index_content += f" <table>\n"
|
f" <td>{language.get_sanitized(truck.TruckData.TruckType)}</td>\n"
|
||||||
index_content += f" <tr><th>Name</th></tr>\n"
|
f" <td>{DLC_NAMES[truck.DLC]}</td>\n"
|
||||||
for reference, truck in sorted(truck_types[truck_type], key=lambda v: v[1].get_translated_ui_name(language)):
|
f" <td>{truck.GameData.get_unlock_str()}</td>\n"
|
||||||
index_content += f" <tr><td><a href='{reference}.html'>{truck.get_translated_ui_name(language)}</a></th></tr>\n"
|
f" <td>{truck.GameData.Country}</td>\n"
|
||||||
index_content += f" </table>\n"
|
f" <td>{truck.get_shop_price()}</td>\n"
|
||||||
|
f" <td>{truck.Weight}</td>\n"
|
||||||
|
f" <td>{truck.DriveTrain}</td>\n"
|
||||||
|
f" <td>{language[truck.AWDInfo.value]}</td>\n"
|
||||||
|
f" <td>{language[truck.DiffLockInfo.value]}</td>\n"
|
||||||
|
f" </tr>\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
index_content += f" </tbody></table>\n"
|
||||||
|
index_content += " <script>document.addEventListener('DOMContentLoaded', function() {new DataTable('#truck_index', {paging: false});});</script>\n"
|
||||||
|
|
||||||
write_html(
|
write_html(
|
||||||
os.path.join(destination_directory, "index.html"), language=language, content=index_content, category="Trucks"
|
os.path.join(destination_directory, "index.html"), language=language, content=index_content, category="Trucks"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def write_frame_addons(pak: InitialPakLoader, destination_directory: str, language: LanguageLoader):
|
||||||
|
index_content = " <h1>Frame Addons</h1>\n"
|
||||||
|
index_content += f" <table id='frame_addons' class='display'>\n"
|
||||||
|
index_content += (
|
||||||
|
f" <thead><tr>\n"
|
||||||
|
f" <th>Name</th>\n"
|
||||||
|
f" <th>Price</th>\n"
|
||||||
|
f" <th>Unlock By</th>\n"
|
||||||
|
f" <th>Mass</th>\n"
|
||||||
|
f" <th>Cargo Slots</th>\n"
|
||||||
|
f" <th>Repair Points</th>\n"
|
||||||
|
f" <th>Spare Wheels</th>\n"
|
||||||
|
f" <th>Fuel Capacity</th>\n"
|
||||||
|
f" <th>Water Capacity</th>\n"
|
||||||
|
f" <th>Available for</th>\n"
|
||||||
|
f" </tr></thead>\n"
|
||||||
|
)
|
||||||
|
index_content += f" <tbody>\n"
|
||||||
|
|
||||||
|
for _, frame_addon in pak.get_sorted_object_list(SnowrunnerGameObjectType.TRUCK_ADDON, language=language):
|
||||||
|
if frame_addon.GameData.Category != TruckAddonCategory.FRAME_ADDON:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (
|
||||||
|
"TRANSLATION NOT FOUND" in frame_addon.get_translated_ui_name(language)
|
||||||
|
or len(frame_addon.get_translated_ui_name(language))
|
||||||
|
> 100 # This is a hidden frame addon where somebody swapped UI_NAME and UI_DESC
|
||||||
|
):
|
||||||
|
continue # FIXME: How To better detect Hidden Frame Addons not shown in game?
|
||||||
|
# Also e.g. Mack Defense has a Spare Wheel Addon that's always installed and not shown in game?!
|
||||||
|
|
||||||
|
available_trucks = [
|
||||||
|
x
|
||||||
|
for x in pak.get_sorted_object_list(SnowrunnerGameObjectType.TRUCK, language=language)
|
||||||
|
if x[1].Type == "Truck" and frame_addon.GameData.InstallSocket in x[1].get_addon_socket_names()
|
||||||
|
]
|
||||||
|
if not available_trucks:
|
||||||
|
continue
|
||||||
|
|
||||||
|
index_content += f" <tr>\n"
|
||||||
|
index_content += f" <td>{frame_addon.get_translated_ui_name(language)}</td>\n"
|
||||||
|
index_content += f" <td>{frame_addon.Price}</td>\n"
|
||||||
|
index_content += f" <td>{frame_addon.GameData.get_unlock_str()}</td>\n"
|
||||||
|
index_content += f" <td>{frame_addon.PhysicsModel.Weight}kg</td>\n"
|
||||||
|
index_content += f" <td>{frame_addon.AddonSlots.Quantity if frame_addon.AddonSlots is not None else ' '}</td>\n"
|
||||||
|
index_content += f" <td>{frame_addon.TruckData.RepairsCapacity if frame_addon.TruckData is not None and frame_addon.TruckData.RepairsCapacity > 0 else ' '}</td>\n"
|
||||||
|
index_content += f" <td>{frame_addon.TruckData.WheelRepairsCapacity if frame_addon.TruckData is not None and frame_addon.TruckData.WheelRepairsCapacity > 0 else ' '}</td>\n"
|
||||||
|
index_content += f" <td>{frame_addon.TruckData.FuelCapacity if frame_addon.TruckData is not None and frame_addon.TruckData.FuelCapacity > 0 else ' '}</td>\n"
|
||||||
|
index_content += f" <td>{frame_addon.TruckData.WaterCapacity if frame_addon.TruckData is not None and frame_addon.TruckData.WaterCapacity > 0 else ' '}</td>\n"
|
||||||
|
|
||||||
|
truck_links = ", ".join(
|
||||||
|
f'<a href="../trucks/{ref}.html">{truck.get_translated_ui_name(language)}</a>'
|
||||||
|
for ref, truck in available_trucks
|
||||||
|
)
|
||||||
|
index_content += f" <td>{truck_links}</td>\n"
|
||||||
|
|
||||||
|
index_content += f" </tr>\n"
|
||||||
|
|
||||||
|
index_content += f" </tbody>\n"
|
||||||
|
index_content += f" </table>\n"
|
||||||
|
index_content += " <script>document.addEventListener('DOMContentLoaded', function() {new DataTable('#frame_addons', {paging: false});});</script>\n"
|
||||||
|
|
||||||
|
write_html(
|
||||||
|
os.path.join(destination_directory, "index.html"),
|
||||||
|
language=language,
|
||||||
|
content=index_content,
|
||||||
|
category="Frame Addons",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_html(pak: InitialPakLoader, destination_directory: str = "output/"):
|
def create_html(pak: InitialPakLoader, destination_directory: str = "output/"):
|
||||||
if not os.path.exists(destination_directory):
|
if not os.path.exists(destination_directory):
|
||||||
os.mkdir(destination_directory)
|
os.mkdir(destination_directory)
|
||||||
@ -157,4 +470,12 @@ def create_html(pak: InitialPakLoader, destination_directory: str = "output/"):
|
|||||||
if not os.path.exists(language_path):
|
if not os.path.exists(language_path):
|
||||||
os.mkdir(language_path)
|
os.mkdir(language_path)
|
||||||
|
|
||||||
write_trucks(pak=pak, destination_directory=language_path, language=language_data)
|
truck_path = os.path.join(destination_directory, language_name, "trucks")
|
||||||
|
if not os.path.exists(truck_path):
|
||||||
|
os.mkdir(truck_path)
|
||||||
|
write_trucks(pak=pak, destination_directory=truck_path, language=language_data)
|
||||||
|
|
||||||
|
frame_addon_path = os.path.join(destination_directory, language_name, "frame_addons")
|
||||||
|
if not os.path.exists(frame_addon_path):
|
||||||
|
os.mkdir(frame_addon_path)
|
||||||
|
write_frame_addons(pak=pak, destination_directory=frame_addon_path, language=language_data)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user