Skip to content

Instantly share code, notes, and snippets.

@nghiadt1098
Last active January 29, 2024 22:35
Show Gist options
  • Save nghiadt1098/8382355eb0439482786509281f06013b to your computer and use it in GitHub Desktop.
Save nghiadt1098/8382355eb0439482786509281f06013b to your computer and use it in GitHub Desktop.
Palworld Saver
{
"email":"*************",
"password":"*******************"
}
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])
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