Read client signed int32 fields as signed

Add ResStream.read_long/write_long and use them for every CObjects
field the client loads with ResStream_ReadInt32 (sb.exe 0x7E1700)
as a value: rank info, attribute/skill/resource amounts, requirements,
door/deed/container/key fields, natural attacks, hardpoints, sound
event types and sparse VAL_LONG (LoadSaveBehavior<long>). Hash/enum
fields, list counts and flag words keep unsigned reads.

The binary is unchanged; JSON now shows e.g. -1 instead of 4294967295
(rank_hirelings, rank_rank) and -10 instead of 4294967286 (attr_adj).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MagicBotandClaude Opus 5.5 committed 2026-10-16 12:55:04 -04:00
1 parent 6a8598f33f
commit 0adbfe0d99
14 files changed
+190 -182

No files matched your search

@@ -13,12 +13,12 @@ from arcane.util import ResStream
class RankInfo:
def load_binary(self, stream: ResStream):
self.rank_hirelings = stream.read_dword()
self.rank_shrines = stream.read_dword()
self.rank_spires = stream.read_dword()
self.rank_barracks = stream.read_dword()
self.rank_rank = stream.read_dword()
self.rank_health = stream.read_dword()
self.rank_hirelings = stream.read_long()
self.rank_shrines = stream.read_long()
self.rank_spires = stream.read_long()
self.rank_barracks = stream.read_long()
self.rank_rank = stream.read_long()
self.rank_health = stream.read_long()
self.rank_automatic = stream.read_bool()
self.rank_energy_k1 = stream.read_float()
self.rank_energy_k2 = stream.read_float()
@@ -35,17 +35,17 @@ class RankInfo:
self.rank_placement_limit = [
[
stream.read_dword(),
stream.read_dword(),
stream.read_long(),
] for _ in range(num_placement_limits)
]
def save_binary(self, stream: ResStream):
stream.write_dword(self.rank_hirelings)
stream.write_dword(self.rank_shrines)
stream.write_dword(self.rank_spires)
stream.write_dword(self.rank_barracks)
stream.write_dword(self.rank_rank)
stream.write_dword(self.rank_health)
stream.write_long(self.rank_hirelings)
stream.write_long(self.rank_shrines)
stream.write_long(self.rank_spires)
stream.write_long(self.rank_barracks)
stream.write_long(self.rank_rank)
stream.write_long(self.rank_health)
stream.write_bool(self.rank_automatic)
stream.write_float(self.rank_energy_k1)
stream.write_float(self.rank_energy_k2)
@@ -58,7 +58,7 @@ class RankInfo:
stream.write_dword(len(self.rank_placement_limit))
for placement in self.rank_placement_limit:
stream.write_dword(placement[0])
stream.write_dword(placement[1])
stream.write_long(placement[1])
def load_json(self, data):
self.rank_hirelings = data['rank_hirelings']
@@ -95,11 +95,11 @@ class RankInfo:
class ArcCityAssetTemplate():
def load_binary(self, stream: ResStream):
self.template_max_ranks = stream.read_dword()
self.template_start_rank = stream.read_dword()
self.template_asset_type = stream.read_dword()
self.template_trade_icon = stream.read_dword()
self.template_landmark = stream.read_dword()
self.template_max_ranks = stream.read_long()
self.template_start_rank = stream.read_long()
self.template_asset_type = stream.read_long()
self.template_trade_icon = stream.read_long()
self.template_landmark = stream.read_long()
self.template_is_maintenance = stream.read_bool()
self.template_has_keys = stream.read_bool()
self.template_use_hardpoints = stream.read_bool()
@@ -148,19 +148,19 @@ class ArcCityAssetTemplate():
self.template_embed_template.load_binary(stream)
num_creators = stream.read_dword()
self.template_creator = [
stream.read_dword() for _ in range(num_creators)
stream.read_long() for _ in range(num_creators)
]
num_terrains = stream.read_dword()
self.template_terrain = [
stream.read_dword() for _ in range(num_terrains)
stream.read_long() for _ in range(num_terrains)
]
num_valid_npc_types = stream.read_dword()
self.template_valid_npc_type = [
stream.read_dword() for _ in range(num_valid_npc_types)
stream.read_long() for _ in range(num_valid_npc_types)
]
num_valid_npc_cat = stream.read_dword()
self.template_valid_npc_cat = [
stream.read_dword() for _ in range(num_valid_npc_cat)
stream.read_long() for _ in range(num_valid_npc_cat)
]
num_rank_info = stream.read_dword()
self.template_rank_info = [RankInfo() for _ in range(num_rank_info)]
@@ -169,15 +169,15 @@ class ArcCityAssetTemplate():
num_cap_info = stream.read_dword()
self.template_cap_info = [
[
stream.read_dword(),
stream.read_dword(),
stream.read_long(),
stream.read_long(),
stream.read_qword(),
] for _ in range(num_cap_info)
]
num_event_rules = stream.read_dword()
self.template_event_rules = [
[
stream.read_dword(),
stream.read_long(),
stream.read_dword(),
] for _ in range(num_event_rules)
]
@@ -198,18 +198,18 @@ class ArcCityAssetTemplate():
self.template_resource_limit = [
[
stream.read_dword(),
stream.read_dword(),
stream.read_dword(),
stream.read_long(),
stream.read_long(),
] for _ in range(num_resource_limit)
]
self.template_unknown = stream.read_dword()
def save_binary(self, stream: ResStream):
stream.write_dword(self.template_max_ranks)
stream.write_dword(self.template_start_rank)
stream.write_dword(self.template_asset_type)
stream.write_dword(self.template_trade_icon)
stream.write_dword(self.template_landmark)
stream.write_long(self.template_max_ranks)
stream.write_long(self.template_start_rank)
stream.write_long(self.template_asset_type)
stream.write_long(self.template_trade_icon)
stream.write_long(self.template_landmark)
stream.write_bool(self.template_is_maintenance)
stream.write_bool(self.template_has_keys)
stream.write_bool(self.template_use_hardpoints)
@@ -243,27 +243,27 @@ class ArcCityAssetTemplate():
self.template_embed_template.save_binary(stream)
stream.write_dword(len(self.template_creator))
for creator in self.template_creator:
stream.write_dword(creator)
stream.write_long(creator)
stream.write_dword(len(self.template_terrain))
for terrain in self.template_terrain:
stream.write_dword(terrain)
stream.write_long(terrain)
stream.write_dword(len(self.template_valid_npc_type))
for npc_type in self.template_valid_npc_type:
stream.write_dword(npc_type)
stream.write_long(npc_type)
stream.write_dword(len(self.template_valid_npc_cat))
for npc_cat in self.template_valid_npc_cat:
stream.write_dword(npc_cat)
stream.write_long(npc_cat)
stream.write_dword(len(self.template_rank_info))
for rank_info in self.template_rank_info:
rank_info.save_binary(stream)
stream.write_dword(len(self.template_cap_info))
for cap in self.template_cap_info:
stream.write_dword(cap[0])
stream.write_dword(cap[1])
stream.write_long(cap[0])
stream.write_long(cap[1])
stream.write_qword(cap[2])
stream.write_dword(len(self.template_event_rules))
for event in self.template_event_rules:
stream.write_dword(event[0])
stream.write_long(event[0])
stream.write_dword(event[1])
stream.write_dword(len(self.template_architecture))
for arch in self.template_architecture:
@@ -277,8 +277,8 @@ class ArcCityAssetTemplate():
stream.write_dword(len(self.template_resource_limit))
for resource in self.template_resource_limit:
stream.write_dword(resource[0])
stream.write_dword(resource[1])
stream.write_dword(resource[2])
stream.write_long(resource[1])
stream.write_long(resource[2])
stream.write_dword(self.template_unknown)
def load_json(self, data):
@@ -25,7 +25,7 @@ class ArcCombatObj(ArcObj):
self.combat_powers = [
[
stream.read_dword(),
stream.read_dword(),
stream.read_long(),
] for _ in range(num_powers)
]
@@ -38,7 +38,7 @@ class ArcCombatObj(ArcObj):
stream.write_dword(len(self.combat_powers))
for power in self.combat_powers:
stream.write_dword(power[0])
stream.write_dword(power[1])
stream.write_long(power[1])
def load_json(self, data):
super().load_json(data)
@@ -14,13 +14,13 @@ from .common.Inventory import Inventory
class ArcContainerObject(ArcItem):
def load_binary(self, stream: ResStream):
super().load_binary(stream)
self.container_open = stream.read_dword()
self.container_locked = stream.read_dword()
self.container_locked_rank = stream.read_dword()
self.container_barred = stream.read_dword()
self.container_barred_rank = stream.read_dword()
self.container_trapped = stream.read_dword()
self.container_trappe_rank = stream.read_dword()
self.container_open = stream.read_long()
self.container_locked = stream.read_long()
self.container_locked_rank = stream.read_long()
self.container_barred = stream.read_long()
self.container_barred_rank = stream.read_long()
self.container_trapped = stream.read_long()
self.container_trappe_rank = stream.read_long()
num_contents = stream.read_dword()
self.container_inventory_contents = [Inventory() for _ in range(num_contents)]
for content in self.container_inventory_contents:
@@ -28,13 +28,13 @@ class ArcContainerObject(ArcItem):
def save_binary(self, stream: ResStream):
super().save_binary(stream)
stream.write_dword(self.container_open)
stream.write_dword(self.container_locked)
stream.write_dword(self.container_locked_rank)
stream.write_dword(self.container_barred)
stream.write_dword(self.container_barred_rank)
stream.write_dword(self.container_trapped)
stream.write_dword(self.container_trappe_rank)
stream.write_long(self.container_open)
stream.write_long(self.container_locked)
stream.write_long(self.container_locked_rank)
stream.write_long(self.container_barred)
stream.write_long(self.container_barred_rank)
stream.write_long(self.container_trapped)
stream.write_long(self.container_trappe_rank)
stream.write_dword(len(self.container_inventory_contents))
for content in self.container_inventory_contents:
content.save_binary(stream)
+8 -8
View File
@@ -13,12 +13,12 @@ from .ArcItem import ArcItem
class ArcDeed(ArcItem):
def load_binary(self, stream: ResStream):
super().load_binary(stream)
self.deed_type = stream.read_dword()
self.deed_type = stream.read_long()
self.deed_furniture_id = stream.read_qword()
self.deed_target_id = stream.read_qword()
self.deed_employment = stream.read_dword()
self.deed_start_rank = stream.read_dword()
self.deed_name_lookup = stream.read_dword()
self.deed_employment = stream.read_long()
self.deed_start_rank = stream.read_long()
self.deed_name_lookup = stream.read_long()
self.deed_indoors = stream.read_bool()
self.deed_is_fortress = stream.read_bool()
self.deed_namelookup_val = stream.read_float()
@@ -33,12 +33,12 @@ class ArcDeed(ArcItem):
def save_binary(self, stream: ResStream):
super().save_binary(stream)
stream.write_dword(self.deed_type)
stream.write_long(self.deed_type)
stream.write_qword(self.deed_furniture_id)
stream.write_qword(self.deed_target_id)
stream.write_dword(self.deed_employment)
stream.write_dword(self.deed_start_rank)
stream.write_dword(self.deed_name_lookup)
stream.write_long(self.deed_employment)
stream.write_long(self.deed_start_rank)
stream.write_long(self.deed_name_lookup)
stream.write_bool(self.deed_indoors)
stream.write_bool(self.deed_is_fortress)
stream.write_float(self.deed_namelookup_val)
@@ -15,9 +15,9 @@ from arcane.util import ResStream
class ArcDoorObject():
def load_binary(self, stream: ResStream):
self.door_id = stream.read_qword()
self.door_type = stream.read_dword()
self.door_movement_axis = stream.read_dword()
self.door_swing_direction = stream.read_dword()
self.door_type = stream.read_long()
self.door_movement_axis = stream.read_long()
self.door_swing_direction = stream.read_long()
self.door_min_time_to_stay_open = stream.read_float()
self.door_max_time_to_stay_open = stream.read_float()
self.door_swing_time = stream.read_float()
@@ -26,16 +26,16 @@ class ArcDoorObject():
self.door_slide_direction = stream.read_tuple()
self.door_slide_start = stream.read_tuple()
self.door_slide_end = stream.read_tuple()
self.door_locked = stream.read_dword()
self.door_locked = stream.read_long()
self.door_linked_to = stream.read_qword()
self.door_key = stream.read_qword()
self.door_sound_event = stream.read_qword()
def save_binary(self, stream: ResStream):
stream.write_qword(self.door_id)
stream.write_dword(self.door_type)
stream.write_dword(self.door_movement_axis)
stream.write_dword(self.door_swing_direction)
stream.write_long(self.door_type)
stream.write_long(self.door_movement_axis)
stream.write_long(self.door_swing_direction)
stream.write_float(self.door_min_time_to_stay_open)
stream.write_float(self.door_max_time_to_stay_open)
stream.write_float(self.door_swing_time)
@@ -44,7 +44,7 @@ class ArcDoorObject():
stream.write_tuple(self.door_slide_direction)
stream.write_tuple(self.door_slide_start)
stream.write_tuple(self.door_slide_end)
stream.write_dword(self.door_locked)
stream.write_long(self.door_locked)
stream.write_qword(self.door_linked_to)
stream.write_qword(self.door_key)
stream.write_qword(self.door_sound_event)
@@ -15,14 +15,14 @@ class ArcDungeonUnitObject(ArcStructureObject):
super().load_binary(stream)
num_connectables = stream.read_dword()
self.dungeon_connectable_edges = [
stream.read_dword() for _ in range(num_connectables)
stream.read_long() for _ in range(num_connectables)
]
def save_binary(self, stream: ResStream):
super().save_binary(stream)
stream.write_dword(len(self.dungeon_connectable_edges))
for edge in self.dungeon_connectable_edges:
stream.write_dword(edge)
stream.write_long(edge)
def load_json(self, data):
super().load_json(data)
+50 -50
View File
@@ -20,14 +20,14 @@ from .common.Race import RaceRequired
class Damage:
def load_binary(self, stream: ResStream):
self.damage_type = stream.read_dword()
self.damage_min = stream.read_dword()
self.damage_max = stream.read_dword()
self.damage_type = stream.read_long()
self.damage_min = stream.read_long()
self.damage_max = stream.read_long()
def save_binary(self, stream: ResStream):
stream.write_dword(self.damage_type)
stream.write_dword(self.damage_min)
stream.write_dword(self.damage_max)
stream.write_long(self.damage_type)
stream.write_long(self.damage_min)
stream.write_long(self.damage_max)
def load_json(self, data):
self.damage_type = STRING_TO_DAMAGE[data['damage_type']]
@@ -45,11 +45,11 @@ class Damage:
class Offerings:
def load_binary(self, stream: ResStream):
self.offering_type = stream.read_string()
self.offering_value = stream.read_dword()
self.offering_value = stream.read_long()
def save_binary(self, stream: ResStream):
stream.write_string(self.offering_type)
stream.write_dword(self.offering_value)
stream.write_long(self.offering_value)
def load_json(self, data):
self.offering_type = data['offering_type']
@@ -68,7 +68,7 @@ class Weapon:
self.weapon_max_range = stream.read_float()
self.weapon_projectile_id = stream.read_qword()
self.weapon_projectile_speed = stream.read_float()
self.weapon_combat_idle_anim = stream.read_dword()
self.weapon_combat_idle_anim = stream.read_long()
num_damages = stream.read_dword()
self.weapon_damage = [Damage() for _ in range(num_damages)]
for damage in self.weapon_damage:
@@ -76,15 +76,15 @@ class Weapon:
num_right_anims = stream.read_dword()
self.weapon_attack_anim_right = [
[
stream.read_dword(),
stream.read_dword(),
stream.read_long(),
stream.read_long(),
] for _ in range(num_right_anims)
]
num_left_anims = stream.read_dword()
self.weapon_attack_anim_left = [
[
stream.read_dword(),
stream.read_dword(),
stream.read_long(),
stream.read_long(),
] for _ in range(num_left_anims)
]
@@ -93,18 +93,18 @@ class Weapon:
stream.write_float(self.weapon_max_range)
stream.write_qword(self.weapon_projectile_id)
stream.write_float(self.weapon_projectile_speed)
stream.write_dword(self.weapon_combat_idle_anim)
stream.write_long(self.weapon_combat_idle_anim)
stream.write_dword(len(self.weapon_damage))
for damage in self.weapon_damage:
damage.save_binary(stream)
stream.write_dword(len(self.weapon_attack_anim_right))
for anim in self.weapon_attack_anim_right:
stream.write_dword(anim[0])
stream.write_dword(anim[1])
stream.write_long(anim[0])
stream.write_long(anim[1])
stream.write_dword(len(self.weapon_attack_anim_left))
for anim in self.weapon_attack_anim_left:
stream.write_dword(anim[0])
stream.write_dword(anim[1])
stream.write_long(anim[0])
stream.write_long(anim[1])
def load_json(self, data):
self.weapon_wepspeed = data['weapon_wepspeed']
@@ -138,14 +138,14 @@ class Weapon:
class ArcItem(ArcCombatObj):
def load_binary(self, stream: ResStream):
super().load_binary(stream)
self.item_type = stream.read_dword()
self.item_eq_slots_value = stream.read_dword()
self.item_eq_slots_or = stream.read_dword()
self.item_eq_slots_and = stream.read_dword()
self.item_type = stream.read_long()
self.item_eq_slots_value = stream.read_long()
self.item_eq_slots_or = stream.read_long()
self.item_eq_slots_and = stream.read_long()
self.item_eq_slots_type = stream.read_bool()
self.item_takeable = stream.read_bool()
self.item_value = stream.read_dword()
self.item_wt = stream.read_dword()
self.item_value = stream.read_long()
self.item_wt = stream.read_long()
self.item_passive_defense_mod = stream.read_float()
self.item_base_name = stream.read_string()
self.item_dsc = stream.read_string()
@@ -153,7 +153,7 @@ class ArcItem(ArcCombatObj):
self.item_health_full = stream.read_float()
self.item_skill_used = stream.read_dword()
self.item_skill_mastery_used = stream.read_dword()
self.item_parry_anim_id = stream.read_dword()
self.item_parry_anim_id = stream.read_long()
num_adjustments = stream.read_dword()
self.item_offering_info = [Offerings() for _ in range(num_adjustments)]
for offering in self.item_offering_info:
@@ -167,11 +167,11 @@ class ArcItem(ArcCombatObj):
if self.item_type == ITEM_TYPE_ARMOR:
self.item_bulk_factor = stream.read_float()
self.item_defense_rating = stream.read_dword()
self.item_defense_rating = stream.read_long()
self.item_flags = stream.read_dword()
self.item_use_flags = stream.read_dword()
self.item_post_item_id = stream.read_qword()
self.item_initial_charges = stream.read_dword()
self.item_initial_charges = stream.read_long()
self.item_book_arcana = stream.read_dword()
num_skills = stream.read_dword()
self.item_skill_req = [SkillLevel() for _ in range(num_skills)]
@@ -187,15 +187,15 @@ class ArcItem(ArcCombatObj):
self.item_attr_req = [AttributeValue() for _ in range(num_attrs)]
for attr in self.item_attr_req:
attr.load_binary(stream)
self.item_level_req = stream.read_dword()
self.item_rank_req = stream.read_dword()
self.item_sex_req = stream.read_dword()
self.item_level_req = stream.read_long()
self.item_rank_req = stream.read_long()
self.item_sex_req = stream.read_long()
num_user_actions = stream.read_dword()
self.item_user_power_action = [
[
stream.read_dword(),
stream.read_dword(),
stream.read_dword(),
stream.read_long(),
stream.read_long(),
] for _ in range(num_user_actions)
]
num_power_grants = stream.read_dword()
@@ -209,7 +209,7 @@ class ArcItem(ArcCombatObj):
self.item_sheathable = stream.read_bool()
if self.item_sheathable:
self.item_sheath_slot = stream.read_dword()
self.item_sheath_slot = stream.read_long()
self.item_sheath_offset = stream.read_tuple()
self.item_sheath_rotation = stream.read_tuple()
@@ -227,19 +227,19 @@ class ArcItem(ArcCombatObj):
self.item_resource_costs = [ResourceInfo() for _ in range(num_costs)]
for res in self.item_resource_costs:
res.load_binary(stream)
self.item_bane_rank = stream.read_dword()
self.item_bane_rank = stream.read_long()
self.item_ignore_saved_actions = stream.read_bool()
def save_binary(self, stream: ResStream):
super().save_binary(stream)
stream.write_dword(self.item_type)
stream.write_dword(self.item_eq_slots_value)
stream.write_dword(self.item_eq_slots_or)
stream.write_dword(self.item_eq_slots_and)
stream.write_long(self.item_type)
stream.write_long(self.item_eq_slots_value)
stream.write_long(self.item_eq_slots_or)
stream.write_long(self.item_eq_slots_and)
stream.write_bool(self.item_eq_slots_type)
stream.write_bool(self.item_takeable)
stream.write_dword(self.item_value)
stream.write_dword(self.item_wt)
stream.write_long(self.item_value)
stream.write_long(self.item_wt)
stream.write_float(self.item_passive_defense_mod)
stream.write_string(self.item_base_name)
stream.write_string(self.item_dsc)
@@ -247,7 +247,7 @@ class ArcItem(ArcCombatObj):
stream.write_float(self.item_health_full)
stream.write_dword(self.item_skill_used)
stream.write_dword(self.item_skill_mastery_used)
stream.write_dword(self.item_parry_anim_id)
stream.write_long(self.item_parry_anim_id)
stream.write_dword(len(self.item_offering_info))
for offering in self.item_offering_info:
offering.save_binary(stream)
@@ -257,11 +257,11 @@ class ArcItem(ArcCombatObj):
stream.write_dword(self.item_secondary_attr)
if self.item_type == ITEM_TYPE_ARMOR:
stream.write_float(self.item_bulk_factor)
stream.write_dword(self.item_defense_rating)
stream.write_long(self.item_defense_rating)
stream.write_dword(self.item_flags)
stream.write_dword(self.item_use_flags)
stream.write_qword(self.item_post_item_id)
stream.write_dword(self.item_initial_charges)
stream.write_long(self.item_initial_charges)
stream.write_dword(self.item_book_arcana)
stream.write_dword(len(self.item_skill_req))
for skill in self.item_skill_req:
@@ -272,14 +272,14 @@ class ArcItem(ArcCombatObj):
stream.write_dword(len(self.item_attr_req))
for attr in self.item_attr_req:
attr.save_binary(stream)
stream.write_dword(self.item_level_req)
stream.write_dword(self.item_rank_req)
stream.write_dword(self.item_sex_req)
stream.write_long(self.item_level_req)
stream.write_long(self.item_rank_req)
stream.write_long(self.item_sex_req)
stream.write_dword(len(self.item_user_power_action))
for power in self.item_user_power_action:
stream.write_dword(power[0])
stream.write_dword(power[1])
stream.write_dword(power[2])
stream.write_long(power[1])
stream.write_long(power[2])
stream.write_dword(len(self.item_power_grant))
for action in self.item_power_grant:
action.save_binary(stream)
@@ -288,7 +288,7 @@ class ArcItem(ArcCombatObj):
grant.save_binary(stream)
stream.write_bool(self.item_sheathable)
if self.item_sheathable:
stream.write_dword(self.item_sheath_slot)
stream.write_long(self.item_sheath_slot)
stream.write_tuple(self.item_sheath_offset)
stream.write_tuple(self.item_sheath_rotation)
stream.write_bool(self.item_has_stub)
@@ -301,7 +301,7 @@ class ArcItem(ArcCombatObj):
stream.write_dword(len(self.item_resource_costs))
for res in self.item_resource_costs:
res.save_binary(stream)
stream.write_dword(self.item_bane_rank)
stream.write_long(self.item_bane_rank)
stream.write_bool(self.item_ignore_saved_actions)
def load_json(self, data):
+2 -2
View File
@@ -16,14 +16,14 @@ class ArcKey(ArcItem):
self.key_keyval = stream.read_qword()
self.key_keyval2 = stream.read_qword()
self.key_keyval3 = stream.read_qword()
self.key_setting = stream.read_dword()
self.key_setting = stream.read_long()
def save_binary(self, stream: ResStream):
super().save_binary(stream)
stream.write_qword(self.key_keyval)
stream.write_qword(self.key_keyval2)
stream.write_qword(self.key_keyval3)
stream.write_dword(self.key_setting)
stream.write_long(self.key_setting)
def load_json(self, data):
super().load_json(data)
+6 -6
View File
@@ -16,11 +16,11 @@ from .common.SparseData import SparseData
class SoundEvent:
def load_binary(self, stream: ResStream):
self.sound_type = stream.read_dword()
self.sound_type = stream.read_long()
self.sound_event = stream.read_qword()
def save_binary(self, stream: ResStream):
stream.write_dword(self.sound_type)
stream.write_long(self.sound_type)
stream.write_qword(self.sound_event)
def load_json(self, data):
@@ -55,8 +55,8 @@ class ArcObj:
num_hard_points = stream.read_dword()
self.obj_arc_hardpoint_list = [
[
stream.read_dword(),
stream.read_dword(),
stream.read_long(),
stream.read_long(),
[stream.read_float() for _ in range(10)]
] for _ in range(num_hard_points)
]
@@ -84,8 +84,8 @@ class ArcObj:
sound_event.save_binary(stream)
stream.write_dword(len(self.obj_arc_hardpoint_list))
for n, m, points in self.obj_arc_hardpoint_list:
stream.write_dword(n)
stream.write_dword(m)
stream.write_long(n)
stream.write_long(m)
for i in range(10):
stream.write_float(points[i])
self.obj_sparse_data.save_binary(stream)
+40 -40
View File
@@ -48,8 +48,8 @@ class SkillAdjust:
num_adjusts = stream.read_dword()
self.skill_adjusts = [
[
stream.read_dword(),
stream.read_dword(),
stream.read_long(),
stream.read_long(),
] for _ in range(num_adjusts)
]
@@ -57,8 +57,8 @@ class SkillAdjust:
stream.write_dword(self.skill_type)
stream.write_dword(len(self.skill_adjusts))
for skill in self.skill_adjusts:
stream.write_dword(skill[0])
stream.write_dword(skill[1])
stream.write_long(skill[0])
stream.write_long(skill[1])
def load_json(self, data):
self.skill_type = string_to_hash(data['skill_type'])
@@ -98,23 +98,23 @@ class BodyPart:
class ArcRune(ArcItem):
def load_binary(self, stream: ResStream):
super().load_binary(stream)
self.rune_type = stream.read_dword()
self.rune_type = stream.read_long()
self.rune_sub_type = stream.read_dword()
self.rune_is_standard_character_creation = stream.read_bool()
self.rune_creation_cost = stream.read_dword()
self.rune_rank = stream.read_dword()
self.rune_pracs_per_level = stream.read_dword()
self.rune_creation_cost = stream.read_long()
self.rune_rank = stream.read_long()
self.rune_pracs_per_level = stream.read_long()
self.rune_exp_req_to_level = stream.read_float()
self.rune_sex = stream.read_dword()
self.rune_sex = stream.read_long()
self.rune_class_icon = stream.read_qword()
self.rune_health = stream.read_dword()
self.rune_mana = stream.read_dword()
self.rune_stamina = stream.read_dword()
self.rune_health = stream.read_long()
self.rune_mana = stream.read_long()
self.rune_stamina = stream.read_long()
self.rune_min_damage = stream.read_float()
self.rune_max_damage = stream.read_float()
self.rune_attack = stream.read_dword()
self.rune_defense = stream.read_dword()
self.rune_level = stream.read_dword()
self.rune_attack = stream.read_long()
self.rune_defense = stream.read_long()
self.rune_level = stream.read_long()
self.rune_speed = [
stream.read_float() for _ in range(7)
]
@@ -142,7 +142,7 @@ class ArcRune(ArcItem):
]
num_genders = stream.read_dword()
self.rune_enemy_gender = [
stream.read_dword() for _ in range(num_genders)
stream.read_long() for _ in range(num_genders)
]
num_skill_grants = stream.read_dword()
self.rune_skill_grant = [SkillGrant() for _ in range(num_skill_grants)]
@@ -165,14 +165,14 @@ class ArcRune(ArcItem):
[
stream.read_float(),
stream.read_float(),
stream.read_dword(),
stream.read_dword(),
stream.read_long(),
stream.read_long(),
stream.read_qword(),
stream.read_float(),
stream.read_dword(),
stream.read_dword(),
stream.read_dword(),
stream.read_dword(),
stream.read_long(),
stream.read_long(),
stream.read_long(),
stream.read_long(),
] for _ in range(num_natural_attacks)
]
num_enchants = stream.read_dword()
@@ -210,23 +210,23 @@ class ArcRune(ArcItem):
def save_binary(self, stream: ResStream):
super().save_binary(stream)
stream.write_dword(self.rune_type)
stream.write_long(self.rune_type)
stream.write_dword(self.rune_sub_type)
stream.write_bool(self.rune_is_standard_character_creation)
stream.write_dword(self.rune_creation_cost)
stream.write_dword(self.rune_rank)
stream.write_dword(self.rune_pracs_per_level)
stream.write_long(self.rune_creation_cost)
stream.write_long(self.rune_rank)
stream.write_long(self.rune_pracs_per_level)
stream.write_float(self.rune_exp_req_to_level)
stream.write_dword(self.rune_sex)
stream.write_long(self.rune_sex)
stream.write_qword(self.rune_class_icon)
stream.write_dword(self.rune_health)
stream.write_dword(self.rune_mana)
stream.write_dword(self.rune_stamina)
stream.write_long(self.rune_health)
stream.write_long(self.rune_mana)
stream.write_long(self.rune_stamina)
stream.write_float(self.rune_min_damage)
stream.write_float(self.rune_max_damage)
stream.write_dword(self.rune_attack)
stream.write_dword(self.rune_defense)
stream.write_dword(self.rune_level)
stream.write_long(self.rune_attack)
stream.write_long(self.rune_defense)
stream.write_long(self.rune_level)
for i in range(7):
stream.write_float(self.rune_speed[i])
self.rune_group.save_binary(stream)
@@ -248,7 +248,7 @@ class ArcRune(ArcItem):
stream.write_dword(monster)
stream.write_dword(len(self.rune_enemy_gender))
for gender in self.rune_enemy_gender:
stream.write_dword(gender)
stream.write_long(gender)
stream.write_dword(len(self.rune_skill_grant))
for grant in self.rune_skill_grant:
grant.save_binary(stream)
@@ -265,14 +265,14 @@ class ArcRune(ArcItem):
for attack in self.rune_naturalattacks:
stream.write_float(attack[0])
stream.write_float(attack[1])
stream.write_dword(attack[2])
stream.write_dword(attack[3])
stream.write_long(attack[2])
stream.write_long(attack[3])
stream.write_qword(attack[4])
stream.write_float(attack[5])
stream.write_dword(attack[6])
stream.write_dword(attack[7])
stream.write_dword(attack[8])
stream.write_dword(attack[9])
stream.write_long(attack[6])
stream.write_long(attack[7])
stream.write_long(attack[8])
stream.write_long(attack[9])
stream.write_dword(len(self.rune_enchantment_type))
for enchantment in self.rune_enchantment_type:
stream.write_dword(enchantment)
@@ -20,9 +20,9 @@ class Sound:
self.sound_max_dist = stream.read_float()
self.sound_dist = stream.read_bool()
self.sound_loop = stream.read_bool()
self.sound_chance = stream.read_dword()
self.sound_chance = stream.read_long()
self.sound_interval = stream.read_float()
self.sound_reserved = stream.read_dword()
self.sound_reserved = stream.read_long()
def save_binary(self, stream: ResStream):
stream.write_qword(self.sound_0)
@@ -31,9 +31,9 @@ class Sound:
stream.write_float(self.sound_max_dist)
stream.write_bool(self.sound_dist)
stream.write_bool(self.sound_loop)
stream.write_dword(self.sound_chance)
stream.write_long(self.sound_chance)
stream.write_float(self.sound_interval)
stream.write_dword(self.sound_reserved)
stream.write_long(self.sound_reserved)
def load_json(self, data):
self.sound_0 = data['sound_0']
@@ -30,7 +30,7 @@ class Inventory:
elif self.inventory_type == INVENTORY_TYPE_BOOTYTABLE:
self.inventory_table = [
stream.read_float(),
stream.read_dword(),
stream.read_long(),
]
def save_binary(self, stream: ResStream):
@@ -44,7 +44,7 @@ class Inventory:
stream.write_qword(self.inventory_items[1])
elif self.inventory_type == INVENTORY_TYPE_BOOTYTABLE:
stream.write_float(self.inventory_table[0])
stream.write_dword(self.inventory_table[1])
stream.write_long(self.inventory_table[1])
def load_json(self, data):
self.inventory_type = STRING_TO_INVENTORY_TYPE[data['type']]
@@ -23,7 +23,7 @@ class SparseData:
value = None
if sparse_type == SPARSE_VAL_LONG:
value = stream.read_dword()
value = stream.read_long()
elif sparse_type == SPARSE_VAL_FLOAT:
value = stream.read_float()
@@ -65,7 +65,7 @@ class SparseData:
sparse_type = SPARSE_TAG_TO_SPARSE_TYPE[tag]
if sparse_type == SPARSE_VAL_LONG:
stream.write_dword(value)
stream.write_long(value)
elif sparse_type == SPARSE_VAL_FLOAT:
stream.write_float(value)
+8
View File
@@ -30,6 +30,10 @@ class ResStream:
data = self.buffer.read(4)
return struct.unpack('<I', data)[0]
def read_long(self):
data = self.buffer.read(4)
return struct.unpack('<i', data)[0]
def read_qword(self):
dwords = struct.unpack('<II', self.buffer.read(8))
buffer = struct.pack('<II', dwords[1], dwords[0])
@@ -72,6 +76,10 @@ class ResStream:
data = struct.pack('<I', value)
self.buffer.write(data)
def write_long(self, value):
data = struct.pack('<i', value)
self.buffer.write(data)
def write_qword(self, value):
qword = struct.pack('<Q', value)
dwords = [