Last active
January 29, 2024 22:35
-
-
Save nghiadt1098/8382355eb0439482786509281f06013b to your computer and use it in GitHub Desktop.
Palworld Saver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"email":"*************", | |
"password":"*******************" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
import time | |
import sys | |
import json | |
import subprocess | |
import os | |
def hexdump(bytes_input, end=None,width=16): | |
current = 0 | |
if(end==None): | |
end = len(bytes_input) | |
result = "" | |
while current < end: | |
byte_slice = bytes_input[current : current + width] | |
# hex section | |
for b in byte_slice: | |
result += "%02X " % b | |
# filler | |
for _ in range(width - len(byte_slice)): | |
result += " " * 3 | |
result += " " * 2 | |
# printable character section | |
for b in byte_slice: | |
if (b >= 32) and (b < 127): | |
result += chr(b) | |
else: | |
result += "." | |
result += "\n" | |
current += width | |
return result | |
def parse_element(data): | |
#print(hexdump(data[:4])) | |
size=int.from_bytes(data[:4], byteorder='little') | |
#print(size) | |
data=data[4:4+size] | |
#print(hexdump(data,end=16)) | |
return size,data | |
def extract_level(data): | |
key=b'Level\0' | |
if(data.find(key)==-1): | |
return 0 | |
x =data.find(key)+len(key) | |
data=data[x:] | |
#print(hexdump(data,16)) | |
a,b=parse_element(data) | |
data=data[a+4:] | |
#print(hexdump(data,16)) | |
size=int.from_bytes(data[:8], byteorder='little') | |
data=data[8:] | |
data=data[1:] | |
level=int.from_bytes(data[:4], byteorder='little') | |
return level | |
def extract_name(data): | |
key=b'NickName\0' | |
x =data.find(key)+len(key) | |
data=data[x:] | |
#print(hexdump(data,16)) | |
a,b=parse_element(data) | |
data=data[a+4:] | |
#print(hexdump(data,16)) | |
size=int.from_bytes(data[:4], byteorder='little') | |
#print(hexdump(data,size)) | |
data=data[4:] | |
check=int.from_bytes(data[:4], byteorder='little') | |
data=data[4:] | |
check=int.from_bytes(data[:4], byteorder='little') | |
#print(hex(size)) | |
#print(hex(check)) | |
if (check>0x7fffffff): | |
data=data[5:] | |
#print(hexdump(data[:size])) | |
return data[:size].decode('utf-16') | |
else: | |
data=data[5:] | |
#print(hexdump(data[:size])) | |
data=data[:size].decode('ascii') | |
data=data[:data.find('\x00')] | |
return data | |
def process_guid(guid): | |
guid=guid.replace("-",'') | |
guid=guid.upper() | |
return guid | |
# Dump player | |
def DumpPlayer(sid): | |
extracted_data={} | |
process_dir="Saved\\SaveGames\\0\\%s\\Players\\"%(sid) | |
level_dir="Saved\\SaveGames\\0\\%s\\"%(sid) | |
files = [f for f in os.listdir(process_dir)] | |
#print(files) | |
subprocess.run(["offzip.exe", "-a","-o",level_dir+"Level.sav"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL) | |
subprocess.run(["offzip.exe", "-a","-o","0000000c.dat"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL) | |
subprocess.run(["uesave.exe", "to-json", "-i", "00000000.gva", | |
"--type", ".worldSaveData.CharacterSaveParameterMap.Key=Struct", | |
"--type", ".worldSaveData.FoliageGridSaveDataMap.Key=Struct", | |
"--type", ".worldSaveData.FoliageGridSaveDataMap.ModelMap.InstanceDataMap.Key=Struct", | |
"--type", ".worldSaveData.MapObjectSpawnerInStageSaveData.Key=Struct", | |
"--type", ".worldSaveData.ItemContainerSaveData.Key=Struct", | |
"--type", ".worldSaveData.CharacterContainerSaveData.Key=Struct", | |
"-o", "level.json"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL) | |
level=json.load(open("level.json","r")) | |
print("Load json done") | |
print("Dumping player data") | |
i=-1 | |
character_map=level["root"]["properties"]["worldSaveData"]["Struct"]["value"]["Struct"]["CharacterSaveParameterMap"]["Map"]["value"] | |
for character in character_map: | |
i+=1 | |
try: | |
player_uid=character["key"]["Struct"]["Struct"]["PlayerUId"] | |
player_guid=player_uid['Struct']['value']['Guid'] | |
except: | |
continue | |
player_uid=character["key"]["Struct"]["Struct"]["PlayerUId"] | |
player_iid=character["key"]["Struct"]["Struct"]["InstanceId"] | |
player_guid=player_uid['Struct']['value']['Guid'] | |
player_instance_guid= player_iid['Struct']['value']['Guid'] | |
if not player_guid=='00000000-0000-0000-0000-000000000000': | |
player_data=character["value"]["Struct"]["Struct"]["RawData"]["Array"]["value"]["Base"]["Byte"]["Byte"] | |
data=b''.join([x.to_bytes(1, 'big') for x in player_data]) | |
#print(hexdump(data)) | |
print(i,process_guid(player_guid),process_guid(player_instance_guid),extract_name(data),extract_level(data)) | |
if (len(sys.argv)<2): | |
print("Usage %s <%s>"%(sys.argv[0],"save_id")) | |
exit(-1) | |
DumpPlayer(sys.argv[1]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
import time | |
import sys | |
import json | |
import subprocess | |
import os | |
if len(sys.argv)<4: | |
print("Usage python %s <%s> <%s> <%s>" %(sys.argv[0],"Save ID","Original Player ID","Patched Player ID")) | |
exit(-1) | |
auth=json.load(open("./auth.json")) | |
email=auth["email"] | |
password=auth["password"] | |
server = requests.get( | |
"https://dathost.net/api/0.1/game-servers", | |
data={"game":"palworld"}, | |
auth=(email, password), | |
).json() | |
#print(server) | |
for s in server: | |
sid=s["id"] | |
print("Server id",sid) | |
# Stop Server | |
print("Stoping %s"%(sid)) | |
response = requests.post( | |
"https://dathost.net/api/0.1/game-servers/%s/stop"%(sid), | |
auth=(email, password)).json() | |
#print(response) | |
time.sleep(10) | |
# Sync file | |
print("Syncing %s"%(sid)) | |
response = requests.post( | |
"https://dathost.net/api/0.1/game-servers/%s/sync-files"%(sid), | |
auth=(email, password)).json() | |
#print(response) | |
time.sleep(10) | |
# Get old file | |
print("Downloading %s from %s"%(sys.argv[2],sid)) | |
response = requests.get( | |
"https://dathost.net/api/0.1/game-servers/%s/files/Saved/SaveGames/0/%s/Players/%s"%(sid,sys.argv[1],sys.argv[2]), | |
auth=(email, password)) | |
print(response) | |
f=open(sys.argv[2],"wb") | |
f.write(response.content) | |
f.close() | |
print("Downloading %s from %s"%(sys.argv[3],sid)) | |
response = requests.get( | |
"https://dathost.net/api/0.1/game-servers/%s/files/Saved/SaveGames/0/%s/Players/%s"%(sid,sys.argv[1],sys.argv[3]), | |
auth=(email, password)) | |
print(response) | |
f=open(sys.argv[3],"wb") | |
f.write(response.content) | |
f.close() | |
# Process | |
print("Processing %s"%(sid)) | |
subprocess.run(["offzip.exe", "-a","-o","./%s"%(sys.argv[2])]) | |
subprocess.run(["uesave.exe", "to-json","-i","0000000c.gva","-o","./%s.json"%(sys.argv[2])]) | |
subprocess.run(["offzip.exe", "-a","-o","./%s"%(sys.argv[3])]) | |
subprocess.run(["uesave.exe", "to-json","-i","0000000c.gva","-o","./%s.json"%(sys.argv[3])]) | |
json1=json.load(open("./%s.json"%(sys.argv[2]))) | |
json2=json.load(open("./%s.json"%(sys.argv[3]))) | |
json1["root"]["properties"]["SaveData"]["Struct"]["value"]["Struct"]["PlayerUId"]["Struct"]["value"]["Guid"]=json2["root"]["properties"]["SaveData"]["Struct"]["value"]["Struct"]["PlayerUId"]["Struct"]["value"]["Guid"] | |
json1["root"]["properties"]["SaveData"]["Struct"]["value"]["Struct"]["IndividualId"]["Struct"]["value"]["Struct"]["PlayerUId"]["Struct"]["value"]["Guid"]=json2["root"]["properties"]["SaveData"]["Struct"]["value"]["Struct"]["IndividualId"]["Struct"]["value"]["Struct"]["PlayerUId"]["Struct"]["value"]["Guid"] | |
json1["root"]["properties"]["SaveData"]["Struct"]["value"]["Struct"]["IndividualId"]["Struct"]["value"]["Struct"]["InstanceId"]["Struct"]["value"]["Guid"]=json2["root"]["properties"]["SaveData"]["Struct"]["value"]["Struct"]["IndividualId"]["Struct"]["value"]["Struct"]["InstanceId"]["Struct"]["value"]["Guid"] | |
out_file = open("data.json", "w") | |
json.dump(json1,out_file) | |
out_file.close() | |
subprocess.run(["uesave.exe", "from-json","-i","data.json","-o","./data/0000000c.gva"]) | |
subprocess.run(["offzip.exe", "-a","-o","-r","./%s"%(sys.argv[2]),"./data/"]) | |
# Upload new file | |
print("Patching %s"%(sid)) | |
url = "https://dathost.net/api/0.1/game-servers/%s/files/Saved/SaveGames/0/%s/Players/%s"%(sid,sys.argv[1],sys.argv[3]) | |
files = {'file': open(sys.argv[2],'rb')} | |
r = requests.post(url, files=files, auth=(email, password)) | |
print(r.content) | |
time.sleep(10) | |
# Sync file | |
print("Syncing %s"%(sid)) | |
response = requests.post( | |
"https://dathost.net/api/0.1/game-servers/%s/sync-files"%(sid), | |
auth=(email, password)).json() | |
#print(response) | |
# Restarting | |
time.sleep(10) | |
print("Starting %s"%(sid)) | |
response = requests.post( | |
"https://dathost.net/api/0.1/game-servers/%s/start"%(sid), | |
auth=(email, password)).json() | |
print(response) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment