Skip to content

Commit

Permalink
Fix bug
Browse files Browse the repository at this point in the history
  • Loading branch information
magicbear committed Feb 14, 2024
1 parent 4e098cc commit 0c12d4c
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 56 deletions.
11 changes: 9 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ Changelog
Note that they these tags will not actually close the issue/PR until they
are merged into the "default" branch.

v0.6.7
-------

Fix:

- Bug for Delete Player

v0.6.6
-------

Expand Down Expand Up @@ -245,7 +252,7 @@ v0.4.0

Feature:

- Item Editor with Autocomplete Combobox
- Item Editor with Autocomplete Combobox

v0.3.10
-------
Expand Down Expand Up @@ -285,7 +292,7 @@ v0.3.6

Feature:

- Move Guild Owner Feature
- Move Guild Owner Feature

v0.3.4
-------
Expand Down
54 changes: 7 additions & 47 deletions palworld_server_toolkit/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,48 +487,6 @@ def load_skipped_decode(_worldSaveData, skip_paths, recursive=True):
SKP_PALWORLD_CUSTOM_PROPERTIES[".worldSaveData.ItemContainerSaveData.Value.BelongInfo"] = (skip_decode, skip_encode)
SKP_PALWORLD_CUSTOM_PROPERTIES[".worldSaveData.ItemContainerSaveData.Value.Slots"] = (skip_decode, skip_encode)
SKP_PALWORLD_CUSTOM_PROPERTIES[".worldSaveData.ItemContainerSaveData.Value.RawData"] = (skip_decode, skip_encode)
import palworld_save_tools.rawdata.group as palworld_save_group


def group_decode(
reader: FArchiveReader, type_name: str, size: int, path: str
) -> dict[str, Any]:
if type_name != "MapProperty":
raise Exception(f"Expected MapProperty, got {type_name}")
value = reader.property(type_name, size, path, nested_caller_path=path)
# Decode the raw bytes and replace the raw data
group_map = value["value"]
for group in group_map:
group_type = group["value"]["GroupType"]["value"]["value"]
if group_type != "EPalGroupType::Guild":
continue
group['value'] = parse_item(group['value'], "GroupSaveDataMap.Value")
group_bytes = group["value"]["RawData"]["value"]["values"]
group["value"]["RawData"]["value"] = palworld_save_group.decode_bytes(
reader, group_bytes, group_type
)
return value


def group_encode(
writer: FArchiveWriter, property_type: str, properties: dict[str, Any]
) -> int:
if property_type != "MapProperty":
raise Exception(f"Expected MapProperty, got {property_type}")
del properties["custom_type"]
group_map = properties["value"]
for group in group_map:
group_type = group["value"]["GroupType"]["value"]["value"]
if group_type != "EPalGroupType::Guild":
continue
if "values" in group["value"]["RawData"]["value"]:
continue
p = group["value"]["RawData"]["value"]
encoded_bytes = palworld_save_group.encode_bytes(p)
group["value"]["RawData"]["value"] = {"values": [b for b in encoded_bytes]}
return writer.property_inner(property_type, properties)


SKP_PALWORLD_CUSTOM_PROPERTIES[".worldSaveData.GroupSaveDataMap"] = (group_decode, group_encode)
SKP_PALWORLD_CUSTOM_PROPERTIES[".worldSaveData.GroupSaveDataMap.Value.RawData"] = (skip_decode, skip_encode)

Expand Down Expand Up @@ -2237,8 +2195,7 @@ def LoadFile(filename):

def Statistics():
for key in wsd:
print("%40s\t%.3f MB\tLoading: %10.2fms\t%20s\t%s: %d" % (key, len(str(wsd[key])) / 1048576,
1000 * loadingStatistics[key],
print("%40s\t%.3f MB\t%20s\t%s: %d" % (key, len(str(wsd[key])) / 1048576,
wsd[key]['type'] if 'type' in wsd[key] else "",
"Bytes" if isinstance(wsd[key]['value'],
bytes) else "Key",
Expand Down Expand Up @@ -3500,6 +3457,7 @@ def DeletePlayer(player_uid, InstanceId=None, dry_run=False):
DeleteItemContainer(player_gvas['inventoryInfo']['value'][key]['value']['ID']['value'])
player_container_ids.append(player_gvas['inventoryInfo']['value'][key]['value']['ID']['value'])
# Remove item from CharacterSaveParameterMap
deleteCharacters = []
for item in wsd['CharacterSaveParameterMap']['value']:
player = item['value']['RawData']['value']['object']['SaveParameter']['value']
if str(item['key']['PlayerUId']['value']) == player_uid \
Expand All @@ -3510,14 +3468,14 @@ def DeletePlayer(player_uid, InstanceId=None, dry_run=False):
str(item['key']['InstanceId']['value']), player['Level']['value'] if 'Level' in player else -1,
player['NickName']['value'] if 'NickName' in player else "*** INVALID ***"))
if not dry_run:
DeleteCharacter(item['key']['InstanceId']['value'])
deleteCharacters.append(item['key']['InstanceId']['value'])
elif 'OwnerPlayerUId' in player and str(player['OwnerPlayerUId']['value']) == player_uid and InstanceId is None:
print(
f"{terminalColor(31)}Delete Pal{terminalColor(0)} UUID: %s Owner: %s CharacterID: %s" % (
str(item['key']['InstanceId']['value']), str(player['OwnerPlayerUId']['value']),
player['CharacterID']['value']))
if not dry_run:
DeleteCharacter(item['key']['InstanceId']['value'])
deleteCharacters.append(item['key']['InstanceId']['value'])
elif 'SlotID' in player and player['SlotID']['value']['ContainerId']['value']['ID'][
'value'] in player_container_ids and InstanceId is None:
print(
Expand All @@ -3526,7 +3484,9 @@ def DeletePlayer(player_uid, InstanceId=None, dry_run=False):
str(player['SlotID']['value']['ContainerId']['value']['ID']['value']),
player['CharacterID']['value']))
if not dry_run:
DeleteCharacter(item['key']['InstanceId']['value'])
deleteCharacters.append(item['key']['InstanceId']['value'])
for instance_id in deleteCharacters:
DeleteCharacter(instance_id)
# Remove Item from GroupSaveDataMap
remove_guilds = []
for group_data in wsd['GroupSaveDataMap']['value']:
Expand Down
142 changes: 135 additions & 7 deletions palworld_server_toolkit/palobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from palworld_save_tools.archive import *
from palworld_save_tools.paltypes import *
import palworld_save_tools.rawdata.group as palworld_save_group
import json
import copy
import multiprocessing
Expand Down Expand Up @@ -313,6 +314,7 @@ def __iter__(self):

class MPMapProperty(list):
def __init__(self, *args, **kwargs):
super().__init__()
count = kwargs.get("count", 0)
size = kwargs.get("size", 0)
intsize = ctypes.sizeof(ctypes.c_ulong)
Expand All @@ -336,7 +338,7 @@ def __init__(self, *args, **kwargs):
self.memaddr + intsize * 4 + intsize * self.count.value)
self.value_size = (ctypes.c_ulong * self.count.value).from_address(
self.memaddr + intsize * 4 + intsize * self.count.value * 2)
super().__init__([None] * self.count.value)
super().extend([None] * self.count.value)

def append(self, obj):
if self.current.value < self.count.value:
Expand All @@ -353,7 +355,7 @@ def append(self, obj):
super().append(obj)

def __iter__(self):
for i in range(self.current.value):
for i in range(len(self)):
yield self.__getitem__(i)

def __getitem__(self, item):
Expand All @@ -364,12 +366,24 @@ def __getitem__(self, item):
self.shm.buf[v_s:v_s + self.value_size[item]])
self.parsed_count.value += 1
if self.parsed_count.value == self.count.value:
self.__iter__ = super().__iter__
self.shm.buf.release()
return super().__getitem__(item)

def load_all_items(self):
if self.parsed_count.value == self.count.value:
return
for i in range(self.current.value):
self.__getitem__(i)

def __delitem__(self, item):
self.load_all_items()
self.current.value -= 1
return super().__delitem__(item)

class MPArrayProperty(list):
def __init__(self, *args, **kwargs):
super().__init__()
count = kwargs.get("count", 0)
size = kwargs.get("size", 0)
intsize = ctypes.sizeof(ctypes.c_ulong)
Expand All @@ -391,7 +405,7 @@ def __init__(self, *args, **kwargs):
self.index = (ctypes.c_ulong * self.count.value).from_address(self.memaddr + intsize * 4)
self.value_size = (ctypes.c_ulong * self.count.value).from_address(
self.memaddr + intsize * 4 + intsize * self.count.value)
super().__init__([None] * self.count.value)
self += [None] * self.count.value

def append(self, obj):
if self.current.value < self.count.value:
Expand All @@ -404,10 +418,6 @@ def append(self, obj):
else:
super().append(obj)

def __iter__(self):
for i in range(self.current.value):
yield self.__getitem__(i)

def __getitem__(self, item):
if super().__getitem__(item) is None:
v_s = self.index[item]
Expand All @@ -418,6 +428,26 @@ def __getitem__(self, item):
self.shm.buf.release()
return super().__getitem__(item)

def __iter__(self):
for i in range(len(self)):
yield self.__getitem__(i)

def __delitem__(self, item):
del self.index[item]
del self.value_size[item]
self.current.value -= 1
return super().__delitem__(item)

def load_all_items(self):
if self.parsed_count.value == self.count.value:
return
for i in range(self.current.value):
self.__getitem__(i)

def __delitem__(self, item):
self.load_all_items()
self.current.value -= 1
return super().__delitem__(item)

def skip_decode(
reader: FArchiveReader, type_name: str, size: int, path: str
Expand Down Expand Up @@ -710,6 +740,104 @@ def properties_until_end(self, path: str = "") -> dict[str, Any]:
properties['worldSaveData']['value'][mp_path[15:]]["custom_type"] = mp_path
return properties

def parse_item(self, properties, skip_path):
if isinstance(properties, dict):
if 'skip_type' in properties:
# print("Parsing worldSaveData.%s..." % skip_path, end="", flush=True)
properties_parsed = self.parse_skiped_item(properties, skip_path)
for k in properties_parsed:
properties[k] = properties_parsed[k]
# print("Done")
else:
for key in properties:
call_skip_path = skip_path + "." + key[0].upper() + key[1:]
properties[key] = self.parse_item(properties[key], call_skip_path)
elif isinstance(properties, list):
top_skip_path = ".".join(skip_path.split(".")[:-1])
for idx, item in enumerate(properties):
properties[idx] = self.parse_item(item, top_skip_path)
return properties

def parse_skiped_item(self, properties, skip_path):
if "skip_type" not in properties:
return properties

writer = FArchiveWriter(PALWORLD_CUSTOM_PROPERTIES)
if properties["skip_type"] == "ArrayProperty":
writer.fstring(properties["array_type"])
writer.optional_guid(properties.get("id", None))
writer.write(properties['value'])
elif properties["skip_type"] == "MapProperty":
writer.fstring(properties["key_type"])
writer.fstring(properties["value_type"])
writer.optional_guid(properties.get("id", None))
writer.write(properties["value"])
elif properties["skip_type"] == "StructProperty":
writer.fstring(properties["struct_type"])
writer.guid(properties["struct_id"])
writer.optional_guid(properties.get("id", None))
writer.write(properties["value"])

keep_custom_type = False
localProperties = copy.deepcopy(PALWORLD_CUSTOM_PROPERTIES)
if ".worldSaveData.%s" % skip_path in PALWORLD_CUSTOM_PROPERTIES:
localProperties[".worldSaveData.%s" % skip_path] = PALWORLD_CUSTOM_PROPERTIES[".worldSaveData.%s" % skip_path]
keep_custom_type = True
elif ".worldSaveData.%s" % skip_path in localProperties:
del localProperties[".worldSaveData.%s" % skip_path]

with FProgressArchiveReader(
writer.bytes(), PALWORLD_TYPE_HINTS,
localProperties
) as reader:
decoded_properties = reader.property(properties["skip_type"], len(properties['value']),
".worldSaveData.%s" % skip_path)
for k in decoded_properties:
properties[k] = decoded_properties[k]
if not keep_custom_type:
del properties['custom_type']
del properties["skip_type"]
return properties


def group_decode(
reader: FProgressArchiveReader, type_name: str, size: int, path: str
) -> dict[str, Any]:
if type_name != "MapProperty":
raise Exception(f"Expected MapProperty, got {type_name}")
value = reader.property(type_name, size, path, nested_caller_path=path)
# Decode the raw bytes and replace the raw data
group_map = value["value"]
for group in group_map:
group_type = group["value"]["GroupType"]["value"]["value"]
if group_type != "EPalGroupType::Guild":
continue
group['value'] = reader.parse_item(group['value'], "GroupSaveDataMap.Value")
group_bytes = group["value"]["RawData"]["value"]["values"]
group["value"]["RawData"]["value"] = palworld_save_group.decode_bytes(
reader, group_bytes, group_type
)
return value


def group_encode(
writer: FArchiveWriter, property_type: str, properties: dict[str, Any]
) -> int:
if property_type != "MapProperty":
raise Exception(f"Expected MapProperty, got {property_type}")
del properties["custom_type"]
group_map = properties["value"]
for group in group_map:
group_type = group["value"]["GroupType"]["value"]["value"]
if group_type != "EPalGroupType::Guild":
continue
if "values" in group["value"]["RawData"]["value"]:
continue
p = group["value"]["RawData"]["value"]
encoded_bytes = palworld_save_group.encode_bytes(p)
group["value"]["RawData"]["value"] = {"values": [b for b in encoded_bytes]}
return writer.property_inner(property_type, properties)


class JsonPalSimpleObject:
type = None
Expand Down

0 comments on commit 0c12d4c

Please sign in to comment.